Merge branch '12.0-development' into sdf-font-hintingmode

This commit is contained in:
Labrium
2023-09-01 18:43:18 -06:00
committed by GitHub
757 changed files with 443543 additions and 45188 deletions
+136 -13
View File
@@ -20,6 +20,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
repository: love2d/love-appimage-source repository: love2d/love-appimage-source
ref: 12.x
- name: Checkout LÖVE - name: Checkout LÖVE
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
@@ -41,7 +42,7 @@ jobs:
- name: Artifact - name: Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: love-x86_64.AppImage name: love-linux-x86_64.AppImage
path: love-${{ github.sha }}.AppImage path: love-${{ github.sha }}.AppImage
- name: Artifact Debug Symbols - name: Artifact Debug Symbols
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
@@ -52,36 +53,158 @@ jobs:
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
matrix: matrix:
platform: [Win32, x64] platform: [Win32, x64, ARM64]
install: [compat, modern]
exclude:
- platform: ARM64
install: compat
defaults:
run:
shell: cmd
continue-on-error: ${{ matrix.platform == 'ARM64' }}
steps: steps:
- name: Define Variables
id: vars
run: |
rem Compat/Modern switch
if "${{ matrix.install }}" == "compat" (
echo moredef=-DLOVE_INSTALL_UCRT=ON>> "%GITHUB_OUTPUT%"
echo compatname=-compat>> "%GITHUB_OUTPUT%"
) else (
echo moredef=>> "%GITHUB_OUTPUT%"
echo compatname=>> "%GITHUB_OUTPUT%"
)
rem JIT Modules
if "${{ matrix.platform }}-${{ matrix.install }}" == "x64-modern" (
(echo jitmodules=1)>> "%GITHUB_OUTPUT%"
) else (
(echo jitmodules=0)>> "%GITHUB_OUTPUT%"
)
rem Architecture-Specific Switch
goto ${{ matrix.platform }}
exit /b 1
:Win32
(echo arch=x86)>> "%GITHUB_OUTPUT%"
(echo angle=0)>> "%GITHUB_OUTPUT%"
echo nofiles=warn>> "%GITHUB_OUTPUT%"
exit /b 0
:x64
(echo arch=x64)>> "%GITHUB_OUTPUT%"
(echo angle=0)>> "%GITHUB_OUTPUT%"
echo nofiles=warn>> "%GITHUB_OUTPUT%"
exit /b 0
:ARM64
(echo arch=arm64)>> "%GITHUB_OUTPUT%"
(echo angle=1)>> "%GITHUB_OUTPUT%"
echo nofiles=ignore>> "%GITHUB_OUTPUT%"
echo moredef=-DLOVE_EXTRA_DLLS=%CD%\angle\libEGL.dll;%CD%\angle\libGLESv2.dll>> "%GITHUB_OUTPUT%"
exit /b 0
- name: Download Windows SDK Setup 10.0.20348
run: curl -Lo winsdksetup.exe https://go.microsoft.com/fwlink/?linkid=2164145
- name: Install Debugging Tools for Windows
id: windbg
run: |
setlocal enabledelayedexpansion
start /WAIT %CD%\winsdksetup.exe /features OptionId.WindowsDesktopDebuggers /q /log %CD%\log.txt
echo ERRORLEVEL=!ERRORLEVEL! >> %GITHUB_OUTPUT%
- name: Print Debugging Tools Install Log
if: always()
run: |
type log.txt
exit /b ${{ steps.windbg.outputs.ERRORLEVEL }}
- name: Setup Python 3.10
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Download source_index.py
run: curl -Lo source_index.py https://gist.github.com/MikuAuahDark/d9c099f5714e09a765496471c2827a55/raw/df34956052035f3473c5f01861dfb53930d06843/source_index.py
- name: Clone Megasource - name: Clone Megasource
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
path: megasource path: megasource
repository: love2d/megasource repository: love2d/megasource
ref: main ref: 12.x
- id: megasource
name: Get Megasource Commit SHA
shell: python
run: |
import os
import subprocess
result = subprocess.run("git -C megasource rev-parse HEAD".split(), check=True, capture_output=True, encoding="UTF-8")
commit = result.stdout.split()[0]
with open(os.environ["GITHUB_OUTPUT"], "w", encoding="UTF-8") as f: f.write(f"commit={commit}")
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
path: megasource/libs/love path: megasource/libs/love
- name: Download ANGLE
uses: robinraju/release-downloader@v1.7
if: steps.vars.outputs.angle == '1'
with:
repository: MikuAuahDark/angle-winbuild
tag: cr_5249
fileName: angle-win-${{ steps.vars.outputs.arch }}.zip
tarBall: false
zipBall: false
out-file-path: angle
- name: Extract ANGLE
if: steps.vars.outputs.angle == '1'
working-directory: angle
run: 7z x angle-win-${{ steps.vars.outputs.arch }}.zip
- name: Delete Strawbery Perl
# https://github.com/actions/runner-images/issues/6627
# In particular, this is not pretty, but even CMAKE_IGNORE_PREFIX_PATH
# cannot help in this case. Delete the whole folder!
run: |
rmdir /s /q C:\Strawberry
exit /b 0
- name: Configure - name: Configure
shell: cmd
env: env:
PLATFORM: ${{ matrix.platform }} CFLAGS: /Zi
run: cmake -Bbuild -Hmegasource -T v142 -A %PLATFORM% -DCMAKE_INSTALL_PREFIX=%CD%\install CXXFLAGS: /Zi
LDFLAGS: /DEBUG:FULL /OPT:REF /OPT:ICF
run: cmake -Bbuild -Smegasource -T v142 -A ${{ matrix.platform }} --install-prefix %CD%\install -DCMAKE_PDB_OUTPUT_DIRECTORY=%CD%\pdb ${{ steps.vars.outputs.moredef }}
- name: Install - name: Install
shell: cmd run: cmake --build build --target PACKAGE --config Release -j2
run: cmake --build build --config Release --target install -j2 - name: Copy LuaJIT lua51.pdb
run: |
copy /Y build\libs\LuaJIT\src\lua51.pdb pdb\Release\lua51.pdb
exit /b 0
- name: Add srcsrv to PATH
run: |
echo C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\srcsrv>>%GITHUB_PATH%
- name: Embed Source Index into PDBs
run: |
python source_index.py ^
--source %CD%\megasource\libs\love https://raw.githubusercontent.com/${{ github.repository }}/${{ github.sha }} ^
--source %CD%\megasource https://raw.githubusercontent.com/love2d/megasource/${{ steps.megasource.outputs.commit }} ^
--source %CD%\build\libs\LuaJIT https://raw.githubusercontent.com/love2d/megasource/${{ steps.megasource.outputs.commit }}/libs/LuaJIT ^
pdb\Release\*.pdb
- name: Artifact - name: Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: love-windows-${{ matrix.platform }} name: love-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}
path: install path: |
build/*.zip
build/*.exe
if-no-files-found: ${{ steps.vars.outputs.nofiles }}
- name: Artifact JIT Modules - name: Artifact JIT Modules
if: steps.vars.outputs.jitmodules == '1'
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: love-windows-jitmodules-${{ matrix.platform }} name: love-windows-jitmodules
path: build/libs/LuaJIT/src/jit/*.lua path: build/libs/LuaJIT/src/jit/*.lua
- name: Artifact PDB
uses: actions/upload-artifact@v3
with:
name: love-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-dbg
path: pdb/Release/*.pdb
macOS: macOS:
runs-on: macos-latest runs-on: macos-latest
steps: steps:
@@ -92,7 +215,7 @@ jobs:
with: with:
path: apple-dependencies path: apple-dependencies
repository: love2d/love-apple-dependencies repository: love2d/love-apple-dependencies
ref: main ref: 12.x
- name: Move Dependencies - name: Move Dependencies
run: run:
mv apple-dependencies/macOS/Frameworks platform/xcode/macosx mv apple-dependencies/macOS/Frameworks platform/xcode/macosx
@@ -120,7 +243,7 @@ jobs:
with: with:
path: apple-dependencies path: apple-dependencies
repository: love2d/love-apple-dependencies repository: love2d/love-apple-dependencies
ref: main ref: 12.x
- name: Move Dependencies - name: Move Dependencies
run: | run: |
mv apple-dependencies/iOS/libraries platform/xcode/ios mv apple-dependencies/iOS/libraries platform/xcode/ios
+13 -1
View File
@@ -1,3 +1,13 @@
# automake products
/config.h
/config.h.in
/config.log
/config.status
/configure
/configure-modules-post.ac
/configure-modules-pre.ac
/configure.ac
/extra/reshax/Release/ /extra/reshax/Release/
/extra/reshax/Debug/ /extra/reshax/Debug/
/extra/reshax/resources.h /extra/reshax/resources.h
@@ -35,8 +45,8 @@ demos
/src/.libs/ /src/.libs/
*~ *~
Makefile* Makefile*
config*
libtool libtool
/src/config.h
/platform/unix/ar-lib /platform/unix/ar-lib
/platform/unix/compile /platform/unix/compile
/platform/unix/config.guess /platform/unix/config.guess
@@ -57,3 +67,5 @@ libtool
stamp-h1 stamp-h1
/src/love /src/love
/src/tags /src/tags
.vs/
.vscode/
-109
View File
@@ -1,109 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := liblove
LOCAL_CFLAGS := -g -DGL_GLEXT_PROTOTYPES -DAL_ALEXT_PROTOTYPES -fvisibility=hidden
LOCAL_CPPFLAGS := -fvisibility-inlines-hidden
# I don't think there's armeabi-v7a device without NEON instructions in 2018
LOCAL_ARM_NEON := true
ifeq ($(IS_ANDROID_21),yes)
# API21 defines socklen_t
LOCAL_CFLAGS += -DHAS_SOCKLEN_T=1
endif
LOCAL_C_INCLUDES := \
${LOCAL_PATH}/src \
${LOCAL_PATH}/src/modules \
${LOCAL_PATH}/src/libraries/ \
${LOCAL_PATH}/src/libraries/enet/libenet/include \
${LOCAL_PATH}/src/libraries/physfs \
${LOCAL_PATH}/src/libraries/glslang/glslang/Include
LOCAL_SRC_FILES := \
$(filter-out \
src/libraries/luasocket/libluasocket/wsocket.c \
,$(subst $(LOCAL_PATH)/,,\
$(wildcard ${LOCAL_PATH}/src/love.cpp) \
$(wildcard ${LOCAL_PATH}/src/common/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/audio/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/audio/null/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/audio/openal/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/data/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/event/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/event/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/filesystem/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/filesystem/physfs/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/font/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/font/freetype/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/graphics/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/graphics/opengl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/image/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/image/magpie/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/joystick/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/joystick/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/keyboard/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/keyboard/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/love/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/math/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/mouse/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/mouse/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/physics/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/physics/box2d/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/sound/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/sound/lullaby/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/system/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/system/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/thread/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/thread/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/touch/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/touch/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/timer/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/timer/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/video/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/video/theora/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/window/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/modules/window/sdl/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/ddsparse/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/Collision/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/Collision/Shapes/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/Common/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/Dynamics/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/Dynamics/Contacts/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/Dynamics/Joints/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/Box2D/Rope/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/glad/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/glslang/glslang/GenericCodeGen/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/glslang/glslang/MachineIndependent/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/glslang/glslang/MachineIndependent/preprocessor/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/glslang/glslang/OSDependent/Unix/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/glslang/OGLCompilersDLL/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/glslang/glslang//*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/enet/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/enet/libenet/*.c) \
$(wildcard ${LOCAL_PATH}/src/libraries/lua53/*.c) \
$(wildcard ${LOCAL_PATH}/src/libraries/luasocket/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/luautf8/*.c) \
$(wildcard ${LOCAL_PATH}/src/libraries/luasocket/libluasocket/*.c) \
$(wildcard ${LOCAL_PATH}/src/libraries/lodepng/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/lz4/*.c) \
$(wildcard ${LOCAL_PATH}/src/libraries/noise1234/*.cpp) \
$(wildcard ${LOCAL_PATH}/src/libraries/physfs/*.c) \
$(wildcard ${LOCAL_PATH}/src/libraries/Wuff/*.c) \
$(wildcard ${LOCAL_PATH}/src/libraries/xxHash/*.c) \
))
LOCAL_CXXFLAGS := -std=c++11
LOCAL_SHARED_LIBRARIES := libopenal libmpg123
LOCAL_STATIC_LIBRARIES := libvorbis libogg libtheora libmodplug libfreetype libluajit SDL2_static
# $(info liblove: include dirs $(LOCAL_C_INCLUDES))
# $(info liblove: src files $(LOCAL_SRC_FILES))
LOCAL_LDLIBS := -lz -lGLESv1_CM -lGLESv2 -ldl -landroid
LOCAL_LDFLAGS := -Wl,--allow-multiple-definition
include $(BUILD_SHARED_LIBRARY)
+428 -215
View File
File diff suppressed because it is too large Load Diff
+144
View File
@@ -1,3 +1,147 @@
LOVE 12.0 [N/A]
---------------
Released: N/A
* Added support for launching a specific .lua file as the main file.
* Added basic usage instructions printed to the console when '--help' is used as a command-line parameter, and when the no-game screen is run.
* Added love.parsedGameArguments and love.rawGameArguments tables, in the main thread.
* Added love.markDeprecated.
* Added HTTPS Lua module.
* Added love.event.restart(optionalvalue). A new love.restart field will contain the value after restarting.
* Added love.system.getPreferredLocales.
* Added love.localechanged callback.
* Added love.audiodisconnected callback.
* Added love.filesystem.mountFullPath and love.filesystem.unmountFullPath, including opt-in mount-for-write support.
* Added love.filesystem.mountCommonPath, unmountCommonPath, and getFullCommonPath.
* Added 'readonly' field to love.filesystem.getInfo's returned table.
* Added love.filesystem.openFile (replaces love.filesystem.newFile).
* Added an optional load mode parameter to love.filesystem.load whetever to only allow binary chunks, text chunks, or both.
* Added love.math.perlinNoise and love.math.simplexNoise (replaces love.math.noise).
* Added SoundData:copyFrom.
* Added SoundData:slice.
* Added optional stream type parameter to love.audio.newSource streaming sources ("file" or "memory"). It defaults to "file".
* Added love.audio.getPlaybackDevice, love.audio.getPlaybackDevices, and love.audio.setPlaybackDevice.
* Added love.keyboard.isModifierActive.
* Added Joystick:setPlayerIndex and Joystick:getPlayerIndex.
* Added Joystick:getJoystickType.
* Added Joystick:getGamepadType.
* Added Joystick:hasSensor.
* Added Joystick:isSensorEnabled and Joystick:setSensorEnabled.
* Added Joystick:getSensorData.
* Added new Gamepad API buttons: "misc1", "paddle1", "paddle2", "paddle3", "paddle4". and "touchpad".
* Added World:getFixturesInArea().
* Added support for saving .exr image files via ImageData:encode.
* Added a Metal backend to love.graphics, available on macOS 10.15+ and iOS 13+.
* Added a Vulkan backend to love.graphics, available on Windows, Linux, and Android 7+.
* Added '--renderers a,b,c' and '--excluderenderers a,b,c' command line arguments.
* Added t.renderers and t.excluderenderers love.conf options.
* Added t.highdpi startup flag in love.conf, replacing t.window.highdpi and the highdpi flag of love.window.setMode.
* Added support for highdpi mode in Windows.
* Added per-shader opt in support for the GLSL 4.30 (desktop) and GLSL ES 3.20 (mobile) shading languages, via #pragma language glsl4.
* Added compile options table parameter to love.graphics.newShader. Allows setting #define values via newShader.
* Added love.graphics.newTexture. newImage and newCanvas still exist as convenience constructor functions.
* Added optional 'mipmapcount' field to the settings table in newTexture/newImage/newCanvas.
* Added optional 'computewrite' boolean field to the settings table in newTexture/newImage/newCanvas.
* Added love.graphics.getTextureFormats, which replaces getImageFormats and getCanvasFormats.
* Added Texture:isCanvas and Texture:isComputeWritable.
* Added Texture:isFormatLinear, Texture:getMSAA, Texture:generateMipmaps, Texture:replacePixels, and Texture:renderTo (moved from old Canvas and Image subclasses).
* Added integer pixel formats for Textures and ImageData.
* Added Graphics Buffer objects, including vertex, index, texel, shader storage, and indirect draw/dispatch argument buffers.
* Added love.graphics.copyBuffer, copyBufferToTexture, and copyTextureToBuffer.
* Added APIs for interacting with the Buffer objects owned by Meshes.
* Added Mesh:getAttachedAttributes.
* Added an optional start array index parameter to Mesh:attachAttribute.
* Added integer buffer data formats.
* Added love.graphics.readbackTexture and love.graphics.readbackTextureAsync (replaces Texture:newImageData).
* Added love.graphics.readbackBuffer and love.graphics.readbackBufferAsync.
* Added 'readback' buffer data usage enum, useful for advanced memory optimization when using love.graphics.readbackBuffer.
* Added new lower level 'vertexmain' and 'pixelmain' shader entry points.
* Added Compute Shader support via love.graphics.newComputeShader and a new 'computemain' shader entry point.
* Added love.graphics.dispatchThreadgroups and love.graphics.dispatchIndirect for running compute shaders.
* Added Shader:hasStage.
* Added love.graphics.drawFromShader.
* Added love.graphics.drawFromShaderIndirect.
* Added love.graphics.drawIndirect.
* Added love.graphics.getQuadIndexBuffer.
* Added variants of love.graphics.applyTransform and replaceTransform which accept x,y,angle,sx,sy,ox,oy parameters.
* Added APIs to override the default orthographic projection: love.graphics.setOrthoProjection, setPerspectiveProjection, and resetProjection.
* Added ability to set point size within a vertex shader by setting the 'love_PointSize' variable.
* Added love.graphics.setBlendState, which gives lower level control over blend operations than setBlendMode.
* Added love.graphics.setStencilMode and getStencilMode. Replaces love.graphics.stencil as well as setStencilTest.
* Added a variant of love.graphics.setColorMask which accepts a single boolean.
* Added new 'clampone' wrap mode.
* Added 'clampone', 'texelbuffer', 'indexbuffer32bit', 'mipmaprange', and 'indirectdraw' graphics feature enums.
* Added 'copybuffer', 'copybuffertotexture', 'copytexturetobuffer', and 'copyrendertargettobuffer' graphics feature enums.
* Added initial support for right-to-left (RTL) text when using TrueType and OpenType fonts.
* Added a variant of Font:getWidth which takes a codepoint number argument.
* Added love.graphics.newTextBatch (renamed from love.graphics.newText).
* Added love.sensor module.
* Added love.sensorupdated callback.
* Added love.joysticksensorupdated callback.
* Added variant for enet peer:send and host:broadcast which accepts a pointer (light userdata) and a size.
* Changed love.filesystem.exists to no longer be deprecated.
* Changed the default font from Vera size 12 to Noto Sans size 13.
* Changed TrueType and OpenType font handling to have improved kerning and character combining support.
* Changed the Texture class and implementation to no longer have separate Canvas and Image subclasses.
* Changed Images to no longer hold onto a CPU copy of their pixel data after creation.
* Changed love.graphics.newImage to error instead of loading a placeholder texture, when the image dimensions are too large for the system.
* Changed love.graphics.newImage to allow creating a mipmapped texture with less than the full mipmap range, instead of erroring.
* Changed love.graphics.newMesh to no longer default to the "fan" Mesh draw mode.
* Changed the behaviour of Meshes to no longer allow a vertex map or index buffer when the "fan" mesh draw mode is used.
* Changed love.window.setMode to no longer clear the contents of Canvases or otherwise recreate OpenGL resources.
* Changed love.graphics.points to require 'love_PointSize' to be set in the vertex shader, if a custom shader is used.
* Changed love.graphics.setCanvas to always clear auto-generated temporary depth and stencil buffers when they're used.
* Changed shader code parsing to ignore shader entry point functions inside comments.
* Changed audio file decoding to choose the most appropriate decoder based on file contents instead of the file extension.
* Changed Videos to stream audio from the file instead of loading all the video file into memory for use with audio decoding.
* Changed love.filesystem.exists to no longer be deprecated.
* Changed RevoluteJoint:getMotorTorque and WheelJoint:getMotorTorque to take 'dt' as a parameter instead of 'inverse_dt'.
* Changed love.math.perlinNoise and simplexNoise to use higher precision numbers for its internal calculations.
* Changed t.accelerometerjoystick startup flag in love.conf to unset by default.
* Renamed 'display' field to 'displayindex' in love.window.setMode/updateMode/getMode and love.conf.
* Renamed love.graphics Text objects to TextBatch.
* Updated Box2D from 2.3 to 2.4.1.
* Updated LuaSocket from 3.0-rc1 to 3.1.0.
* Deprecated usage of slashes instead of dots for module separators in require.
* Deprecated love.filesystem.newFile (replaced by openFile).
* Deprecated love.math.noise (replaced by perlinNoise and simplexNoise).
* Deprecated love.graphics.setNewFont (use love.graphics.newFont and love.graphics.setFont instead).
* Deprecated love.graphics.newText (renamed to love.graphics.newTextBatch).
* Deprecated love.graphics.getImageFormats and love.graphics.getCanvasFormats (replaced by getTextureFormats).
* Deprecated love.graphics.stencil (replaced by love.graphics.setStencilMode).
* Deprecated love.graphics.setStencilTest and love.graphics.getStencilTest (replaced by love.graphics.setStencilMode and getStencilMode).
* Deprecated t.window.highdpi in love.conf and the highdpi flag of love.window.setMode (replaced by t.highdpi in love.conf).
* Deprecated t.accelerometerjoystick in love.conf (replaced by love.sensor module).
* Deprecated the variants of Mesh:attachAttribute and SpriteBatch:attachAttribute which accept a Mesh (replaced by variants which accept a Buffer).
* Deprecated Texture:newImageData (replaced by love.graphics.readbackTexture).
* Removed the variant of SpriteBatch:setColor() which turns off all previously set colors.
* Removed the no-argument variant of love.graphics.setColorMask.
* Removed functions deprecated in LOVE 11:
* Removed love.audio.getSourceCount (renamed to love.audio.getActiveSourceCount).
* Removed Source:getChannels (renamed to Source:getChannelCount).
* Removed Decoder:getChannels (renamed to Decoder:getChannelCount).
* Removed love.filesystem.isDirectory (replaced by love.filesystem.getInfo).
* Removed love.filesystem.isFile (replaced by love.filesystem.getInfo).
* Removed love.filesystem.isSymlink (replaced by love.filesystem.getInfo).
* Removed love.filesystem.getLastModified (replaced by love.filesystem.getInfo).
* Removed love.filesystem.getSize (replaced by love.filesystem.getInfo).
* Removed ParticleSystem:setAreaSpread and ParticleSystem:getAreaSpread (renamed to ParticleSystem:setEmissionArea and getEmissionArea).
* Removed love.math.compress and love.math.decompress (replaced by love.data.compress and love.data.decompress).
* Removed World:getBodyList, World:getJointList, and World:getContactList (renamed to World:getBodies, World:getJoints, and World:getContacts).
* Removed Body:getFixtureList, Body:getJointList, and Body:getContactList (renamed to Body:getFixtures, Body:getJoints, and Body:getContacts).
* Removed PrismaticJoint:hasLimitsEnabled (renamed to PrismaticJoint:areLimitsEnabled).
* Removed RevoluteJoint:hasLimitsEnabled (renamed to RevoluteJoint:areLimitsEnabled).
* Fixed BezierCurve:render adding collinear points in some situations.
* Fixed sound Decoders to cause a Lua error instead of hard-crashing when memory for the decoding buffer can't be allocated.
* Fixed enum misspelling for thousandsseparator from thsousandsseparator for both keyboard and scancode enums.
LOVE 11.5 [Mysterious Mysteries] LOVE 11.5 [Mysterious Mysteries]
-------------------------------- --------------------------------
-51
View File
@@ -1,51 +0,0 @@
version: 11.5.{build}
image: Visual Studio 2013
shallow_clone: true
environment:
matrix:
- PLATFORM: x86
VCVARSALL_PLATFORM: x86
GENERATOR: "Visual Studio 12"
- PLATFORM: x64
VCVARSALL_PLATFORM: x86_amd64
GENERATOR: "Visual Studio 12 Win64"
init:
# Make VS 2013 command line tools available
- call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %VCVARSALL_PLATFORM%
install:
# We need to install NSIS to create the packaged installer executable.
- choco install nsis-unicode -y
# Move all woking directory items except `appveyor.yml` to `love` subdirectory.
- md love
- for /D %%i in (*) do @if "%%i" NEQ "love" @move %%i love\%%i
- for %%i in (*) do @if "%%i" NEQ "appveyor.yml" @move %%i love\%%i
# clone megasource and move into top directory.
- git clone --depth 1 https://github.com/love2d/megasource.git megasource
- cd megasource
- for /D %%i in (*) do @move %%i ..\%%i
- for %%i in (*) do @move %%i ..\%%i
- cd ..
# move love source to megasource's libs\love.
- move love libs\love
before_build:
- cmake -G "%GENERATOR%" -H. -Bbuild
build_script:
- cmake --build build --target PACKAGE --config Release
after_build:
before_test:
test_script:
artifacts:
- path: build\*.zip
- path: build\*.exe
+25
View File
@@ -0,0 +1,25 @@
# Sets the following variables:
#
# HARFBUZZ_FOUND
# HARFBUZZ_INCLUDE_DIR
# HARFBUZZ_LIBRARY
set(HARFBUZZ_SEARCH_PATHS
/usr/local
/usr
)
find_path(HARFBUZZ_INCLUDE_DIR
NAMES hb.h
PATH_SUFFIXES include include/harfbuzz
PATHS ${HARFBUZZ_SEARCH_PATHS})
find_library(HARFBUZZ_LIBRARY
NAMES harfbuzz
PATH_SUFFIXES lib
PATHS ${HARFBUZZ_SEARCH_PATHS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Harfbuzz DEFAULT_MSG HARFBUZZ_LIBRARY HARFBUZZ_INCLUDE_DIR)
mark_as_advanced(HARFBUZZ_INCLUDE_DIR HARFBUZZ_LIBRARY)
Binary file not shown.
Binary file not shown.
+28 -15
View File
@@ -29,6 +29,12 @@ This distribution contains code from the following projects (full license text b
Copyright (C) 2002-2005 3Dlabs Inc. Ltd. Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
Copyright (C) 2013-2016 LunarG, Inc. Copyright (C) 2013-2016 LunarG, Inc.
- SPIRV-Cross
Website: https://github.com/KhronosGroup/SPIRV-Cross
License: Apache 2.0 or MIT/Expat
Copyright 2015-2021 Arm Limited
Copyright 2016-2021 The Brenwill Workshop Ltd.
- Kepler Project's lua-compat-5.3 - Kepler Project's lua-compat-5.3
Website: https://github.com/keplerproject/lua-compat-5.3 Website: https://github.com/keplerproject/lua-compat-5.3
License: MIT/Expat License: MIT/Expat
@@ -87,7 +93,13 @@ This distribution contains code from the following projects (full license text b
- dr_flac - dr_flac
Website: https://github.com/mackron/dr_libs Website: https://github.com/mackron/dr_libs
Source download: https://github.com/mackron/dr_libs/blob/c5e5355/dr_flac.h Source download: https://github.com/mackron/dr_libs/blob/15f37e3/dr_flac.h
License: MIT/Expat
Copyright 2018 David Reid
- dr_mp3
Website: https://mackron.github.io/dr_libs/
Source download: https://github.com/mackron/dr_libs/blob/dd762b8/dr_mp3.h
License: MIT/Expat License: MIT/Expat
Copyright 2018 David Reid Copyright 2018 David Reid
@@ -97,20 +109,6 @@ This distribution contains code from the following projects (full license text b
License: MIT/Expat License: MIT/Expat
Copyright (c) 2017 Sean Barrett Copyright (c) 2017 Sean Barrett
- libmpg123
Website: http://www.mpg123.de/
Source download: http://sourceforge.net/projects/mpg123/files/latest/download
License: LGPL 2.1
Copyright (c) 1995-2013 by Michael Hipp and others, free software under the terms of the LGPL v2.1
Detailed information from the debian project:
Copyright 1995-2016 by the mpg123 project
Copyright 2009-2011 by Malcolm Boczek
Copyright 2008 Christian Weisgerber <naddy@openbsd.org>
Copyright 2006-2007 by Zuxy Meng
Copyright 2000-2002 David Olofson
Copyright 1998 Fabrice Bellard
Copyright 1997 Mikko Tommila
- OpenAL Soft - OpenAL Soft
Website: https://openal-soft.org/ Website: https://openal-soft.org/
Source download: https://openal-soft.org/#download Source download: https://openal-soft.org/#download
@@ -149,6 +147,21 @@ This distribution contains code from the following projects (full license text b
Copyright © 2013 Mike Gorchak Copyright © 2013 Mike Gorchak
Copyright © 2014 Timothy Arceri Copyright © 2014 Timothy Arceri
- Vulkan Memory Allocator
Website: https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
License: MIT/Expat
Copyright (c) 2017-2022 Advanced Micro Devices, Inc.
- volk
Website: https://github.com/zeux/volk
License: MIT/Expat
Copyright (c) 2018-2022 Arseny Kapoulkine
- Vulkan-Headers
Website: https://github.com/KhronosGroup/Vulkan-Headers
License: Apache 2.0
Copyright (c) 2022 Khronos Group
License text License text
============ ============
+12 -16
View File
@@ -1,4 +1,4 @@
AC_INIT([love], [11.5]) AC_INIT([love], [12.0])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_AUX_DIR([platform/unix]) AC_CONFIG_AUX_DIR([platform/unix])
AC_CONFIG_MACRO_DIR([platform/unix/m4]) AC_CONFIG_MACRO_DIR([platform/unix/m4])
@@ -18,7 +18,7 @@ AC_C_BIGENDIAN
AC_LANG([C++]) AC_LANG([C++])
dnl Workaround for old aclocal versions dnl Workaround for old aclocal versions
m4_include([platform/unix/cpp11.m4]) m4_include([platform/unix/cpp14.m4])
m4_include([platform/unix/deps.m4]) m4_include([platform/unix/deps.m4])
includes= includes=
@@ -26,8 +26,8 @@ includes=
AC_DEFUN([LOVE_MSG_ERROR], AC_DEFUN([LOVE_MSG_ERROR],
[AC_MSG_ERROR([LÖVE needs "$1"[,] please install "$1" with development files and try again])]) [AC_MSG_ERROR([LÖVE needs "$1"[,] please install "$1" with development files and try again])])
# C++11 support in cpp11.m4 # C++14 support in cpp14.m4
ACLOVE_CPP11_TEST ACLOVE_CPP14_TEST
# Add -fvisibility=hidden and -fvisibility-inlines-hidden # Add -fvisibility=hidden and -fvisibility-inlines-hidden
CFLAGS="-fvisibility=hidden $CFLAGS" CFLAGS="-fvisibility=hidden $CFLAGS"
@@ -58,10 +58,6 @@ with_clean_luaversion=`printf ${with_luaversion} | sed 's/\.//g'`
# Generated sources for enabling/disabling modules # Generated sources for enabling/disabling modules
m4_include([configure-modules-pre.ac]) m4_include([configure-modules-pre.ac])
# Other features that can be enabled/disabled
AC_ARG_ENABLE([mpg123], AC_HELP_STRING([--disable-mpg123], [Disable mp3 support, for patent-free builds]), [], [enable_mpg123=yes])
AC_ARG_ENABLE([gme], AC_HELP_STRING([--enable-gme], [Enable GME support, for more chiptuney goodness]), [], [enable_gme=no])
# Dependencies we always use # Dependencies we always use
ACLOVE_DEP_LUA ACLOVE_DEP_LUA
ACLOVE_DEP_SDL2 ACLOVE_DEP_SDL2
@@ -71,27 +67,28 @@ ACLOVE_DEP_PTHREAD
# Conditional dependencies # Conditional dependencies
AS_VAR_IF([enable_module_audio], [yes], [ACLOVE_DEP_OPENAL], []) AS_VAR_IF([enable_module_audio], [yes], [ACLOVE_DEP_OPENAL], [])
AS_VAR_IF([enable_module_font], [yes], [ACLOVE_DEP_FREETYPE2], []) AS_VAR_IF([enable_module_font], [yes], [
ACLOVE_DEP_FREETYPE2
ACLOVE_DEP_HARFBUZZ
], [])
AS_VAR_IF([enable_module_sound], [yes], [ AS_VAR_IF([enable_module_sound], [yes], [
ACLOVE_DEP_LIBMODPLUG ACLOVE_DEP_LIBMODPLUG
ACLOVE_DEP_VORBISFILE ACLOVE_DEP_VORBISFILE
], [enable_mpg123=no]) ], [])
AS_VAR_IF([enable_module_video], [yes], [ACLOVE_DEP_THEORA], []) AS_VAR_IF([enable_module_video], [yes], [ACLOVE_DEP_THEORA], [])
AS_VAR_IF([enable_gme], [yes], [ACLOVE_DEP_GME], [])
AS_VAR_IF([enable_mpg123], [no],
AC_DEFINE([LOVE_NOMPG123], [], [Build without mpg123]),
[ACLOVE_DEP_MPG123])
# Add flags for optional libraries # Add flags for optional libraries
AC_ARG_ENABLE([library-enet], [ --disable-library-enet Turn off library enet], [], [enable_library_enet=yes]) AC_ARG_ENABLE([library-enet], [ --disable-library-enet Turn off library enet], [], [enable_library_enet=yes])
AC_ARG_ENABLE([library-luasocket], [ --disable-library-luasocket Turn off library luasocket], [], [enable_library_luasocket=yes]) AC_ARG_ENABLE([library-luasocket], [ --disable-library-luasocket Turn off library luasocket], [], [enable_library_luasocket=yes])
AC_ARG_ENABLE([library-lua53], [ --disable-library-lua53 Turn off library lua53 (lua 5.3 backports, required by love.data)], [], [enable_library_lua53=yes]) AC_ARG_ENABLE([library-lua53], [ --disable-library-lua53 Turn off library lua53 (lua 5.3 backports, required by love.data)], [], [enable_library_lua53=yes])
AC_ARG_ENABLE([library-luahttps], [ --disable-library-luahttps Turn off library luahttps], [], [enable_library_luahttps=yes])
# Select the libraries we need to build, based on the selected modules # Select the libraries we need to build, based on the selected modules
AS_VAR_IF([enable_module_filesystem], [yes], [enable_library_physfs=yes], [enable_library_physfs=no]) AS_VAR_IF([enable_module_filesystem], [yes], [enable_library_physfs=yes], [enable_library_physfs=no])
AS_VAR_IF([enable_module_physics], [yes], [enable_library_Box2D=yes], [enable_library_Box2D=no]) AS_VAR_IF([enable_module_physics], [yes], [enable_library_box2d=yes], [enable_library_box2d=no])
AS_VAR_IF([enable_module_image], [yes], [enable_library_ddsparse=yes], [enable_library_ddsparse=no]) AS_VAR_IF([enable_module_image], [yes], [enable_library_ddsparse=yes], [enable_library_ddsparse=no])
AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glad=yes], [enable_library_glad=no]) AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glad=yes], [enable_library_glad=no])
AS_VAR_IF([enable_module_graphics], [yes], [enable_library_spirv_cross=yes], [enable_library_spirv_cross=no])
AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glslang=yes], [enable_library_glslang=no]) AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glslang=yes], [enable_library_glslang=no])
AS_VAR_IF([enable_module_image], [yes], [enable_library_lodepng=yes], [enable_library_lodepng=no]) AS_VAR_IF([enable_module_image], [yes], [enable_library_lodepng=yes], [enable_library_lodepng=no])
AS_VAR_IF([enable_module_data], [yes], [enable_library_lua53=yes], []) AS_VAR_IF([enable_module_data], [yes], [enable_library_lua53=yes], [])
@@ -121,7 +118,6 @@ AS_VAR_IF([enable_exe], [no], [], #else
AC_DEFINE([LOVE_BUILD_EXE], [], [Skip building launcher])) AC_DEFINE([LOVE_BUILD_EXE], [], [Skip building launcher]))
AM_CONDITIONAL([LOVE_BUILD_EXE], [test "x$enable_exe" != xno]) AM_CONDITIONAL([LOVE_BUILD_EXE], [test "x$enable_exe" != xno])
AM_CONDITIONAL([LOVE_NOMPG123], [test "x$enable_mpg123" = xno])
AM_CONDITIONAL([LOVE_TARGET_OSX], [test "x$enable_osx" != xno]) AM_CONDITIONAL([LOVE_TARGET_OSX], [test "x$enable_osx" != xno])
# Automatic script file rebuilding # Automatic script file rebuilding
@@ -22,48 +22,47 @@ AC_DEFUN([ACLOVE_GET_CLANG_VERSION], [
AC_COMPUTE_INT(aclove_clang_version_patch, __clang_patchlevel__,, aclove_clang_version_found="no") AC_COMPUTE_INT(aclove_clang_version_patch, __clang_patchlevel__,, aclove_clang_version_found="no")
]) ])
AC_DEFUN([ACLOVE_CPP11_TEST_FLAG], [ AC_DEFUN([ACLOVE_CPP14_TEST_FLAG], [
aclove_cpp11_test_cxx11name="no" aclove_cpp14_test_cxx14name="no"
ACLOVE_CXX_FLAG_TEST([-std=c++0x], aclove_cpp11_test_cxx11name="c++0x", []) ACLOVE_CXX_FLAG_TEST([-std=c++14], aclove_cpp14_test_cxx14name="c++14", [])
ACLOVE_CXX_FLAG_TEST([-std=c++11], aclove_cpp11_test_cxx11name="c++11", []) AS_VAR_IF([aclove_cpp14_test_cxx14name], [no],
AS_VAR_IF([aclove_cpp11_test_cxx11name], [no], [AC_MSG_ERROR([LÖVE needs a C++ compiler with C++14 support])],
[AC_MSG_ERROR([LÖVE needs a C++ compiler with C++11 support])], [CXXFLAGS="$CXXFLAGS -std=$aclove_cpp14_test_cxx14name"])
[CXXFLAGS="$CXXFLAGS -std=$aclove_cpp11_test_cxx11name"])
]) ])
AC_DEFUN([ACLOVE_CPP11_CHECK_VERSION], [ dnl compiler, targetmajor, targetminor, on-failure AC_DEFUN([ACLOVE_CPP14_CHECK_VERSION], [ dnl compiler, targetmajor, targetminor, on-failure
aclove_cpp11_check_version_status="no" aclove_cpp14_check_version_status="no"
AC_MSG_CHECKING([whether $1 version is at least $2.$3]) AC_MSG_CHECKING([whether $1 version is at least $2.$3])
AS_IF([test "$aclove_[]$1[]_version_major" -gt $2], aclove_cpp11_check_version_status="yes") AS_IF([test "$aclove_[]$1[]_version_major" -gt $2], aclove_cpp14_check_version_status="yes")
AS_IF([test "$aclove_[]$1[]_version_major" -eq $2 && test "$aclove_[]$1[]_version_minor" -ge $3], aclove_cpp11_check_version_status="yes") AS_IF([test "$aclove_[]$1[]_version_major" -eq $2 && test "$aclove_[]$1[]_version_minor" -ge $3], aclove_cpp14_check_version_status="yes")
AC_MSG_RESULT([$aclove_cpp11_check_version_status]) AC_MSG_RESULT([$aclove_cpp14_check_version_status])
AS_VAR_IF([aclove_cpp11_check_version_status], [no], AS_VAR_IF([aclove_cpp14_check_version_status], [no],
[$4]) [$4])
]) ])
AC_DEFUN([ACLOVE_CPP11_TEST_VERSION_GCC], [ AC_DEFUN([ACLOVE_CPP14_TEST_VERSION_GCC], [
ACLOVE_CPP11_CHECK_VERSION([gcc], 4, 7, ACLOVE_CPP14_CHECK_VERSION([gcc], 4, 9,
[AC_MSG_ERROR([LÖVE needs a GCC version of at least 4.7])]) [AC_MSG_ERROR([LÖVE needs a GCC version of at least 4.9])])
]) ])
AC_DEFUN([ACLOVE_CPP11_TEST_VERSION_CLANG], [ AC_DEFUN([ACLOVE_CPP14_TEST_VERSION_CLANG], [
ACLOVE_CPP11_CHECK_VERSION([clang], 3, 1, ACLOVE_CPP14_CHECK_VERSION([clang], 3, 4,
[AC_MSG_ERROR([LÖVE needs a clang version of at least 3.1])]) [AC_MSG_ERROR([LÖVE needs a clang version of at least 3.4])])
]) ])
AC_DEFUN([ACLOVE_CPP11_TEST], [ AC_DEFUN([ACLOVE_CPP14_TEST], [
ACLOVE_CPP11_TEST_FLAG ACLOVE_CPP14_TEST_FLAG
ACLOVE_GET_GCC_VERSION ACLOVE_GET_GCC_VERSION
ACLOVE_GET_CLANG_VERSION ACLOVE_GET_CLANG_VERSION
# Since clang also sets gcc headers, check clang after # Since clang also sets gcc headers, check clang after
aclove_cpp11_test_compiler="unknown" aclove_cpp14_test_compiler="unknown"
AS_VAR_IF([aclove_gcc_version_found], [yes], aclove_cpp11_test_compiler="gcc") AS_VAR_IF([aclove_gcc_version_found], [yes], aclove_cpp14_test_compiler="gcc")
AS_VAR_IF([aclove_clang_version_found], [yes], aclove_cpp11_test_compiler="clang") AS_VAR_IF([aclove_clang_version_found], [yes], aclove_cpp14_test_compiler="clang")
AS_CASE([$aclove_cpp11_test_compiler], AS_CASE([$aclove_cpp14_test_compiler],
[gcc], [ACLOVE_CPP11_TEST_VERSION_GCC], [gcc], [ACLOVE_CPP14_TEST_VERSION_GCC],
[clang], [ACLOVE_CPP11_TEST_VERSION_CLANG], [clang], [ACLOVE_CPP14_TEST_VERSION_CLANG],
[AC_MSG_WARN([Could not determine compiler version])]) [AC_MSG_WARN([Could not determine compiler version])])
]) ])
+2 -2
View File
@@ -8,13 +8,13 @@ Build-Depends: debhelper (>= 9),
libtool, libtool,
g++ (>= 4.7.0), g++ (>= 4.7.0),
libfreetype6-dev, libfreetype6-dev,
libharfbuzz-dev,
luajit, luajit,
libluajit-5.1-dev, libluajit-5.1-dev,
libmodplug-dev, libmodplug-dev,
libmpg123-dev,
libopenal-dev, libopenal-dev,
libphysfs-dev, libphysfs-dev,
libsdl2-dev (>= 2.0.1), libsdl2-dev (>= 2.0.9),
libogg-dev, libogg-dev,
libvorbis-dev, libvorbis-dev,
libtheora-dev, libtheora-dev,
+4 -6
View File
@@ -1,6 +1,9 @@
AC_DEFUN([ACLOVE_DEP_FREETYPE2], [ AC_DEFUN([ACLOVE_DEP_FREETYPE2], [
PKG_CHECK_MODULES([freetype2], [freetype2], [], [LOVE_MSG_ERROR([FreeType2])])]) PKG_CHECK_MODULES([freetype2], [freetype2], [], [LOVE_MSG_ERROR([FreeType2])])])
AC_DEFUN([ACLOVE_DEP_HARFBUZZ], [
PKG_CHECK_MODULES([harfbuzz], [harfbuzz], [], [LOVE_MSG_ERROR([Harfbuzz])])])
AC_DEFUN([ACLOVE_DEP_OPENAL], [ AC_DEFUN([ACLOVE_DEP_OPENAL], [
PKG_CHECK_MODULES([openal], [openal], [], [LOVE_MSG_ERROR([OpenAL])])]) PKG_CHECK_MODULES([openal], [openal], [], [LOVE_MSG_ERROR([OpenAL])])])
@@ -21,7 +24,7 @@ AC_DEFUN([ACLOVE_DEP_LIBM], [
AC_DEFUN([ACLOVE_DEP_SDL2], [ AC_DEFUN([ACLOVE_DEP_SDL2], [
aclove_sdl2_found=no aclove_sdl2_found=no
AM_PATH_SDL2([], [aclove_sdl2_found=yes], []) AM_PATH_SDL2([2.0.9], [aclove_sdl2_found=yes], [])
AS_VAR_IF([aclove_sdl2_found], [no], [LOVE_MSG_ERROR([SDL 2])], [])]) AS_VAR_IF([aclove_sdl2_found], [no], [LOVE_MSG_ERROR([SDL 2])], [])])
AC_DEFUN([ACLOVE_DEP_PTHREAD], [ AC_DEFUN([ACLOVE_DEP_PTHREAD], [
@@ -35,11 +38,6 @@ AC_DEFUN([ACLOVE_DEP_MPG123], [
AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]), AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]),
AC_SUBST([FILE_OFFSET],[]))]) AC_SUBST([FILE_OFFSET],[]))])
AC_DEFUN([ACLOVE_DEP_GME], [
AC_SEARCH_LIBS([gme_open_data], [gme], [], [LOVE_MSG_ERROR([gme])])
AC_DEFINE([LOVE_SUPPORT_GME], [], [Enable gme])
AC_CHECK_HEADER([gme/gme.h], [includes="$includes -I/usr/include/gme"], [])])
# For enet # For enet
AC_DEFUN([ACLOVE_SOCKLEN_T], [ AC_DEFUN([ACLOVE_SOCKLEN_T], [
AC_CHECK_TYPE([socklen_t], [AC_DEFINE([HAS_SOCKLEN_T], [1], [Define if socklen_t exists.] )], , AC_CHECK_TYPE([socklen_t], [AC_DEFINE([HAS_SOCKLEN_T], [1], [Define if socklen_t exists.] )], ,
-2
View File
@@ -1,5 +1,3 @@
\./libraries/luasocket/libluasocket/wsocket.* \./libraries/luasocket/libluasocket/wsocket.*
\./love\.cpp \./love\.cpp
\./modules/sound/lullaby/Mpg123Decoder\.cpp
\./modules/sound/lullaby/Mpg123Decoder\.h
\./libraries/glslang/glslang/OSDependent/Windows \./libraries/glslang/glslang/OSDependent/Windows
+3 -11
View File
@@ -45,14 +45,6 @@ genmodules()
printf "${FILES:0:${#FILES}-2}\n\n" printf "${FILES:0:${#FILES}-2}\n\n"
modulelist+=("$module") modulelist+=("$module")
fi fi
if [[ "$module" = "sound" ]]; then
printf "if !LOVE_NOMPG123\n"
printf "liblove_module_$module += \\\\\n"
printf "\t./modules/sound/lullaby/Mpg123Decoder.cpp \\\\\n"
printf "\t./modules/sound/lullaby/Mpg123Decoder.h\n"
printf "endif\n\n"
fi
done done
cd ../libraries cd ../libraries
@@ -114,8 +106,8 @@ inc_modules="$inc_current/modules"
inc_libraries="$inc_current/libraries" inc_libraries="$inc_current/libraries"
cat > src/Makefile.am << EOF cat > src/Makefile.am << EOF
AM_CPPFLAGS = -I$inc_current -I$inc_modules -I$inc_libraries -I$inc_libraries/enet/libenet/include \$(LOVE_INCLUDES) \$(FILE_OFFSET)\ AM_CPPFLAGS = -I$inc_current -I$inc_modules -I$inc_libraries -I$inc_libraries/enet/libenet/include -I$inc_libraries/box2d \$(LOVE_INCLUDES) \$(FILE_OFFSET)\
\$(SDL_CFLAGS) \$(lua_CFLAGS) \$(freetype2_CFLAGS)\ \$(SDL_CFLAGS) \$(lua_CFLAGS) \$(freetype2_CFLAGS) \$(harfbuzz_CFLAGS)\
\$(openal_CFLAGS) \$(zlib_CFLAGS) \$(libmodplug_CFLAGS)\ \$(openal_CFLAGS) \$(zlib_CFLAGS) \$(libmodplug_CFLAGS)\
\$(vorbisfile_CFLAGS) \$(theora_CFLAGS) \$(vorbisfile_CFLAGS) \$(theora_CFLAGS)
AUTOMAKE_OPTIONS = subdir-objects AUTOMAKE_OPTIONS = subdir-objects
@@ -147,7 +139,7 @@ endif
lib_LTLIBRARIES = liblove${love_suffix}.la lib_LTLIBRARIES = liblove${love_suffix}.la
liblove${love_amsuffix}_la_LDFLAGS = -module -export-dynamic \$(LDFLAGS) -release \$(PACKAGE_VERSION) liblove${love_amsuffix}_la_LDFLAGS = -module -export-dynamic \$(LDFLAGS) -release \$(PACKAGE_VERSION)
liblove${love_amsuffix}_la_LIBADD = \ liblove${love_amsuffix}_la_LIBADD = \
\$(SDL_LIBS) \$(freetype2_LIBS) \$(lua_LIBS)\ \$(SDL_LIBS) \$(freetype2_LIBS) \$(harfbuzz_LIBS) \$(lua_LIBS)\
\$(openal_LIBS) \$(zlib_LIBS) \$(libmodplug_LIBS)\ \$(openal_LIBS) \$(zlib_LIBS) \$(libmodplug_LIBS)\
\$(vorbisfile_LIBS) \$(theora_LIBS) \$(vorbisfile_LIBS) \$(theora_LIBS)
+1 -1
View File
@@ -12,7 +12,7 @@
.\" 3. This notice may not be removed or altered from any source distribution. .\" 3. This notice may not be removed or altered from any source distribution.
.Dd March 31, 2018 .Dd March 31, 2018
.Dt LOVE 6 .Dt LOVE 6
.Os LÖVE 11.5 .Os LÖVE 12.0
.Sh NAME .Sh NAME
.Nm love .Nm love
.Nd 2D game development framework .Nd 2D game development framework
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -13,9 +13,9 @@
A9255F58104324E100BA1496 /* ogg.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255F51104324D700BA1496 /* ogg.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; A9255F58104324E100BA1496 /* ogg.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255F51104324D700BA1496 /* ogg.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
A93E6E5510420B57007D418B /* Lua.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; }; A93E6E5510420B57007D418B /* Lua.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; };
A93E6EED10420BA8007D418B /* love.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A93E6A3410420AC0007D418B /* love.cpp */; }; A93E6EED10420BA8007D418B /* love.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A93E6A3410420AC0007D418B /* love.cpp */; };
A9F169AC109E825000FC83D1 /* mpg123.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9F169A6109E824900FC83D1 /* mpg123.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9F16926109E7BAD00FC83D1 /* libmodplug.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9F16926109E7BAD00FC83D1 /* libmodplug.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
CE73F8001EEB64150052DAB3 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */; }; CE73F8001EEB64150052DAB3 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */; };
D9DAB9372963CF6900C64820 /* harfbuzz.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D9DAB9352963CF5F00C64820 /* harfbuzz.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
FA0797991BF480A200034B7C /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA0797981BF480A200034B7C /* GameController.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; FA0797991BF480A200034B7C /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA0797981BF480A200034B7C /* GameController.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
FA08F69616C766E000F007B5 /* love.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; }; FA08F69616C766E000F007B5 /* love.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; };
FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
@@ -88,7 +88,7 @@
FAD4B1731C1F50A3004CF150 /* theora.framework in Copy Frameworks */, FAD4B1731C1F50A3004CF150 /* theora.framework in Copy Frameworks */,
FAAFF04716CB120000CCDE45 /* OpenAL-Soft.framework in Copy Frameworks */, FAAFF04716CB120000CCDE45 /* OpenAL-Soft.framework in Copy Frameworks */,
FAD43ED01FF3136500831BB8 /* freetype.framework in Copy Frameworks */, FAD43ED01FF3136500831BB8 /* freetype.framework in Copy Frameworks */,
A9F169AC109E825000FC83D1 /* mpg123.framework in Copy Frameworks */, D9DAB9372963CF6900C64820 /* harfbuzz.framework in Copy Frameworks */,
A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */, A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */,
A9255F58104324E100BA1496 /* ogg.framework in Copy Frameworks */, A9255F58104324E100BA1496 /* ogg.framework in Copy Frameworks */,
A9255E031043195A00BA1496 /* vorbis.framework in Copy Frameworks */, A9255E031043195A00BA1496 /* vorbis.framework in Copy Frameworks */,
@@ -109,8 +109,8 @@
A93E6E5310420B57007D418B /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = macosx/Frameworks/Lua.framework; sourceTree = "<group>"; }; A93E6E5310420B57007D418B /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = macosx/Frameworks/Lua.framework; sourceTree = "<group>"; };
A97E3842132A9EDE00198A2F /* love-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "love-macosx.plist"; path = "macosx/love-macosx.plist"; sourceTree = "<group>"; }; A97E3842132A9EDE00198A2F /* love-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "love-macosx.plist"; path = "macosx/love-macosx.plist"; sourceTree = "<group>"; };
A9F16926109E7BAD00FC83D1 /* libmodplug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libmodplug.framework; path = macosx/Frameworks/libmodplug.framework; sourceTree = "<group>"; }; A9F16926109E7BAD00FC83D1 /* libmodplug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libmodplug.framework; path = macosx/Frameworks/libmodplug.framework; sourceTree = "<group>"; };
A9F169A6109E824900FC83D1 /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = macosx/Frameworks/mpg123.framework; sourceTree = "<group>"; };
CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; }; CE73F7FF1EEB64150052DAB3 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; };
D9DAB9352963CF5F00C64820 /* harfbuzz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = harfbuzz.framework; path = macosx/Frameworks/harfbuzz.framework; sourceTree = "<group>"; };
FA0797981BF480A200034B7C /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; }; FA0797981BF480A200034B7C /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/System/Library/Frameworks/GameController.framework; sourceTree = DEVELOPER_DIR; };
FA08F69116C765A200F007B5 /* love.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FA08F69116C765A200F007B5 /* love.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FA0B7F061A95AAF3000E1D17 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; }; FA0B7F061A95AAF3000E1D17 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -236,10 +236,10 @@
children = ( children = (
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
FAD43ECF1FF3133700831BB8 /* freetype.framework */, FAD43ECF1FF3133700831BB8 /* freetype.framework */,
D9DAB9352963CF5F00C64820 /* harfbuzz.framework */,
A9F16926109E7BAD00FC83D1 /* libmodplug.framework */, A9F16926109E7BAD00FC83D1 /* libmodplug.framework */,
FA08F69116C765A200F007B5 /* love.framework */, FA08F69116C765A200F007B5 /* love.framework */,
A93E6E5310420B57007D418B /* Lua.framework */, A93E6E5310420B57007D418B /* Lua.framework */,
A9F169A6109E824900FC83D1 /* mpg123.framework */,
A9255F51104324D700BA1496 /* ogg.framework */, A9255F51104324D700BA1496 /* ogg.framework */,
FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */, FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */,
A93E6E4710420B4A007D418B /* OpenGL.framework */, A93E6E4710420B4A007D418B /* OpenGL.framework */,
@@ -332,7 +332,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = { 29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1310; LastUpgradeCheck = 1340;
TargetAttributes = { TargetAttributes = {
FA0B7F051A95AAF3000E1D17 = { FA0B7F051A95AAF3000E1D17 = {
CreatedOnToolsVersion = 6.1.1; CreatedOnToolsVersion = 6.1.1;
@@ -464,7 +464,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 11.5; MARKETING_VERSION = 12.0;
PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love; PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love;
PRODUCT_NAME = love; PRODUCT_NAME = love;
}; };
@@ -496,7 +496,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 11.5; MARKETING_VERSION = 12.0;
PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love; PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love;
PRODUCT_NAME = love; PRODUCT_NAME = love;
}; };
@@ -507,7 +507,7 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
@@ -562,9 +562,9 @@
"\"$(SRCROOT)/../../src/modules\"", "\"$(SRCROOT)/../../src/modules\"",
); );
INFOPLIST_FILE = "love-Info.plist"; INFOPLIST_FILE = "love-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = love; PRODUCT_NAME = love;
SDKROOT = macosx; SDKROOT = macosx;
@@ -580,7 +580,7 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
@@ -637,10 +637,10 @@
"\"$(SRCROOT)/../../src/modules\"", "\"$(SRCROOT)/../../src/modules\"",
); );
INFOPLIST_FILE = "love-Info.plist"; INFOPLIST_FILE = "love-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
LLVM_LTO = YES; LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = love; PRODUCT_NAME = love;
SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES;
@@ -697,7 +697,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 11.5; MARKETING_VERSION = 12.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love; PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love;
PRODUCT_NAME = love; PRODUCT_NAME = love;
@@ -747,7 +747,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 11.5; MARKETING_VERSION = 12.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love; PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love;
PRODUCT_NAME = love; PRODUCT_NAME = love;
@@ -798,7 +798,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 11.5; MARKETING_VERSION = 12.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love; PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love;
PRODUCT_NAME = love; PRODUCT_NAME = love;
@@ -814,7 +814,7 @@
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++"; CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_ARC = YES;
@@ -871,10 +871,10 @@
"\"$(SRCROOT)/../../src/modules\"", "\"$(SRCROOT)/../../src/modules\"",
); );
INFOPLIST_FILE = "love-Info.plist"; INFOPLIST_FILE = "love-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks";
LLVM_LTO = YES; LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.7; MACOSX_DEPLOYMENT_TARGET = 10.9;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = love; PRODUCT_NAME = love;
SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES;
@@ -912,7 +912,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MARKETING_VERSION = 11.5; MARKETING_VERSION = 12.0;
PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love; PRODUCT_BUNDLE_IDENTIFIER = org.love2d.love;
PRODUCT_NAME = love; PRODUCT_NAME = love;
}; };
+1 -1
View File
@@ -17,7 +17,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string> <string>12.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>LoVe</string> <string>LoVe</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
-2
View File
@@ -1,6 +1,5 @@
LÖVE is an *awesome* framework you can use to make 2D games in Lua. It's free, open-source, and works on Windows, macOS, Linux, Android, and iOS. LÖVE is an *awesome* framework you can use to make 2D games in Lua. It's free, open-source, and works on Windows, macOS, Linux, Android, and iOS.
[![Build Status: Windows](https://ci.appveyor.com/api/projects/status/chc0hdr08wv1d5c7?svg=true)](https://ci.appveyor.com/project/slime73/love)
[![Build Status: Github CI](https://github.com/love2d/love/workflows/continuous-integration/badge.svg)](https://github.com/love2d/love/actions?query=workflow%3Acontinuous-integration) [![Build Status: Github CI](https://github.com/love2d/love/workflows/continuous-integration/badge.svg)](https://github.com/love2d/love/actions?query=workflow%3Acontinuous-integration)
Documentation Documentation
@@ -91,7 +90,6 @@ Dependencies
- Lua / LuaJIT / LLVM-lua - Lua / LuaJIT / LLVM-lua
- FreeType - FreeType
- ModPlug - ModPlug
- mpg123
- Vorbisfile - Vorbisfile
- Theora - Theora
+1
View File
@@ -137,6 +137,7 @@ ColorT<T> operator/(const ColorT<T> &a, T s)
typedef ColorT<unsigned char> Color32; typedef ColorT<unsigned char> Color32;
typedef ColorT<float> Colorf; typedef ColorT<float> Colorf;
typedef ColorT<double> ColorD;
inline Color32 toColor32(Colorf cf) inline Color32 toColor32(Colorf cf)
{ {
+43
View File
@@ -181,6 +181,32 @@ const float *Matrix4::getElements() const
return e; return e;
} }
void Matrix4::setRow(int r, const Vector4 &v)
{
e[0 * 4 + r] = v.x;
e[1 * 4 + r] = v.y;
e[2 * 4 + r] = v.z;
e[3 * 4 + r] = v.w;
}
Vector4 Matrix4::getRow(int r) const
{
return Vector4(e[0 * 4 + r], e[1 * 4 + r], e[2 * 4 + r], e[3 * 4 + r]);
}
void Matrix4::setColumn(int c, const Vector4 &v)
{
e[c * 4 + 0] = v.x;
e[c * 4 + 1] = v.y;
e[c * 4 + 2] = v.z;
e[c * 4 + 3] = v.w;
}
Vector4 Matrix4::getColumn(int c) const
{
return Vector4(e[c * 4 + 0], e[c * 4 + 1], e[c * 4 + 2], e[c * 4 + 3]);
}
void Matrix4::setIdentity() void Matrix4::setIdentity()
{ {
memset(e, 0, sizeof(float)*16); memset(e, 0, sizeof(float)*16);
@@ -430,6 +456,23 @@ Matrix4 Matrix4::ortho(float left, float right, float bottom, float top, float n
return m; return m;
} }
Matrix4 Matrix4::perspective(float verticalfov, float aspect, float near, float far)
{
Matrix4 m;
float cotangent = 1.0f / tanf(verticalfov * 0.5f);
m.e[0] = cotangent / aspect;
m.e[5] = cotangent;
m.e[10] = (far + near) / (near - far);
m.e[11] = -1.0f;
m.e[14] = 2.0f * near * far / (near - far);
m.e[15] = 0.0f;
return m;
}
/** /**
* | e0 e3 e6 | * | e0 e3 e6 |
* | e1 e4 e7 | * | e1 e4 e7 |
+11
View File
@@ -23,6 +23,7 @@
// LOVE // LOVE
#include "math.h" #include "math.h"
#include "Vector.h"
namespace love namespace love
{ {
@@ -88,6 +89,11 @@ public:
**/ **/
const float *getElements() const; const float *getElements() const;
void setRow(int r, const Vector4 &v);
Vector4 getRow(int r) const;
void setColumn(int c, const Vector4 &v);
Vector4 getColumn(int c) const;
/** /**
* Resets this Matrix to the identity matrix. * Resets this Matrix to the identity matrix.
**/ **/
@@ -222,6 +228,11 @@ public:
**/ **/
static Matrix4 ortho(float left, float right, float bottom, float top, float near, float far); static Matrix4 ortho(float left, float right, float bottom, float top, float near, float far);
/**
* Creates a new perspective projection matrix.
**/
static Matrix4 perspective(float verticalfov, float aspect, float near, float far);
private: private:
/** /**
+9 -6
View File
@@ -113,15 +113,18 @@ void Module::registerInstance(Module *instance)
registry.insert(make_pair(name, instance)); registry.insert(make_pair(name, instance));
ModuleType moduletype = instance->getModuleType(); ModuleType mtype = instance->getModuleType();
if (instances[moduletype] != nullptr) if (mtype != M_UNKNOWN)
{ {
printf("Warning: overwriting module instance %s with new instance %s\n", if (instances[mtype] != nullptr)
instances[moduletype]->getName(), instance->getName()); {
} printf("Warning: overwriting module instance %s with new instance %s\n",
instances[mtype]->getName(), instance->getName());
}
instances[moduletype] = instance; instances[mtype] = instance;
}
} }
Module *Module::getInstance(const std::string &name) Module *Module::getInstance(const std::string &name)
+3 -1
View File
@@ -38,6 +38,7 @@ public:
enum ModuleType enum ModuleType
{ {
M_UNKNOWN = -1, // Use this for modules outside of LOVE's source code.
M_AUDIO, M_AUDIO,
M_DATA, M_DATA,
M_EVENT, M_EVENT,
@@ -50,6 +51,7 @@ public:
M_MATH, M_MATH,
M_MOUSE, M_MOUSE,
M_PHYSICS, M_PHYSICS,
M_SENSOR,
M_SOUND, M_SOUND,
M_SYSTEM, M_SYSTEM,
M_THREAD, M_THREAD,
@@ -99,7 +101,7 @@ public:
template <typename T> template <typename T>
static T *getInstance(ModuleType type) static T *getInstance(ModuleType type)
{ {
return (T *) instances[type]; return type != M_UNKNOWN ? (T *) instances[type] : nullptr;
} }
private: private:
+14
View File
@@ -78,6 +78,20 @@ private:
}; // Object }; // Object
/**
* Structure wrapping an object and its associated Type instance. This is used
* for storing everything necessary to identify an object's properties in
* environments where the Type is not easily obtained otherwise, for example in
* a Lua state.
**/
struct Proxy
{
// Holds type information (see types.h).
love::Type *type;
// Pointer to the actual object.
Object *object;
};
enum class Acquire enum class Acquire
{ {
+10
View File
@@ -45,6 +45,16 @@ struct Optional
value = val; value = val;
hasValue = true; hasValue = true;
} }
T get(T defaultVal)
{
return hasValue ? value : defaultVal;
}
void clear()
{
hasValue = false;
}
}; };
typedef Optional<bool> OptionalBool; typedef Optional<bool> OptionalBool;
+94
View File
@@ -0,0 +1,94 @@
/**
* Copyright (c) 2006-2023 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.
**/
#pragma once
#include <stddef.h>
#include <algorithm>
#include <limits>
namespace love
{
struct Range
{
size_t first;
size_t last;
Range()
: first(std::numeric_limits<size_t>::max())
, last(0)
{}
Range(size_t offset, size_t size)
: first(offset)
, last(offset + size - 1)
{}
bool isValid() const { return first <= last; }
void invalidate()
{
first = std::numeric_limits<size_t>::max();
last = 0;
}
size_t getMin() const { return first; }
size_t getMax() const { return last; }
size_t getOffset() const { return first; }
size_t getSize() const { return (last - first) + 1; }
bool contains(const Range &other) const
{
return first <= other.first && last >= other.last;
}
bool intersects(const Range &other)
{
return !(first > other.last || last < other.first);
}
void intersect(const Range &other)
{
first = std::max(first, other.first);
last = std::min(last, other.last);
}
void encapsulate(size_t index)
{
first = std::min(first, index);
last = std::max(last, index);
}
void encapsulate(size_t offset, size_t size)
{
first = std::min(first, offset);
last = std::max(last, offset + size - 1);
}
void encapsulate(const Range &other)
{
first = std::min(first, other.first);
last = std::max(last, other.last);
}
};
} // love
+49
View File
@@ -20,10 +20,59 @@
// LOVE // LOVE
#include "Stream.h" #include "Stream.h"
#include "Data.h"
#include "data/ByteData.h"
#include "Exception.h"
namespace love namespace love
{ {
love::Type Stream::type("Stream", &Object::type); love::Type Stream::type("Stream", &Object::type);
Data *Stream::read(int64 size)
{
int64 max = LOVE_INT64_MAX;
int64 cur = 0;
if (isSeekable())
{
max = getSize();
cur = tell();
}
if (cur < 0)
cur = 0;
else if (cur > max)
cur = max;
if (cur + size > max)
size = max - cur;
StrongRef<data::ByteData> dst(new data::ByteData(size, false), Acquire::NORETAIN);
int64 bytesRead = read(dst->getData(), size);
if (bytesRead < 0 || (bytesRead == 0 && bytesRead != size))
throw love::Exception("Could not read from stream.");
if (bytesRead < size)
dst.set(new data::ByteData(dst->getData(), (size_t) bytesRead), Acquire::NORETAIN);
dst->retain();
return dst;
}
bool Stream::write(Data *src)
{
return write(src, 0, src->getSize());
}
bool Stream::write(Data *src, int64 offset, int64 size)
{
if (offset < 0 || size < 0 || offset + size > (int64) src->getSize())
throw love::Exception("Offset and size parameters do not fit within the given Data's size.");
return write((const uint8 *) src->getData() + offset, size);
}
} // love } // love
+63 -12
View File
@@ -24,41 +24,92 @@
// LOVE // LOVE
#include <stddef.h> #include <stddef.h>
#include "Object.h" #include "Object.h"
#include "int.h"
namespace love namespace love
{ {
class Data;
class Stream : public Object class Stream : public Object
{ {
public: public:
enum SeekOrigin
{
SEEKORIGIN_BEGIN,
SEEKORIGIN_CURRENT,
SEEKORIGIN_END,
SEEKORIGIN_MAX_ENUM
};
static love::Type type; static love::Type type;
virtual ~Stream() {} virtual ~Stream() {}
// getData and getSize are assumed to talk about /**
// the buffer * Creates a new copy of the Stream, with the same settings as the original.
* The seek position will be reset in the copy.
**/
virtual Stream *clone() = 0;
/** /**
* A callback, gets called when some Stream consumer exhausts the data * Gets whether read() is supported for this Stream.
**/ **/
virtual void fillBackBuffer() {} virtual bool isReadable() const = 0;
/** /**
* Get the front buffer, Streams are supposed to be (at least) double-buffered * Gets whether write() is supported for this Stream.
**/ **/
virtual const void *getFrontBuffer() const = 0; virtual bool isWritable() const = 0;
/** /**
* Get the size of any (and in particular the front) buffer * Gets whether seek(), tell(), and getSize() are supported for this Stream.
**/ **/
virtual size_t getSize() const = 0; virtual bool isSeekable() const = 0;
/** /**
* Swap buffers. Returns true if there is new data in the front buffer, * Reads data into the destination buffer, and returns the number of bytes
* false otherwise. * actually read.
* NOTE: If there is no back buffer ready, this call must be ignored
**/ **/
virtual bool swapBuffers() = 0; virtual int64 read(void *dst, int64 size) = 0;
/**
* Reads data into a new Data object.
**/
virtual Data *read(int64 size);
/**
* Writes data from the source buffer into the Stream.
**/
virtual bool write(const void *src, int64 size) = 0;
/**
* Writes data from the source Data object into the Stream.
**/
virtual bool write(Data *src, int64 offset, int64 size);
bool write(Data *src);
/**
* Flushes all data written to the Stream.
**/
virtual bool flush() = 0;
/**
* Gets the total size of the Stream, if supported.
**/
virtual int64 getSize() = 0;
/**
* Sets the current position in the Stream, if supported.
**/
virtual bool seek(int64 pos, SeekOrigin origin = SEEKORIGIN_BEGIN) = 0;
/**
* Gets the current position in the Stream, if supported.
**/
virtual int64 tell() = 0;
}; // Stream }; // Stream
} // love } // love
+30 -2
View File
@@ -21,8 +21,6 @@
#ifndef LOVE_STRING_MAP_H #ifndef LOVE_STRING_MAP_H
#define LOVE_STRING_MAP_H #define LOVE_STRING_MAP_H
#include "Exception.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -182,6 +180,36 @@ private:
}; // StringMap }; // StringMap
#define STRINGMAP_DECLARE(type) \
bool getConstant(const char *in, type &out); \
bool getConstant(type in, const char *&out); \
std::vector<std::string> getConstants(type); \
#define STRINGMAP_BEGIN(type, count, name) \
static StringMap<type, count>::Entry name##Entries[] =
#define STRINGMAP_END(type, count, name) \
; \
static StringMap<type, count> name##s(name##Entries, sizeof(name##Entries)); \
bool getConstant(const char *in, type &out) { return name##s.find(in, out); } \
bool getConstant(type in, const char *&out) { return name##s.find(in, out); } \
std::vector<std::string> getConstants(type) { return name##s.getNames(); }
#define STRINGMAP_CLASS_DECLARE(type) \
static bool getConstant(const char *in, type &out); \
static bool getConstant(type in, const char *&out); \
static std::vector<std::string> getConstants(type); \
#define STRINGMAP_CLASS_BEGIN(classname, type, count, name) \
static StringMap<type, count>::Entry name##Entries[] =
#define STRINGMAP_CLASS_END(classname, type, count, name) \
; \
static StringMap<type, count> name##s(name##Entries, sizeof(name##Entries)); \
bool classname::getConstant(const char *in, type &out) { return name##s.find(in, out); } \
bool classname::getConstant(type in, const char *&out) { return name##s.find(in, out); } \
std::vector<std::string> classname::getConstants(type) { return name##s.getNames(); }
} // love } // love
#endif // LOVE_STRING_MAP_H #endif // LOVE_STRING_MAP_H
+6 -149
View File
@@ -26,25 +26,13 @@
namespace love namespace love
{ {
static Proxy *tryextractproxy(lua_State *L, int idx) Variant::Variant(Type vtype)
{ : type(vtype)
Proxy *u = (Proxy *)lua_touserdata(L, idx); {}
if (u == nullptr || u->type == nullptr)
return nullptr;
// We could get rid of the dynamic_cast for more performance, but it would
// be less safe...
if (dynamic_cast<Object *>(u->object) != nullptr)
return u;
return nullptr;
}
Variant::Variant() Variant::Variant()
: type(NIL) : type(NIL)
{ {}
}
Variant::Variant(bool boolean) Variant::Variant(bool boolean)
: type(BOOLEAN) : type(BOOLEAN)
@@ -95,10 +83,10 @@ Variant::Variant(love::Type *lovetype, love::Object *object)
} }
// Variant gets ownership of the vector. // Variant gets ownership of the vector.
Variant::Variant(std::vector<std::pair<Variant, Variant>> *table) Variant::Variant(SharedTable *table)
: type(TABLE) : type(TABLE)
{ {
data.table = new SharedTable(table); data.table = table;
} }
Variant::Variant(const Variant &v) Variant::Variant(const Variant &v)
@@ -152,135 +140,4 @@ Variant &Variant::operator = (const Variant &v)
return *this; return *this;
} }
Variant Variant::fromLua(lua_State *L, int n, std::set<const void*> *tableSet)
{
size_t len;
const char *str;
Proxy *p = nullptr;
if (n < 0) // Fix the stack position, we might modify it later
n += lua_gettop(L) + 1;
switch (lua_type(L, n))
{
case LUA_TBOOLEAN:
return Variant(luax_toboolean(L, n));
case LUA_TNUMBER:
return Variant(lua_tonumber(L, n));
case LUA_TSTRING:
str = lua_tolstring(L, n, &len);
return Variant(str, len);
case LUA_TLIGHTUSERDATA:
return Variant(lua_touserdata(L, n));
case LUA_TUSERDATA:
p = tryextractproxy(L, n);
if (p != nullptr)
return Variant(p->type, p->object);
else
{
luax_typerror(L, n, "love type");
return Variant();
}
case LUA_TNIL:
return Variant();
case LUA_TTABLE:
{
bool success = true;
std::set<const void *> topTableSet;
std::vector<std::pair<Variant, Variant>> *table = new std::vector<std::pair<Variant, Variant>>();
// We can use a pointer to a stack-allocated variable because it's
// never used after the stack-allocated variable is destroyed.
if (tableSet == nullptr)
tableSet = &topTableSet;
// Now make sure this table wasn't already serialised
const void *tablePointer = lua_topointer(L, n);
{
auto result = tableSet->insert(tablePointer);
if (!result.second) // insertion failed
throw love::Exception("Cycle detected in table");
}
size_t len = luax_objlen(L, -1);
if (len > 0)
table->reserve(len);
lua_pushnil(L);
while (lua_next(L, n))
{
table->emplace_back(fromLua(L, -2, tableSet), fromLua(L, -1, tableSet));
lua_pop(L, 1);
const auto &p = table->back();
if (p.first.getType() == UNKNOWN || p.second.getType() == UNKNOWN)
{
success = false;
break;
}
}
// And remove the table from the set again
tableSet->erase(tablePointer);
if (success)
return Variant(table);
else
delete table;
}
break;
}
Variant v;
v.type = UNKNOWN;
return v;
}
void Variant::toLua(lua_State *L) const
{
switch (type)
{
case BOOLEAN:
lua_pushboolean(L, data.boolean);
break;
case NUMBER:
lua_pushnumber(L, data.number);
break;
case STRING:
lua_pushlstring(L, data.string->str, data.string->len);
break;
case SMALLSTRING:
lua_pushlstring(L, data.smallstring.str, data.smallstring.len);
break;
case LUSERDATA:
lua_pushlightuserdata(L, data.userdata);
break;
case LOVEOBJECT:
luax_pushtype(L, *data.objectproxy.type, data.objectproxy.object);
break;
case TABLE:
{
std::vector<std::pair<Variant, Variant>> *table = data.table->table;
int tsize = (int) table->size();
lua_createtable(L, 0, tsize);
for (int i = 0; i < tsize; ++i)
{
std::pair<Variant, Variant> &kv = (*table)[i];
kv.first.toLua(L);
kv.second.toLua(L);
lua_settable(L, -3);
}
break;
}
case NIL:
default:
lua_pushnil(L);
break;
}
}
} // love } // love
+9 -13
View File
@@ -21,19 +21,18 @@
#ifndef LOVE_VARIANT_H #ifndef LOVE_VARIANT_H
#define LOVE_VARIANT_H #define LOVE_VARIANT_H
#include "common/runtime.h" #include "common/config.h"
#include "common/Object.h" #include "common/Object.h"
#include "common/int.h" #include "common/int.h"
#include <cstring> #include <cstring>
#include <string> #include <string>
#include <vector> #include <vector>
#include <set>
namespace love namespace love
{ {
class Variant class LOVE_EXPORT Variant
{ {
public: public:
@@ -73,14 +72,10 @@ public:
{ {
public: public:
SharedTable(std::vector<std::pair<Variant, Variant>> *table) SharedTable() {}
: table(table) virtual ~SharedTable() {}
{
}
virtual ~SharedTable() { delete table; } std::vector<std::pair<Variant, Variant>> pairs;
std::vector<std::pair<Variant, Variant>> *table;
}; };
union Data union Data
@@ -105,7 +100,7 @@ public:
Variant(const std::string &str); Variant(const std::string &str);
Variant(void *lightuserdata); Variant(void *lightuserdata);
Variant(love::Type *type, love::Object *object); Variant(love::Type *type, love::Object *object);
Variant(std::vector<std::pair<Variant, Variant>> *table); Variant(SharedTable *table);
Variant(const Variant &v); Variant(const Variant &v);
Variant(Variant &&v); Variant(Variant &&v);
~Variant(); ~Variant();
@@ -115,11 +110,12 @@ public:
Type getType() const { return type; } Type getType() const { return type; }
const Data &getData() const { return data; } const Data &getData() const { return data; }
static Variant fromLua(lua_State *L, int n, std::set<const void*> *tableSet = nullptr); static Variant unknown() { return Variant(UNKNOWN); }
void toLua(lua_State *L) const;
private: private:
Variant(Type vtype);
Type type; Type type;
Data data; Data data;
+195 -134
View File
@@ -19,6 +19,7 @@
**/ **/
#include "android.h" #include "android.h"
#include "Object.h"
#ifdef LOVE_ANDROID #ifdef LOVE_ANDROID
@@ -35,6 +36,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "libraries/physfs/physfs.h"
#include "filesystem/physfs/PhysfsIo.h" #include "filesystem/physfs/PhysfsIo.h"
namespace love namespace love
@@ -45,13 +47,11 @@ namespace android
void setImmersive(bool immersive_active) void setImmersive(bool immersive_active)
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity(); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
jclass clazz(env->GetObjectClass(activity)); static jmethodID setImmersiveMethod = env->GetMethodID(clazz, "setImmersiveMode", "(Z)V");
jmethodID method_id = env->GetMethodID(clazz, "setImmersiveMode", "(Z)V"); env->CallVoidMethod(activity, setImmersiveMethod, immersive_active);
env->CallVoidMethod(activity, method_id, immersive_active);
env->DeleteLocalRef(activity); env->DeleteLocalRef(activity);
env->DeleteLocalRef(clazz); env->DeleteLocalRef(clazz);
@@ -60,18 +60,16 @@ void setImmersive(bool immersive_active)
bool getImmersive() bool getImmersive()
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity(); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
jclass clazz(env->GetObjectClass(activity)); static jmethodID getImmersiveMethod = env->GetMethodID(clazz, "getImmersiveMode", "()Z");
jmethodID method_id = env->GetMethodID(clazz, "getImmersiveMode", "()Z"); jboolean immersiveActive = env->CallBooleanMethod(activity, getImmersiveMethod);
jboolean immersive_active = env->CallBooleanMethod(activity, method_id);
env->DeleteLocalRef(activity); env->DeleteLocalRef(activity);
env->DeleteLocalRef(clazz); env->DeleteLocalRef(clazz);
return immersive_active; return immersiveActive;
} }
double getScreenScale() double getScreenScale()
@@ -81,16 +79,13 @@ double getScreenScale()
if (result == -1.) if (result == -1.)
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jclass activity = env->FindClass("org/love2d/android/GameActivity"); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
jmethodID getMetrics = env->GetStaticMethodID(activity, "getMetrics", "()Landroid/util/DisplayMetrics;"); jmethodID getDPIMethod = env->GetMethodID(clazz, "getDPIScale", "()F");
jobject metrics = env->CallStaticObjectMethod(activity, getMetrics); result = (double) env->CallFloatMethod(activity, getDPIMethod);
jclass metricsClass = env->GetObjectClass(metrics);
result = env->GetFloatField(metrics, env->GetFieldID(metricsClass, "density", "F")); env->DeleteLocalRef(clazz);
env->DeleteLocalRef(metricsClass);
env->DeleteLocalRef(metrics);
env->DeleteLocalRef(activity); env->DeleteLocalRef(activity);
} }
@@ -101,8 +96,10 @@ bool getSafeArea(int &top, int &left, int &bottom, int &right)
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity(); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz(env->GetObjectClass(activity)); jclass clazz = env->GetObjectClass(activity);
jmethodID methodID = env->GetMethodID(clazz, "initializeSafeArea", "()Z");
static jmethodID methodID = env->GetMethodID(clazz, "getSafeArea", "()Z");
bool hasSafeArea = false; bool hasSafeArea = false;
if (methodID == nullptr) if (methodID == nullptr)
@@ -122,64 +119,33 @@ bool getSafeArea(int &top, int &left, int &bottom, int &right)
return hasSafeArea; return hasSafeArea;
} }
const char *getSelectedGameFile()
{
static const char *path = NULL;
if (path)
{
delete path;
path = NULL;
}
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jclass activity = env->FindClass("org/love2d/android/GameActivity");
jmethodID getGamePath = env->GetStaticMethodID(activity, "getGamePath", "()Ljava/lang/String;");
jstring gamePath = (jstring) env->CallStaticObjectMethod(activity, getGamePath);
const char *utf = env->GetStringUTFChars(gamePath, 0);
if (utf)
{
path = SDL_strdup(utf);
env->ReleaseStringUTFChars(gamePath, utf);
}
env->DeleteLocalRef(gamePath);
env->DeleteLocalRef(activity);
return path;
}
bool openURL(const std::string &url) bool openURL(const std::string &url)
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jclass activity = env->FindClass("org/love2d/android/GameActivity"); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
jmethodID openURL = env->GetStaticMethodID(activity, "openURLFromLOVE", "(Ljava/lang/String;)Z"); static jmethodID openURL = env->GetMethodID(clazz, "openURLFromLOVE", "(Ljava/lang/String;)Z");
if (openURL == nullptr) jstring jstringURL = env->NewStringUTF(url.c_str());
{ jboolean result = env->CallBooleanMethod(clazz, openURL, jstringURL);
env->ExceptionClear();
openURL = env->GetStaticMethodID(activity, "openURL", "(Ljava/lang/String;)Z");
}
jstring url_jstring = (jstring) env->NewStringUTF(url.c_str()); env->DeleteLocalRef(jstringURL);
env->DeleteLocalRef(clazz);
jboolean result = env->CallStaticBooleanMethod(activity, openURL, url_jstring);
env->DeleteLocalRef(url_jstring);
env->DeleteLocalRef(activity); env->DeleteLocalRef(activity);
return result; return (bool) result;
} }
void vibrate(double seconds) void vibrate(double seconds)
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jclass activity = env->FindClass("org/love2d/android/GameActivity"); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
jmethodID vibrate_method = env->GetStaticMethodID(activity, "vibrate", "(D)V"); static jmethodID vibrateMethod = env->GetMethodID(clazz, "vibrate", "(D)V");
env->CallStaticVoidMethod(activity, vibrate_method, seconds); env->CallVoidMethod(activity, vibrateMethod, seconds);
env->DeleteLocalRef(clazz);
env->DeleteLocalRef(activity); env->DeleteLocalRef(activity);
} }
@@ -192,40 +158,9 @@ void freeGameArchiveMemory(void *ptr)
delete[] game_love_data; delete[] game_love_data;
} }
bool loadGameArchiveToMemory(const char* filename, char **ptr, size_t *size)
{
SDL_RWops *asset_game_file = SDL_RWFromFile(filename, "rb");
if (!asset_game_file) {
SDL_Log("Could not find %s", filename);
return false;
}
Sint64 file_size = asset_game_file->size(asset_game_file);
if (file_size <= 0) {
SDL_Log("Could not load game from %s. File has invalid file size: %d.", filename, (int) file_size);
return false;
}
*ptr = new char[file_size];
if (!*ptr) {
SDL_Log("Could not allocate memory for in-memory game archive");
return false;
}
size_t bytes_copied = asset_game_file->read(asset_game_file, (void*) *ptr, sizeof(char), (size_t) file_size);
if (bytes_copied != file_size) {
SDL_Log("Incomplete copy of in-memory game archive!");
delete[] *ptr;
return false;
}
*size = (size_t) file_size;
return true;
}
bool directoryExists(const char *path) bool directoryExists(const char *path)
{ {
struct stat s; struct stat s {};
int err = stat(path, &s); int err = stat(path, &s);
if (err == -1) if (err == -1)
{ {
@@ -284,9 +219,9 @@ bool hasRecordingPermission()
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity(); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
jclass clazz(env->GetObjectClass(activity)); static jmethodID methodID = env->GetMethodID(clazz, "hasRecordAudioPermission", "()Z");
jmethodID methodID = env->GetMethodID(clazz, "hasRecordAudioPermission", "()Z");
jboolean result = false; jboolean result = false;
if (methodID == nullptr) if (methodID == nullptr)
@@ -736,21 +671,11 @@ void deinitializeVirtualArchive()
bool checkFusedGame(void **physfsIO_Out) bool checkFusedGame(void **physfsIO_Out)
{ {
// TODO: Reorder the loading in 12.0
PHYSFS_Io *&io = *(PHYSFS_Io **) physfsIO_Out; PHYSFS_Io *&io = *(PHYSFS_Io **) physfsIO_Out;
AAssetManager *assetManager = getAssetManager(); AAssetManager *assetManager = getAssetManager();
// Prefer game.love inside assets/ folder // Prefer main.lua inside assets/ folder
AAsset *asset = AAssetManager_open(assetManager, "game.love", AASSET_MODE_RANDOM); AAsset *asset = AAssetManager_open(assetManager, "main.lua", AASSET_MODE_STREAMING);
if (asset)
{
io = aasset::AssetInfo::fromAAsset(assetManager, "game.love", asset);
return true;
}
// If there's no game.love inside assets/ try main.lua
asset = AAssetManager_open(assetManager, "main.lua", AASSET_MODE_STREAMING);
if (asset) if (asset)
{ {
AAsset_close(asset); AAsset_close(asset);
@@ -758,6 +683,14 @@ bool checkFusedGame(void **physfsIO_Out)
return true; return true;
} }
// If there's no main.lua inside assets/ try game.love
asset = AAssetManager_open(assetManager, "game.love", AASSET_MODE_RANDOM);
if (asset)
{
io = aasset::AssetInfo::fromAAsset(assetManager, "game.love", asset);
return true;
}
// Not found // Not found
return false; return false;
} }
@@ -765,43 +698,171 @@ bool checkFusedGame(void **physfsIO_Out)
const char *getCRequirePath() const char *getCRequirePath()
{ {
static bool initialized = false; static bool initialized = false;
static const char *path = nullptr; static std::string path;
if (!initialized) if (!initialized)
{ {
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity(); jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
jclass clazz(env->GetObjectClass(activity)); static jmethodID getCRequireMethod = env->GetMethodID(clazz, "getCRequirePath", "()Ljava/lang/String;");
jmethodID method_id = env->GetMethodID(clazz, "getCRequirePath", "()Ljava/lang/String;");
path = ""; jstring cpath = (jstring) env->CallObjectMethod(activity, getCRequireMethod);
initialized = true; const char *utf = env->GetStringUTFChars(cpath, nullptr);
if (utf)
if (method_id)
{ {
jstring cpath = (jstring) env->CallObjectMethod(activity, method_id); path = utf;
const char *utf = env->GetStringUTFChars(cpath, nullptr); env->ReleaseStringUTFChars(cpath, utf);
if (utf)
{
path = SDL_strdup(utf);
env->ReleaseStringUTFChars(cpath, utf);
}
env->DeleteLocalRef(cpath);
}
else
{
// NoSuchMethodException is thrown in case methodID is null
env->ExceptionClear();
return "";
} }
env->DeleteLocalRef(cpath);
env->DeleteLocalRef(activity); env->DeleteLocalRef(activity);
env->DeleteLocalRef(clazz); env->DeleteLocalRef(clazz);
} }
return path; return path.c_str();
}
int getFDFromContentProtocol(const char *path)
{
int fd = -1;
if (strstr(path, "content://") == path)
{
JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv();
jobject activity = (jobject) SDL_AndroidGetActivity();
jclass clazz = env->GetObjectClass(activity);
static jmethodID converter = env->GetMethodID(clazz, "convertToFileDescriptor", "(Ljava/lang/String;)I");
jstring uri = env->NewStringUTF(path);
fd = (int) env->CallIntMethod(activity, converter, uri);
env->DeleteLocalRef(uri);
env->DeleteLocalRef(clazz);
env->DeleteLocalRef(activity);
}
return fd;
}
int getFDFromLoveProtocol(const char *path)
{
constexpr const char PROTOCOL[] = "love2d://fd/";
constexpr size_t PROTOCOL_LEN = sizeof(PROTOCOL) - 1;
if (*path == '/')
path++;
if (memcmp(path, PROTOCOL, PROTOCOL_LEN) == 0)
{
try
{
return std::stoi(path + PROTOCOL_LEN, nullptr, 10);
}
catch (std::logic_error &)
{ }
}
return -1;
}
class FileDescriptorTracker: public love::Object
{
public:
explicit FileDescriptorTracker(int fd): Object(), fd(fd) {}
~FileDescriptorTracker() override { close(fd); }
int getFd() const { return fd; }
private:
int fd;
};
struct FileDescriptorIO
{
FileDescriptorTracker *fd;
off64_t size;
off64_t offset;
};
void *getIOFromFD(int fd)
{
if (fd == -1)
return nullptr;
// Create file descriptor IO structure
FileDescriptorIO *fdio = new FileDescriptorIO();
fdio->size = lseek64(fd, 0, SEEK_END);
fdio->offset = 0;
lseek64(fd, 0, SEEK_SET);
if (fdio->size == -1)
{
// Cannot get size
delete fdio;
return nullptr;
}
fdio->fd = new FileDescriptorTracker(fd);
PHYSFS_Io *io = new PHYSFS_Io();
io->version = 0;
io->opaque = fdio;
io->read = [](PHYSFS_Io *io, void *buf, PHYSFS_uint64 size)
{
FileDescriptorIO *fdio = (FileDescriptorIO *) io->opaque;
ssize_t ret = pread64(fdio->fd->getFd(), buf, (size_t) size, fdio->offset);
if (ret == -1)
PHYSFS_setErrorCode(PHYSFS_ERR_OTHER_ERROR);
else
fdio->offset = std::min(fdio->offset + (off64_t) ret, fdio->size);
return (PHYSFS_sint64) ret;
};
io->write = nullptr;
io->seek = [](PHYSFS_Io *io, PHYSFS_uint64 offset)
{
FileDescriptorIO *fdio = (FileDescriptorIO *) io->opaque;
fdio->offset = std::min(std::max<off64_t>((off64_t) offset, 0), fdio->size);
// Always success
return 1;
};
io->tell = [](PHYSFS_Io *io)
{
FileDescriptorIO *fdio = (FileDescriptorIO *) io->opaque;
return (PHYSFS_sint64) fdio->offset;
};
io->length = [](PHYSFS_Io *io)
{
FileDescriptorIO *fdio = (FileDescriptorIO *) io->opaque;
return (PHYSFS_sint64) fdio->size;
};
io->duplicate = [](PHYSFS_Io *io)
{
FileDescriptorIO *fdio = (FileDescriptorIO *) io->opaque;
FileDescriptorIO *fdio2 = new FileDescriptorIO();
PHYSFS_Io *io2 = new PHYSFS_Io();
fdio->fd->retain();
// Copy data
*fdio2 = *fdio;
*io2 = *io;
io2->opaque = fdio2;
return io2;
};
io->flush = nullptr;
io->destroy = [](PHYSFS_Io *io)
{
FileDescriptorIO *fdio = (FileDescriptorIO *) io->opaque;
fdio->fd->release();
delete fdio;
delete io;
};
return io;
} }
const char *getArg0() const char *getArg0()
+21 -7
View File
@@ -50,11 +50,6 @@ double getScreenScale();
**/ **/
bool getSafeArea(int &top, int &left, int &bottom, int &right); bool getSafeArea(int &top, int &left, int &bottom, int &right);
/**
* Gets the selected love file in the device filesystem.
**/
const char *getSelectedGameFile();
bool openURL(const std::string &url); bool openURL(const std::string &url);
void vibrate(double seconds); void vibrate(double seconds);
@@ -64,8 +59,6 @@ void vibrate(double seconds);
*/ */
void freeGameArchiveMemory(void *ptr); void freeGameArchiveMemory(void *ptr);
bool loadGameArchiveToMemory(const char *filename, char **ptr, size_t *size);
bool directoryExists(const char *path); bool directoryExists(const char *path);
bool mkdir(const char *path); bool mkdir(const char *path);
@@ -103,6 +96,27 @@ bool checkFusedGame(void **physfsIO_Out);
const char *getCRequirePath(); const char *getCRequirePath();
/**
* Convert "content://" to file descriptor.
* @param path Path with content:// URI
* @return File descriptor if successful, -1 on failure.
*/
int getFDFromContentProtocol(const char *path);
/**
* Attempt to parse "(/)love2d://fd/<fd>" from path.
* @param path Potentially special path.
* @return File descriptor passed if successful, -1 if path is not valid.
*/
int getFDFromLoveProtocol(const char *path);
/**
* Create PHYSFS_Io from file descriptor.
* @param fd File descriptor
* @return PHYSFS_Io casted to void*.
*/
void *getIOFromFD(int fd);
/** /**
* Retrieve PHYSFS_AndroidInit structure. * Retrieve PHYSFS_AndroidInit structure.
* @return Pointer to PHYSFS_AndroidInit structure, casted to pointer of char. * @return Pointer to PHYSFS_AndroidInit structure, casted to pointer of char.
+50
View File
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2006-2023 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.
**/
#pragma once
#include "config.h"
#if defined(LOVE_IOS) || defined(LOVE_MACOS)
#include <string>
namespace love
{
namespace apple
{
enum UserDirectory
{
USER_DIRECTORY_HOME,
USER_DIRECTORY_APPSUPPORT,
USER_DIRECTORY_DOCUMENTS,
USER_DIRECTORY_DESKTOP,
USER_DIRECTORY_CACHES,
USER_DIRECTORY_TEMP,
};
std::string getUserDirectory(UserDirectory dir);
std::string getExecutablePath();
} // apple
} // love
#endif // defined(LOVE_IOS) || defined(LOVE_MACOS)
+79
View File
@@ -0,0 +1,79 @@
/**
* Copyright (c) 2006-2023 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.
**/
#include "apple.h"
#if defined(LOVE_IOS) || defined(LOVE_MACOS)
#import <Foundation/Foundation.h>
namespace love
{
namespace apple
{
std::string getUserDirectory(UserDirectory dir)
{
std::string path;
NSSearchPathDirectory nsdir = NSTrashDirectory;
@autoreleasepool
{
switch (dir)
{
case USER_DIRECTORY_HOME:
return NSHomeDirectory().UTF8String;
case USER_DIRECTORY_APPSUPPORT:
nsdir = NSApplicationSupportDirectory;
break;
case USER_DIRECTORY_DOCUMENTS:
nsdir = NSDocumentDirectory;
break;
case USER_DIRECTORY_DESKTOP:
nsdir = NSDesktopDirectory;
break;
case USER_DIRECTORY_CACHES:
nsdir = NSCachesDirectory;
break;
case USER_DIRECTORY_TEMP:
nsdir = NSItemReplacementDirectory;
break;
}
NSArray<NSURL *> *dirs = [[NSFileManager defaultManager] URLsForDirectory:nsdir inDomains:NSUserDomainMask];
if (dirs.count > 0)
path = [dirs[0].path UTF8String];
}
return path;
}
std::string getExecutablePath()
{
@autoreleasepool
{
return std::string([NSBundle mainBundle].executablePath.UTF8String);
}
}
} // apple
} // love
#endif // defined(LOVE_IOS) || defined(LOVE_MACOS)
+20 -12
View File
@@ -24,14 +24,10 @@
// Platform stuff. // Platform stuff.
#if defined(WIN32) || defined(_WIN32) #if defined(WIN32) || defined(_WIN32)
# define LOVE_WINDOWS 1 # define LOVE_WINDOWS 1
// If _USING_V110_SDK71_ is defined it means we are using the xp toolset. # include <winapifamily.h>
# if defined(_MSC_VER) && (_MSC_VER >= 1700) && !_USING_V110_SDK71_ # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# include <winapifamily.h> # define LOVE_WINDOWS_UWP 1
# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # define LOVE_NO_MODPLUG 1
# define LOVE_WINDOWS_UWP 1
# define LOVE_NO_MODPLUG 1
# define LOVE_NOMPG123 1
# endif
# endif # endif
#endif #endif
#if defined(linux) || defined(__linux) || defined(__linux__) #if defined(linux) || defined(__linux) || defined(__linux__)
@@ -39,13 +35,15 @@
#endif #endif
#if defined(__ANDROID__) #if defined(__ANDROID__)
# define LOVE_ANDROID 1 # define LOVE_ANDROID 1
// Needed for ENet
# define HAS_SOCKLEN_T 1
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
# include <TargetConditionals.h> # include <TargetConditionals.h>
# if TARGET_OS_IPHONE # if TARGET_OS_IPHONE
# define LOVE_IOS 1 # define LOVE_IOS 1
# elif TARGET_OS_MAC # elif TARGET_OS_MAC
# define LOVE_MACOSX 1 # define LOVE_MACOS 1
# endif # endif
#endif #endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
@@ -72,7 +70,7 @@
#endif #endif
// NEON instructions. // NEON instructions.
#if defined(__ARM_NEON) #if defined(__ARM_NEON) || defined(_M_ARM64)
# define LOVE_SIMD_NEON # define LOVE_SIMD_NEON
#endif #endif
@@ -119,7 +117,7 @@
# define NOMINMAX # define NOMINMAX
#endif #endif
#if defined(LOVE_MACOSX) || defined(LOVE_IOS) #if defined(LOVE_MACOS) || defined(LOVE_IOS)
# define LOVE_LEGENDARY_APP_ARGV_HACK # define LOVE_LEGENDARY_APP_ARGV_HACK
#endif #endif
@@ -127,6 +125,14 @@
# define LOVE_LEGENDARY_ACCELEROMETER_AS_JOYSTICK_HACK # define LOVE_LEGENDARY_ACCELEROMETER_AS_JOYSTICK_HACK
#endif #endif
#if defined(LOVE_WINDOWS) || defined(LOVE_LINUX) || defined(LOVE_ANDROID)
# define LOVE_GRAPHICS_VULKAN
#endif
#if defined(LOVE_MACOS) || defined(LOVE_IOS)
# define LOVE_GRAPHICS_METAL
#endif
// Autotools config.h // Autotools config.h
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <../config.h> # include <../config.h>
@@ -152,6 +158,7 @@
# define LOVE_ENABLE_MATH # define LOVE_ENABLE_MATH
# define LOVE_ENABLE_MOUSE # define LOVE_ENABLE_MOUSE
# define LOVE_ENABLE_PHYSICS # define LOVE_ENABLE_PHYSICS
# define LOVE_ENABLE_SENSOR
# define LOVE_ENABLE_SOUND # define LOVE_ENABLE_SOUND
# define LOVE_ENABLE_SYSTEM # define LOVE_ENABLE_SYSTEM
# define LOVE_ENABLE_THREAD # define LOVE_ENABLE_THREAD
@@ -163,10 +170,11 @@
# define LOVE_ENABLE_ENET # define LOVE_ENABLE_ENET
# define LOVE_ENABLE_LUASOCKET # define LOVE_ENABLE_LUASOCKET
# define LOVE_ENABLE_LUA53 # define LOVE_ENABLE_LUA53
# define LOVE_ENABLE_LUAHTTPS
#endif #endif
// Check we have a sane configuration // Check we have a sane configuration
#if !defined(LOVE_WINDOWS) && !defined(LOVE_LINUX) && !defined(LOVE_IOS) && !defined(LOVE_MACOSX) && !defined(LOVE_ANDROID) #if !defined(LOVE_WINDOWS) && !defined(LOVE_LINUX) && !defined(LOVE_IOS) && !defined(LOVE_MACOS) && !defined(LOVE_ANDROID)
# error Could not detect target platform # error Could not detect target platform
#endif #endif
#if !defined(LOVE_LITTLE_ENDIAN) && !defined(LOVE_BIG_ENDIAN) #if !defined(LOVE_LITTLE_ENDIAN) && !defined(LOVE_BIG_ENDIAN)
+33 -13
View File
@@ -24,6 +24,7 @@
#include <atomic> #include <atomic>
#include <map> #include <map>
#include <sstream>
namespace love namespace love
{ {
@@ -97,32 +98,32 @@ bool isDeprecationOutputEnabled()
std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere) std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere)
{ {
std::string notice; std::stringstream notice;
if (usewhere) if (usewhere)
notice += info.where; notice << info.where;
notice += "Using deprecated "; notice << "Using deprecated ";
if (info.apiType == API_FUNCTION) if (info.apiType == API_FUNCTION)
notice += "function "; notice << "function ";
else if (info.apiType == API_METHOD) else if (info.apiType == API_METHOD)
notice += "method "; notice << "method ";
else if (info.apiType == API_CALLBACK)
notice << "callback ";
else if (info.apiType == API_FIELD) else if (info.apiType == API_FIELD)
notice += "field "; notice << "field ";
else if (info.apiType == API_CONSTANT) else if (info.apiType == API_CONSTANT)
notice += "constant "; notice << "constant ";
else
notice += "API ";
notice += info.name; notice << info.name;
if (info.type == DEPRECATED_REPLACED && !info.replacement.empty()) if (info.type == DEPRECATED_REPLACED && !info.replacement.empty())
notice += " (replaced by " + info.replacement + ")"; notice << " (replaced by " << info.replacement << ")";
else if (info.type == DEPRECATED_RENAMED && !info.replacement.empty()) else if (info.type == DEPRECATED_RENAMED && !info.replacement.empty())
notice += " (renamed to " + info.replacement + ")"; notice << " (renamed to " << info.replacement << ")";
return notice; return notice.str();
} }
GetDeprecated::GetDeprecated() GetDeprecated::GetDeprecated()
@@ -184,4 +185,23 @@ MarkDeprecated::~MarkDeprecated()
mutex->unlock(); mutex->unlock();
} }
STRINGMAP_BEGIN(APIType, API_MAX_ENUM, apiType)
{
{ "function", API_FUNCTION },
{ "method", API_METHOD },
{ "callback", API_CALLBACK },
{ "field", API_FIELD },
{ "constant", API_CONSTANT },
{ "custom", API_CUSTOM },
}
STRINGMAP_END(APIType, API_MAX_ENUM, apiType)
STRINGMAP_BEGIN(DeprecationType, DEPRECATED_MAX_ENUM, deprecationType)
{
{ "noreplacement", DEPRECATED_NO_REPLACEMENT },
{ "replaced", DEPRECATED_REPLACED },
{ "renamed", DEPRECATED_RENAMED },
}
STRINGMAP_END(DeprecationType, DEPRECATED_MAX_ENUM, deprecationType)
} // love } // love
+8
View File
@@ -21,6 +21,7 @@
#pragma once #pragma once
#include "int.h" #include "int.h"
#include "StringMap.h"
#include <string> #include <string>
#include <vector> #include <vector>
@@ -32,8 +33,11 @@ enum APIType
{ {
API_FUNCTION, API_FUNCTION,
API_METHOD, API_METHOD,
API_CALLBACK,
API_FIELD, API_FIELD,
API_CONSTANT, API_CONSTANT,
API_CUSTOM,
API_MAX_ENUM
}; };
enum DeprecationType enum DeprecationType
@@ -41,6 +45,7 @@ enum DeprecationType
DEPRECATED_NO_REPLACEMENT, DEPRECATED_NO_REPLACEMENT,
DEPRECATED_REPLACED, DEPRECATED_REPLACED,
DEPRECATED_RENAMED, DEPRECATED_RENAMED,
DEPRECATED_MAX_ENUM
}; };
struct DeprecationInfo struct DeprecationInfo
@@ -78,4 +83,7 @@ struct MarkDeprecated
DeprecationInfo *info; DeprecationInfo *info;
}; };
STRINGMAP_DECLARE(APIType);
STRINGMAP_DECLARE(DeprecationType);
} // love } // love
-15
View File
@@ -42,27 +42,12 @@ namespace ios
**/ **/
std::string getLoveInResources(bool &fused); std::string getLoveInResources(bool &fused);
/**
* Gets the directory path where files should be stored.
**/
std::string getAppdataDirectory();
/**
* Get the home directory (on iOS, this really means the app's sandbox dir.)
**/
std::string getHomeDirectory();
/** /**
* Opens the specified URL with the default program associated with the URL's * Opens the specified URL with the default program associated with the URL's
* scheme. * scheme.
**/ **/
bool openURL(const std::string &url); bool openURL(const std::string &url);
/**
* Returns the full path to the executable.
**/
std::string getExecutablePath();
/** /**
* Causes devices with vibration support to vibrate for about 0.5 seconds. * Causes devices with vibration support to vibrate for about 0.5 seconds.
**/ **/
+12 -47
View File
@@ -19,6 +19,9 @@
**/ **/
#include "ios.h" #include "ios.h"
#include "apple.h"
using namespace love::apple;
#ifdef LOVE_IOS #ifdef LOVE_IOS
@@ -127,18 +130,14 @@ static bool deleteFileInDocuments(NSString *filename);
@end @end
static NSString *getDocumentsDirectory()
{
NSArray *docdirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return docdirs[0];
}
static NSArray *getLovesInDocuments() static NSArray *getLovesInDocuments()
{ {
std::string docdir = getUserDirectory(USER_DIRECTORY_DOCUMENTS);
NSMutableArray *paths = [NSMutableArray new]; NSMutableArray *paths = [NSMutableArray new];
NSFileManager *manager = [NSFileManager defaultManager]; NSFileManager *manager = [NSFileManager defaultManager];
NSDirectoryEnumerator *enumerator = [manager enumeratorAtPath:getDocumentsDirectory()]; NSDirectoryEnumerator *enumerator = [manager enumeratorAtPath:@(docdir.c_str())];
NSString *path = nil; NSString *path = nil;
while ((path = [enumerator nextObject])) while ((path = [enumerator nextObject]))
@@ -155,9 +154,9 @@ static NSArray *getLovesInDocuments()
static bool deleteFileInDocuments(NSString *filename) static bool deleteFileInDocuments(NSString *filename)
{ {
NSString *documents = getDocumentsDirectory(); std::string docdir = getUserDirectory(USER_DIRECTORY_DOCUMENTS);
NSString *file = [documents stringByAppendingPathComponent:filename]; NSString *file = [@(docdir.c_str()) stringByAppendingPathComponent:filename];
bool success = [[NSFileManager defaultManager] removeItemAtPath:file error:nil]; bool success = [[NSFileManager defaultManager] removeItemAtPath:file error:nil];
if (success) if (success)
@@ -178,7 +177,8 @@ static int dropFileEventFilter(void *userdata, SDL_Event *event)
if ([fmanager fileExistsAtPath:fname] && [fname.pathExtension isEqual:@"love"]) if ([fmanager fileExistsAtPath:fname] && [fname.pathExtension isEqual:@"love"])
{ {
NSString *documents = getDocumentsDirectory(); std::string docdir = getUserDirectory(USER_DIRECTORY_DOCUMENTS);
NSString *documents = @(docdir.c_str());
documents = documents.stringByStandardizingPath.stringByResolvingSymlinksInPath; documents = documents.stringByStandardizingPath.stringByResolvingSymlinksInPath;
fname = fname.stringByStandardizingPath.stringByResolvingSymlinksInPath; fname = fname.stringByStandardizingPath.stringByResolvingSymlinksInPath;
@@ -331,7 +331,8 @@ std::string getLoveInResources(bool &fused)
// The string length might be 0 if the no-game screen was selected. // The string length might be 0 if the no-game screen was selected.
if (selectedfile != nil && selectedfile.length > 0) if (selectedfile != nil && selectedfile.length > 0)
{ {
NSString *documents = getDocumentsDirectory(); std::string docdir = getUserDirectory(USER_DIRECTORY_DOCUMENTS);
NSString *documents = @(docdir.c_str());
path = [documents stringByAppendingPathComponent:selectedfile].UTF8String; path = [documents stringByAppendingPathComponent:selectedfile].UTF8String;
} }
} }
@@ -339,34 +340,6 @@ std::string getLoveInResources(bool &fused)
return path; return path;
} }
std::string getAppdataDirectory()
{
NSSearchPathDirectory searchdir = NSApplicationSupportDirectory;
std::string path;
@autoreleasepool
{
NSArray *dirs = NSSearchPathForDirectoriesInDomains(searchdir, NSUserDomainMask, YES);
if (dirs.count > 0)
path = [dirs[0] UTF8String];
}
return path;
}
std::string getHomeDirectory()
{
std::string path;
@autoreleasepool
{
path = [NSHomeDirectory() UTF8String];
}
return path;
}
bool openURL(const std::string &url) bool openURL(const std::string &url)
{ {
bool success = false; bool success = false;
@@ -383,14 +356,6 @@ bool openURL(const std::string &url)
return success; return success;
} }
std::string getExecutablePath()
{
@autoreleasepool
{
return std::string([NSBundle mainBundle].executablePath.UTF8String);
}
}
void vibrate() void vibrate()
{ {
@autoreleasepool @autoreleasepool
+11 -13
View File
@@ -18,12 +18,11 @@
* 3. This notice may not be removed or altered from any source distribution. * 3. This notice may not be removed or altered from any source distribution.
**/ **/
#ifndef LOVE_OSX_H #pragma once
#define LOVE_OSX_H
#include "config.h" #include "config.h"
#ifdef LOVE_MACOSX #ifdef LOVE_MACOS
#include <string> #include <string>
@@ -31,7 +30,7 @@ typedef struct SDL_Window SDL_Window;
namespace love namespace love
{ {
namespace macosx namespace macos
{ {
/** /**
@@ -47,25 +46,24 @@ LOVE_EXPORT std::string getLoveInResources();
**/ **/
LOVE_EXPORT std::string checkDropEvents(); LOVE_EXPORT std::string checkDropEvents();
/**
* Returns the full path to the executable.
**/
std::string getExecutablePath();
/** /**
* Bounce the dock icon, if the app isn't in the foreground. * Bounce the dock icon, if the app isn't in the foreground.
**/ **/
void requestAttention(bool continuous); void requestAttention(bool continuous);
/**
* Sets whether vsync is enabled for the given CAMetalLayer
**/
void setMetalLayerVSync(void *metallayer, bool vsync);
bool getMetalLayerVSync(void *metallayer);
/** /**
* Explicitly sets the window's color space to be sRGB - which stops the OS * Explicitly sets the window's color space to be sRGB - which stops the OS
* from interpreting the backbuffer output as P3 on P3-capable displays. * from interpreting the backbuffer output as P3 on P3-capable displays.
**/ **/
void setWindowSRGBColorSpace(SDL_Window *window); void setWindowSRGBColorSpace(SDL_Window *window);
} // macosx } // macos
} // love } // love
#endif // LOVE_MACOSX #endif // LOVE_MACOS
#endif // LOVE_OSX_H
+32 -13
View File
@@ -18,12 +18,13 @@
* 3. This notice may not be removed or altered from any source distribution. * 3. This notice may not be removed or altered from any source distribution.
**/ **/
#include "macosx.h" #include "macos.h"
#ifdef LOVE_MACOSX #ifdef LOVE_MACOS
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import <QuartzCore/CAMetalLayer.h>
#ifdef LOVE_MACOSX_SDL_DIRECT_INCLUDE #ifdef LOVE_MACOSX_SDL_DIRECT_INCLUDE
#include <SDL.h> #include <SDL.h>
@@ -35,7 +36,7 @@
namespace love namespace love
{ {
namespace macosx namespace macos
{ {
std::string getLoveInResources() std::string getLoveInResources()
@@ -76,14 +77,6 @@ std::string checkDropEvents()
return dropstr; return dropstr;
} }
std::string getExecutablePath()
{
@autoreleasepool
{
return std::string([NSBundle mainBundle].executablePath.UTF8String);
}
}
void requestAttention(bool continuous) void requestAttention(bool continuous)
{ {
@autoreleasepool @autoreleasepool
@@ -95,6 +88,32 @@ void requestAttention(bool continuous)
} }
} }
void setMetalLayerVSync(void *metallayer, bool vsync)
{
@autoreleasepool
{
if (@available(macOS 10.13, *))
{
CAMetalLayer *layer = (__bridge CAMetalLayer *) metallayer;
layer.displaySyncEnabled = vsync;
}
}
}
bool getMetalLayerVSync(void *metallayer)
{
@autoreleasepool
{
if (@available(macOS 10.13, *))
{
CAMetalLayer *layer = (__bridge CAMetalLayer *) metallayer;
return layer.displaySyncEnabled;
}
}
return true;
}
void setWindowSRGBColorSpace(SDL_Window *window) void setWindowSRGBColorSpace(SDL_Window *window)
{ {
@autoreleasepool @autoreleasepool
@@ -110,7 +129,7 @@ void setWindowSRGBColorSpace(SDL_Window *window)
} }
} }
} // osx } // macos
} // love } // love
#endif // LOVE_MACOSX #endif // LOVE_MACOS
+253 -120
View File
@@ -24,6 +24,107 @@
namespace love namespace love
{ {
static PixelFormatInfo formatInfo[] =
{
// components, blockW, blockH, blockSize, color, depth, stencil, compressed, dataType
{ 0, 1, 1, 0, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_UNKNOWN
{ 0, 1, 1, 0, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_NORMAL
{ 0, 1, 1, 0, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_HDR
{ 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R8_UNORM
{ 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R8_INT
{ 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R8_UINT
{ 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R16_UNORM
{ 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R16_FLOAT
{ 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R16_INT
{ 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R16_UINT
{ 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R32_FLOAT
{ 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R32_INT
{ 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R32_UINT
{ 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG8_UNORM
{ 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG8_INT
{ 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG8_UINT
{ 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_LA8_UNORM
{ 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG16_UNORM
{ 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG16_FLOAT
{ 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG16_INT
{ 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG16_UINT
{ 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG32_FLOAT
{ 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG32_INT
{ 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG32_UINT
{ 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM
{ 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM_sRGB
{ 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM
{ 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM_sRGB
{ 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA8_INT
{ 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA8_UINT
{ 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA16_UNORM
{ 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA16_FLOAT
{ 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA16_INT
{ 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA16_UINT
{ 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA32_FLOAT
{ 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA32_INT
{ 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA32_UINT
{ 4, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA4_UNORM
{ 4, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB5A1_UNORM
{ 3, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB565_UNORM
{ 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB10A2_UNORM
{ 3, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_RG11B10_FLOAT
{ 1, 1, 1, 1, false, false, true , false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_STENCIL8
{ 1, 1, 1, 2, false, true, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH16_UNORM
{ 1, 1, 1, 3, false, true, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM
{ 1, 1, 1, 4, false, true, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT
{ 2, 1, 1, 4, false, true, true , false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM_STENCIL8
{ 2, 1, 1, 5, false, true, true , false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT_STENCIL8
{ 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT1_UNORM
{ 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT3_UNORM
{ 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT5_UNORM
{ 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC4_UNORM
{ 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC4_SNORM
{ 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC5_UNORM
{ 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC5_SNORM
{ 3, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_BC6H_UFLOAT
{ 3, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_BC6H_FLOAT
{ 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC7_UNORM
{ 3, 16, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB2_UNORM
{ 3, 8, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB4_UNORM
{ 4, 16, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA2_UNORM
{ 4, 8, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA4_UNORM
{ 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC1_UNORM
{ 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGB_UNORM
{ 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA_UNORM
{ 4, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA1_UNORM
{ 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_R_UNORM
{ 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_R_SNORM
{ 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_RG_UNORM
{ 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_RG_SNORM
{ 4, 4, 4, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_4x4
{ 4, 5, 4, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x4
{ 4, 5, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x5
{ 4, 6, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x5
{ 4, 6, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x6
{ 4, 8, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x5
{ 4, 8, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x6
{ 4, 8, 8, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x8
{ 4, 8, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x5
{ 4, 10, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x6
{ 4, 10, 8, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x8
{ 4, 10, 10, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x10
{ 4, 12, 10, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x10
{ 4, 12, 12, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x12
};
static_assert(sizeof(formatInfo) / sizeof(PixelFormatInfo) == PIXELFORMAT_MAX_ENUM, "Update the formatInfo array when adding or removing a PixelFormat");
static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM>::Entry formatEntries[] = static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM>::Entry formatEntries[] =
{ {
{ "unknown", PIXELFORMAT_UNKNOWN }, { "unknown", PIXELFORMAT_UNKNOWN },
@@ -31,57 +132,79 @@ static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM>::Entry formatEntries[] =
{ "normal", PIXELFORMAT_NORMAL }, { "normal", PIXELFORMAT_NORMAL },
{ "hdr", PIXELFORMAT_HDR }, { "hdr", PIXELFORMAT_HDR },
{ "r8", PIXELFORMAT_R8 }, { "r8", PIXELFORMAT_R8_UNORM },
{ "rg8", PIXELFORMAT_RG8 }, { "r8i", PIXELFORMAT_R8_INT },
{ "rgba8", PIXELFORMAT_RGBA8 }, { "r8ui", PIXELFORMAT_R8_UINT },
{ "srgba8", PIXELFORMAT_sRGBA8 }, { "r16", PIXELFORMAT_R16_UNORM },
{ "r16", PIXELFORMAT_R16 }, { "r16f", PIXELFORMAT_R16_FLOAT },
{ "rg16", PIXELFORMAT_RG16 }, { "r16i", PIXELFORMAT_R16_INT },
{ "rgba16", PIXELFORMAT_RGBA16 }, { "r16ui", PIXELFORMAT_R16_UINT },
{ "r16f", PIXELFORMAT_R16F }, { "r32f", PIXELFORMAT_R32_FLOAT },
{ "rg16f", PIXELFORMAT_RG16F }, { "r32i", PIXELFORMAT_R32_INT },
{ "rgba16f", PIXELFORMAT_RGBA16F }, { "r32ui", PIXELFORMAT_R32_UINT },
{ "r32f", PIXELFORMAT_R32F },
{ "rg32f", PIXELFORMAT_RG32F },
{ "rgba32f", PIXELFORMAT_RGBA32F },
{ "la8", PIXELFORMAT_LA8 }, { "rg8", PIXELFORMAT_RG8_UNORM },
{ "rg8i", PIXELFORMAT_RG8_INT },
{ "rg8ui", PIXELFORMAT_RG8_UINT },
{ "la8", PIXELFORMAT_LA8_UNORM },
{ "rg16", PIXELFORMAT_RG16_UNORM },
{ "rg16f", PIXELFORMAT_RG16_FLOAT },
{ "rg16i", PIXELFORMAT_RG16_INT },
{ "rg16ui", PIXELFORMAT_RG16_UINT },
{ "rg32f", PIXELFORMAT_RG32_FLOAT },
{ "rg32i", PIXELFORMAT_RG32_INT },
{ "rg32ui", PIXELFORMAT_RG32_UINT },
{ "rgba4", PIXELFORMAT_RGBA4 }, { "rgba8", PIXELFORMAT_RGBA8_UNORM },
{ "rgb5a1", PIXELFORMAT_RGB5A1 }, { "srgba8", PIXELFORMAT_RGBA8_UNORM_sRGB },
{ "rgb565", PIXELFORMAT_RGB565 }, { "bgra8", PIXELFORMAT_BGRA8_UNORM },
{ "rgb10a2", PIXELFORMAT_RGB10A2 }, { "bgra8srgb", PIXELFORMAT_BGRA8_UNORM_sRGB },
{ "rg11b10f", PIXELFORMAT_RG11B10F }, { "rgba8i", PIXELFORMAT_RGBA8_INT },
{ "rgba8ui", PIXELFORMAT_RGBA8_UINT },
{ "rgba16", PIXELFORMAT_RGBA16_UNORM },
{ "rgba16f", PIXELFORMAT_RGBA16_FLOAT },
{ "rgba16i", PIXELFORMAT_RGBA16_INT },
{ "rgba16ui", PIXELFORMAT_RGBA16_UINT },
{ "rgba32f", PIXELFORMAT_RGBA32_FLOAT },
{ "rgba32i", PIXELFORMAT_RGBA32_INT },
{ "rgba32ui", PIXELFORMAT_RGBA32_UINT },
{ "stencil8", PIXELFORMAT_STENCIL8 }, { "rgba4", PIXELFORMAT_RGBA4_UNORM },
{ "depth16", PIXELFORMAT_DEPTH16 }, { "rgb5a1", PIXELFORMAT_RGB5A1_UNORM },
{ "depth24", PIXELFORMAT_DEPTH24 }, { "rgb565", PIXELFORMAT_RGB565_UNORM },
{ "depth32f", PIXELFORMAT_DEPTH32F }, { "rgb10a2", PIXELFORMAT_RGB10A2_UNORM },
{ "depth24stencil8", PIXELFORMAT_DEPTH24_STENCIL8 }, { "rg11b10f", PIXELFORMAT_RG11B10_FLOAT },
{ "depth32fstencil8", PIXELFORMAT_DEPTH32F_STENCIL8 },
{ "stencil8", PIXELFORMAT_STENCIL8 },
{ "depth16", PIXELFORMAT_DEPTH16_UNORM },
{ "depth24", PIXELFORMAT_DEPTH24_UNORM },
{ "depth32f", PIXELFORMAT_DEPTH32_FLOAT },
{ "depth24stencil8", PIXELFORMAT_DEPTH24_UNORM_STENCIL8 },
{ "depth32fstencil8", PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 },
{ "DXT1", PIXELFORMAT_DXT1_UNORM },
{ "DXT3", PIXELFORMAT_DXT3_UNORM },
{ "DXT5", PIXELFORMAT_DXT5_UNORM },
{ "BC4", PIXELFORMAT_BC4_UNORM },
{ "BC4s", PIXELFORMAT_BC4_SNORM },
{ "BC5", PIXELFORMAT_BC5_UNORM },
{ "BC5s", PIXELFORMAT_BC5_SNORM },
{ "BC6h", PIXELFORMAT_BC6H_UFLOAT },
{ "BC6hs", PIXELFORMAT_BC6H_FLOAT },
{ "BC7", PIXELFORMAT_BC7_UNORM },
{ "PVR1rgb2", PIXELFORMAT_PVR1_RGB2_UNORM },
{ "PVR1rgb4", PIXELFORMAT_PVR1_RGB4_UNORM },
{ "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2_UNORM },
{ "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4_UNORM },
{ "ETC1", PIXELFORMAT_ETC1_UNORM },
{ "ETC2rgb", PIXELFORMAT_ETC2_RGB_UNORM },
{ "ETC2rgba", PIXELFORMAT_ETC2_RGBA_UNORM },
{ "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1_UNORM },
{ "EACr", PIXELFORMAT_EAC_R_UNORM },
{ "EACrs", PIXELFORMAT_EAC_R_SNORM },
{ "EACrg", PIXELFORMAT_EAC_RG_UNORM },
{ "EACrgs", PIXELFORMAT_EAC_RG_SNORM },
{ "DXT1", PIXELFORMAT_DXT1 },
{ "DXT3", PIXELFORMAT_DXT3 },
{ "DXT5", PIXELFORMAT_DXT5 },
{ "BC4", PIXELFORMAT_BC4 },
{ "BC4s", PIXELFORMAT_BC4s },
{ "BC5", PIXELFORMAT_BC5 },
{ "BC5s", PIXELFORMAT_BC5s },
{ "BC6h", PIXELFORMAT_BC6H },
{ "BC6hs", PIXELFORMAT_BC6Hs },
{ "BC7", PIXELFORMAT_BC7 },
{ "PVR1rgb2", PIXELFORMAT_PVR1_RGB2 },
{ "PVR1rgb4", PIXELFORMAT_PVR1_RGB4 },
{ "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2 },
{ "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4 },
{ "ETC1", PIXELFORMAT_ETC1 },
{ "ETC2rgb", PIXELFORMAT_ETC2_RGB },
{ "ETC2rgba", PIXELFORMAT_ETC2_RGBA },
{ "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1 },
{ "EACr", PIXELFORMAT_EAC_R },
{ "EACrs", PIXELFORMAT_EAC_Rs },
{ "EACrg", PIXELFORMAT_EAC_RG },
{ "EACrgs", PIXELFORMAT_EAC_RGs },
{ "ASTC4x4", PIXELFORMAT_ASTC_4x4 }, { "ASTC4x4", PIXELFORMAT_ASTC_4x4 },
{ "ASTC5x4", PIXELFORMAT_ASTC_5x4 }, { "ASTC5x4", PIXELFORMAT_ASTC_5x4 },
{ "ASTC5x5", PIXELFORMAT_ASTC_5x5 }, { "ASTC5x5", PIXELFORMAT_ASTC_5x5 },
@@ -112,100 +235,110 @@ bool getConstant(PixelFormat in, const char *&out)
return formats.find(in, out); return formats.find(in, out);
} }
const PixelFormatInfo &getPixelFormatInfo(PixelFormat format)
{
return formatInfo[format];
}
const char *getPixelFormatName(PixelFormat format)
{
const char *name = "unknown";
getConstant(format, name);
return name;
}
bool isPixelFormatCompressed(PixelFormat format) bool isPixelFormatCompressed(PixelFormat format)
{ {
// I'm lazy return formatInfo[format].compressed;
int iformat = (int) format; }
return iformat >= (int) PIXELFORMAT_DXT1 && iformat < (int) PIXELFORMAT_MAX_ENUM;
bool isPixelFormatColor(PixelFormat format)
{
return formatInfo[format].color;
} }
bool isPixelFormatDepthStencil(PixelFormat format) bool isPixelFormatDepthStencil(PixelFormat format)
{ {
int iformat = (int) format; const PixelFormatInfo &info = formatInfo[format];
return iformat >= (int) PIXELFORMAT_STENCIL8 && iformat <= (int) PIXELFORMAT_DEPTH32F_STENCIL8; return info.depth || info.stencil;
} }
bool isPixelFormatDepth(PixelFormat format) bool isPixelFormatDepth(PixelFormat format)
{ {
int iformat = (int) format; return formatInfo[format].depth;
return iformat >= (int) PIXELFORMAT_DEPTH16 && iformat <= (int) PIXELFORMAT_DEPTH32F_STENCIL8;
} }
bool isPixelFormatStencil(PixelFormat format) bool isPixelFormatStencil(PixelFormat format)
{ {
return format == PIXELFORMAT_STENCIL8 || format == PIXELFORMAT_DEPTH24_STENCIL8 || format == PIXELFORMAT_DEPTH32F_STENCIL8; return formatInfo[format].stencil;
} }
size_t getPixelFormatSize(PixelFormat format) bool isPixelFormatSRGB(PixelFormat format)
{ {
switch (format) return format == PIXELFORMAT_RGBA8_UNORM_sRGB || format == PIXELFORMAT_BGRA8_UNORM_sRGB;
{ }
case PIXELFORMAT_R8:
case PIXELFORMAT_STENCIL8: bool isPixelFormatInteger(PixelFormat format)
return 1; {
case PIXELFORMAT_RG8: auto type = formatInfo[format].dataType;
case PIXELFORMAT_R16: return type == PIXELFORMATTYPE_SINT || type == PIXELFORMATTYPE_UINT;
case PIXELFORMAT_R16F: }
case PIXELFORMAT_LA8:
case PIXELFORMAT_RGBA4: PixelFormat getSRGBPixelFormat(PixelFormat format)
case PIXELFORMAT_RGB5A1: {
case PIXELFORMAT_RGB565: if (format == PIXELFORMAT_RGBA8_UNORM)
case PIXELFORMAT_DEPTH16: return PIXELFORMAT_RGBA8_UNORM_sRGB;
return 2; else if (format == PIXELFORMAT_BGRA8_UNORM)
case PIXELFORMAT_RGBA8: return PIXELFORMAT_BGRA8_UNORM_sRGB;
case PIXELFORMAT_sRGBA8: return format;
case PIXELFORMAT_RG16: }
case PIXELFORMAT_RG16F:
case PIXELFORMAT_R32F: PixelFormat getLinearPixelFormat(PixelFormat format)
case PIXELFORMAT_RGB10A2: {
case PIXELFORMAT_RG11B10F: if (format == PIXELFORMAT_RGBA8_UNORM_sRGB)
case PIXELFORMAT_DEPTH24: return PIXELFORMAT_RGBA8_UNORM;
case PIXELFORMAT_DEPTH32F: else if (format == PIXELFORMAT_BGRA8_UNORM_sRGB)
case PIXELFORMAT_DEPTH24_STENCIL8: return PIXELFORMAT_BGRA8_UNORM;
return 4; return format;
case PIXELFORMAT_RGBA16: }
case PIXELFORMAT_RGBA16F:
case PIXELFORMAT_RG32F: size_t getPixelFormatBlockSize(PixelFormat format)
case PIXELFORMAT_DEPTH32F_STENCIL8: {
return 8; return formatInfo[format].blockSize;
case PIXELFORMAT_RGBA32F: }
return 16;
default: size_t getPixelFormatUncompressedRowSize(PixelFormat format, int width)
// TODO: compressed formats {
return 0; const PixelFormatInfo &info = formatInfo[format];
} if (info.compressed) return 0;
return info.blockSize * width / info.blockWidth;
}
size_t getPixelFormatCompressedBlockRowSize(PixelFormat format, int width)
{
const PixelFormatInfo &info = formatInfo[format];
if (!info.compressed) return 0;
return info.blockSize * ((width + info.blockWidth - 1) / info.blockWidth);
}
size_t getPixelFormatCompressedBlockRowCount(PixelFormat format, int height)
{
const PixelFormatInfo &info = formatInfo[format];
if (!info.compressed) return 0;
return (height + info.blockHeight - 1) / info.blockHeight;
}
size_t getPixelFormatSliceSize(PixelFormat format, int width, int height)
{
const PixelFormatInfo &info = formatInfo[format];
size_t blockW = (width + info.blockWidth - 1) / info.blockWidth;
size_t blockH = (height + info.blockHeight - 1) / info.blockHeight;
return info.blockSize * blockW * blockH;
} }
int getPixelFormatColorComponents(PixelFormat format) int getPixelFormatColorComponents(PixelFormat format)
{ {
switch (format) return formatInfo[format].components;
{
case PIXELFORMAT_R8:
case PIXELFORMAT_R16:
case PIXELFORMAT_R16F:
case PIXELFORMAT_R32F:
return 1;
case PIXELFORMAT_RG8:
case PIXELFORMAT_RG16:
case PIXELFORMAT_RG16F:
case PIXELFORMAT_RG32F:
case PIXELFORMAT_LA8:
return 2;
case PIXELFORMAT_RGB565:
case PIXELFORMAT_RG11B10F:
return 3;
case PIXELFORMAT_RGBA8:
case PIXELFORMAT_sRGBA8:
case PIXELFORMAT_RGBA16:
case PIXELFORMAT_RGBA16F:
case PIXELFORMAT_RGBA32F:
case PIXELFORMAT_RGBA4:
case PIXELFORMAT_RGB5A1:
case PIXELFORMAT_RGB10A2:
return 4;
default:
return 0;
}
} }
} // love } // love
+154 -50
View File
@@ -33,61 +33,84 @@ enum PixelFormat
PIXELFORMAT_NORMAL, PIXELFORMAT_NORMAL,
PIXELFORMAT_HDR, PIXELFORMAT_HDR,
// "regular" formats // 1-channel normal formats
PIXELFORMAT_R8, PIXELFORMAT_R8_UNORM,
PIXELFORMAT_RG8, PIXELFORMAT_R8_INT,
PIXELFORMAT_RGBA8, PIXELFORMAT_R8_UINT,
PIXELFORMAT_sRGBA8, PIXELFORMAT_R16_UNORM,
PIXELFORMAT_R16, PIXELFORMAT_R16_FLOAT,
PIXELFORMAT_RG16, PIXELFORMAT_R16_INT,
PIXELFORMAT_RGBA16, PIXELFORMAT_R16_UINT,
PIXELFORMAT_R16F, PIXELFORMAT_R32_FLOAT,
PIXELFORMAT_RG16F, PIXELFORMAT_R32_INT,
PIXELFORMAT_RGBA16F, PIXELFORMAT_R32_UINT,
PIXELFORMAT_R32F,
PIXELFORMAT_RG32F,
PIXELFORMAT_RGBA32F,
PIXELFORMAT_LA8, // Same as RG8, but accessed as (L, L, L, A) // 2-channel normal formats
PIXELFORMAT_RG8_UNORM,
PIXELFORMAT_RG8_INT,
PIXELFORMAT_RG8_UINT,
PIXELFORMAT_LA8_UNORM, // Same as RG8, but accessed as (L, L, L, A)
PIXELFORMAT_RG16_UNORM,
PIXELFORMAT_RG16_FLOAT,
PIXELFORMAT_RG16_INT,
PIXELFORMAT_RG16_UINT,
PIXELFORMAT_RG32_FLOAT,
PIXELFORMAT_RG32_INT,
PIXELFORMAT_RG32_UINT,
// 4-channel normal formats
PIXELFORMAT_RGBA8_UNORM,
PIXELFORMAT_RGBA8_UNORM_sRGB,
PIXELFORMAT_BGRA8_UNORM,
PIXELFORMAT_BGRA8_UNORM_sRGB,
PIXELFORMAT_RGBA8_INT,
PIXELFORMAT_RGBA8_UINT,
PIXELFORMAT_RGBA16_UNORM,
PIXELFORMAT_RGBA16_FLOAT,
PIXELFORMAT_RGBA16_INT,
PIXELFORMAT_RGBA16_UINT,
PIXELFORMAT_RGBA32_FLOAT,
PIXELFORMAT_RGBA32_INT,
PIXELFORMAT_RGBA32_UINT,
// packed formats // packed formats
PIXELFORMAT_RGBA4, // LSB->MSB: [a, b, g, r] PIXELFORMAT_RGBA4_UNORM, // LSB->MSB: [a, b, g, r]
PIXELFORMAT_RGB5A1, // LSB->MSB: [a, b, g, r] PIXELFORMAT_RGB5A1_UNORM, // LSB->MSB: [a, b, g, r]
PIXELFORMAT_RGB565, // LSB->MSB: [b, g, r] PIXELFORMAT_RGB565_UNORM, // LSB->MSB: [b, g, r]
PIXELFORMAT_RGB10A2, // LSB->MSB: [r, g, b, a] PIXELFORMAT_RGB10A2_UNORM, // LSB->MSB: [r, g, b, a]
PIXELFORMAT_RG11B10F, // LSB->MSB: [r, g, b] PIXELFORMAT_RG11B10_FLOAT, // LSB->MSB: [r, g, b]
// depth/stencil formats // depth/stencil formats
PIXELFORMAT_STENCIL8, PIXELFORMAT_STENCIL8,
PIXELFORMAT_DEPTH16, PIXELFORMAT_DEPTH16_UNORM,
PIXELFORMAT_DEPTH24, PIXELFORMAT_DEPTH24_UNORM,
PIXELFORMAT_DEPTH32F, PIXELFORMAT_DEPTH32_FLOAT,
PIXELFORMAT_DEPTH24_STENCIL8, PIXELFORMAT_DEPTH24_UNORM_STENCIL8,
PIXELFORMAT_DEPTH32F_STENCIL8, PIXELFORMAT_DEPTH32_FLOAT_STENCIL8,
// compressed formats // compressed formats
PIXELFORMAT_DXT1, PIXELFORMAT_DXT1_UNORM,
PIXELFORMAT_DXT3, PIXELFORMAT_DXT3_UNORM,
PIXELFORMAT_DXT5, PIXELFORMAT_DXT5_UNORM,
PIXELFORMAT_BC4, PIXELFORMAT_BC4_UNORM,
PIXELFORMAT_BC4s, PIXELFORMAT_BC4_SNORM,
PIXELFORMAT_BC5, PIXELFORMAT_BC5_UNORM,
PIXELFORMAT_BC5s, PIXELFORMAT_BC5_SNORM,
PIXELFORMAT_BC6H, PIXELFORMAT_BC6H_UFLOAT,
PIXELFORMAT_BC6Hs, PIXELFORMAT_BC6H_FLOAT,
PIXELFORMAT_BC7, PIXELFORMAT_BC7_UNORM,
PIXELFORMAT_PVR1_RGB2, PIXELFORMAT_PVR1_RGB2_UNORM,
PIXELFORMAT_PVR1_RGB4, PIXELFORMAT_PVR1_RGB4_UNORM,
PIXELFORMAT_PVR1_RGBA2, PIXELFORMAT_PVR1_RGBA2_UNORM,
PIXELFORMAT_PVR1_RGBA4, PIXELFORMAT_PVR1_RGBA4_UNORM,
PIXELFORMAT_ETC1, PIXELFORMAT_ETC1_UNORM,
PIXELFORMAT_ETC2_RGB, PIXELFORMAT_ETC2_RGB_UNORM,
PIXELFORMAT_ETC2_RGBA, PIXELFORMAT_ETC2_RGBA_UNORM,
PIXELFORMAT_ETC2_RGBA1, PIXELFORMAT_ETC2_RGBA1_UNORM,
PIXELFORMAT_EAC_R, PIXELFORMAT_EAC_R_UNORM,
PIXELFORMAT_EAC_Rs, PIXELFORMAT_EAC_R_SNORM,
PIXELFORMAT_EAC_RG, PIXELFORMAT_EAC_RG_UNORM,
PIXELFORMAT_EAC_RGs, PIXELFORMAT_EAC_RG_SNORM,
PIXELFORMAT_ASTC_4x4, PIXELFORMAT_ASTC_4x4,
PIXELFORMAT_ASTC_5x4, PIXELFORMAT_ASTC_5x4,
PIXELFORMAT_ASTC_5x5, PIXELFORMAT_ASTC_5x5,
@@ -106,14 +129,49 @@ enum PixelFormat
PIXELFORMAT_MAX_ENUM PIXELFORMAT_MAX_ENUM
}; };
enum PixelFormatType
{
PIXELFORMATTYPE_UNORM,
PIXELFORMATTYPE_SNORM,
PIXELFORMATTYPE_UFLOAT,
PIXELFORMATTYPE_SFLOAT,
PIXELFORMATTYPE_UINT,
PIXELFORMATTYPE_SINT,
};
struct PixelFormatInfo
{
int components;
size_t blockWidth;
size_t blockHeight;
size_t blockSize;
bool color;
bool depth;
bool stencil;
bool compressed;
PixelFormatType dataType;
};
bool getConstant(PixelFormat in, const char *&out); bool getConstant(PixelFormat in, const char *&out);
bool getConstant(const char *in, PixelFormat &out); bool getConstant(const char *in, PixelFormat &out);
const PixelFormatInfo &getPixelFormatInfo(PixelFormat format);
/**
* Gets the name of the specified pixel format.
**/
const char *getPixelFormatName(PixelFormat format);
/** /**
* Gets whether the specified pixel format is a compressed type. * Gets whether the specified pixel format is a compressed type.
**/ **/
bool isPixelFormatCompressed(PixelFormat format); bool isPixelFormatCompressed(PixelFormat format);
/**
* Gets whether the specified pixel format is a color type.
**/
bool isPixelFormatColor(PixelFormat format);
/** /**
* Gets whether the specified pixel format is a depth or stencil type. * Gets whether the specified pixel format is a depth or stencil type.
**/ **/
@@ -130,10 +188,56 @@ bool isPixelFormatDepth(PixelFormat format);
bool isPixelFormatStencil(PixelFormat format); bool isPixelFormatStencil(PixelFormat format);
/** /**
* Gets the size in bytes of the specified pixel format. * Gets whether the specified color pixel format is sRGB-encoded.
* NOTE: Currently returns 0 for compressed formats.
**/ **/
size_t getPixelFormatSize(PixelFormat format); bool isPixelFormatSRGB(PixelFormat format);
/**
* Gets whether the specified pixel format is a signed or unsigned integer type.
**/
bool isPixelFormatInteger(PixelFormat format);
/**
* Gets the sRGB version of a linear pixel format, if applicable.
**/
PixelFormat getSRGBPixelFormat(PixelFormat format);
/**
* Gets the linear version of a sRGB pixel format, if applicable.
**/
PixelFormat getLinearPixelFormat(PixelFormat format);
/**
* Gets the block size in bytes of the specified pixel format.
* This is the size in bytes of a pixel for uncompressed formats, but *not*
* for compressed formats!
**/
size_t getPixelFormatBlockSize(PixelFormat format);
/**
* Gets the size in bytes of a row of an uncompressed pixel format.
**/
size_t getPixelFormatUncompressedRowSize(PixelFormat format, int width);
/**
* Gets the size in bytes of a row of a compressed pixel format. This is the
* number of blocks used by the given width, multiplied by the block size. The
* number of rows of blocks for a given height can be computed by
* getPixelFormatCompressedBlockRowCount.
**/
size_t getPixelFormatCompressedBlockRowSize(PixelFormat format, int width);
/**
* Gets the number of rows of blocks the given compressed pixel format will use,
* for the given height in pixels.
**/
size_t getPixelFormatCompressedBlockRowCount(PixelFormat format, int height);
/**
* Gets the size in bytes of a slice (width x height 2D plane) which uses the
* given pixel format.
**/
size_t getPixelFormatSliceSize(PixelFormat format, int width, int height);
/** /**
* Gets the number of color components in the given pixel format. * Gets the number of color components in the given pixel format.
+177 -13
View File
@@ -36,13 +36,6 @@
#include <cmath> #include <cmath>
#include <sstream> #include <sstream>
// VS2013 doesn't support alignof
#if defined(_MSC_VER) && _MSC_VER <= 1800
#define LOVE_ALIGNOF(x) __alignof(x)
#else
#define LOVE_ALIGNOF(x) alignof(x)
#endif
namespace love namespace love
{ {
@@ -145,7 +138,7 @@ static ObjectKey luax_computeloveobjectkey(lua_State *L, love::Object *object)
// It appears to be ABI violation. However it seems there's no reliable way to // It appears to be ABI violation. However it seems there's no reliable way to
// get the correct alignment pre-C++17. Consider that 32-bit pointer still fits // get the correct alignment pre-C++17. Consider that 32-bit pointer still fits
// in 2^53 range, it's perfectly fine to assume alignment of 1 there. // in 2^53 range, it's perfectly fine to assume alignment of 1 there.
const size_t minalign = sizeof(void*) == 8 ? LOVE_ALIGNOF(std::max_align_t) : 1; const size_t minalign = sizeof(void*) == 8 ? alignof(std::max_align_t) : 1;
uintptr_t key = (uintptr_t) object; uintptr_t key = (uintptr_t) object;
if ((key & (minalign - 1)) != 0) if ((key & (minalign - 1)) != 0)
@@ -349,6 +342,23 @@ double luax_numberflag(lua_State *L, int table_index, const char *key, double de
return retval; return retval;
} }
bool luax_checkboolflag(lua_State *L, int table_index, const char *key)
{
lua_getfield(L, table_index, key);
bool retval = false;
if (lua_type(L, -1) != LUA_TBOOLEAN)
{
std::string err = "expected boolean field '" + std::string(key) + "' in table";
return luaL_argerror(L, table_index, err.c_str());
}
else
retval = luax_toboolean(L, -1);
lua_pop(L, 1);
return retval;
}
int luax_checkintflag(lua_State *L, int table_index, const char *key) int luax_checkintflag(lua_State *L, int table_index, const char *key)
{ {
lua_getfield(L, table_index, key); lua_getfield(L, table_index, key);
@@ -356,7 +366,7 @@ int luax_checkintflag(lua_State *L, int table_index, const char *key)
int retval; int retval;
if (!lua_isnumber(L, -1)) if (!lua_isnumber(L, -1))
{ {
std::string err = "expected integer field " + std::string(key) + " in table"; std::string err = "expected integer field '" + std::string(key) + "' in table";
return luaL_argerror(L, table_index, err.c_str()); return luaL_argerror(L, table_index, err.c_str());
} }
else else
@@ -693,6 +703,160 @@ bool luax_istype(lua_State *L, int idx, love::Type &type)
return false; return false;
} }
static Proxy *tryextractproxy(lua_State *L, int idx)
{
Proxy *u = (Proxy *)lua_touserdata(L, idx);
if (u == nullptr || u->type == nullptr)
return nullptr;
// We could get rid of the dynamic_cast for more performance, but it would
// be less safe...
if (dynamic_cast<Object *>(u->object) != nullptr)
return u;
return nullptr;
}
Variant luax_checkvariant(lua_State *L, int n, bool allowuserdata, std::set<const void*> *tableSet)
{
size_t len;
const char *str;
Proxy *p = nullptr;
if (n < 0) // Fix the stack position, we might modify it later
n += lua_gettop(L) + 1;
switch (lua_type(L, n))
{
case LUA_TBOOLEAN:
return Variant(luax_toboolean(L, n));
case LUA_TNUMBER:
return Variant(lua_tonumber(L, n));
case LUA_TSTRING:
str = lua_tolstring(L, n, &len);
return Variant(str, len);
case LUA_TLIGHTUSERDATA:
return Variant(lua_touserdata(L, n));
case LUA_TUSERDATA:
if (!allowuserdata)
{
luax_typerror(L, n, "copyable Lua value");
return Variant();
}
p = tryextractproxy(L, n);
if (p != nullptr)
return Variant(p->type, p->object);
else
{
luax_typerror(L, n, "love type");
return Variant();
}
case LUA_TNIL:
return Variant();
case LUA_TTABLE:
{
bool success = true;
std::set<const void *> topTableSet;
// We can use a pointer to a stack-allocated variable because it's
// never used after the stack-allocated variable is destroyed.
if (tableSet == nullptr)
tableSet = &topTableSet;
// Now make sure this table wasn't already serialised
const void *tablePointer = lua_topointer(L, n);
{
auto result = tableSet->insert(tablePointer);
if (!result.second) // insertion failed
throw love::Exception("Cycle detected in table");
}
Variant::SharedTable *table = new Variant::SharedTable();
size_t len = luax_objlen(L, -1);
if (len > 0)
table->pairs.reserve(len);
lua_pushnil(L);
while (lua_next(L, n))
{
table->pairs.emplace_back(
luax_checkvariant(L, -2, allowuserdata, tableSet),
luax_checkvariant(L, -1, allowuserdata, tableSet)
);
lua_pop(L, 1);
const auto &p = table->pairs.back();
if (p.first.getType() == Variant::UNKNOWN || p.second.getType() == Variant::UNKNOWN)
{
success = false;
break;
}
}
// And remove the table from the set again
tableSet->erase(tablePointer);
if (success)
return Variant(table);
else
table->release();
}
break;
}
return Variant::unknown();
}
void luax_pushvariant(lua_State *L, const Variant &v)
{
const Variant::Data &data = v.getData();
switch (v.getType())
{
case Variant::BOOLEAN:
lua_pushboolean(L, data.boolean);
break;
case Variant::NUMBER:
lua_pushnumber(L, data.number);
break;
case Variant::STRING:
lua_pushlstring(L, data.string->str, data.string->len);
break;
case Variant::SMALLSTRING:
lua_pushlstring(L, data.smallstring.str, data.smallstring.len);
break;
case Variant::LUSERDATA:
lua_pushlightuserdata(L, data.userdata);
break;
case Variant::LOVEOBJECT:
luax_pushtype(L, *data.objectproxy.type, data.objectproxy.object);
break;
case Variant::TABLE:
{
std::vector<std::pair<Variant, Variant>> &table = data.table->pairs;
int tsize = (int) table.size();
lua_createtable(L, 0, tsize);
for (int i = 0; i < tsize; ++i)
{
std::pair<Variant, Variant> &kv = table[i];
luax_pushvariant(L, kv.first);
luax_pushvariant(L, kv.second);
lua_settable(L, -3);
}
break;
}
case Variant::NIL:
default:
lua_pushnil(L);
break;
}
}
int luax_getfunction(lua_State *L, const char *mod, const char *fn) int luax_getfunction(lua_State *L, const char *mod, const char *fn)
{ {
lua_getglobal(L, "love"); lua_getglobal(L, "love");
@@ -899,18 +1063,18 @@ lua_State *luax_getpinnedthread(lua_State *L)
return thread; return thread;
} }
void luax_markdeprecated(lua_State *L, const char *name, APIType api) void luax_markdeprecated(lua_State *L, int level, const char *name, APIType api)
{ {
luax_markdeprecated(L, name, api, DEPRECATED_NO_REPLACEMENT, nullptr); luax_markdeprecated(L, level, name, api, DEPRECATED_NO_REPLACEMENT, nullptr);
} }
void luax_markdeprecated(lua_State *L, const char *name, APIType api, DeprecationType type, const char *replacement) void luax_markdeprecated(lua_State *L, int level, const char *name, APIType api, DeprecationType type, const char *replacement)
{ {
MarkDeprecated deprecated(name, api, type, replacement); MarkDeprecated deprecated(name, api, type, replacement);
if (deprecated.info != nullptr && deprecated.info->uses == 1) if (deprecated.info != nullptr && deprecated.info->uses == 1)
{ {
luaL_where(L, 1); luaL_where(L, level);
const char *where = lua_tostring(L, -1); const char *where = lua_tostring(L, -1);
if (where != nullptr) if (where != nullptr)
deprecated.info->where = where; deprecated.info->where = where;
+26 -18
View File
@@ -24,6 +24,8 @@
// LOVE // LOVE
#include "config.h" #include "config.h"
#include "types.h" #include "types.h"
#include "Object.h"
#include "Variant.h"
#include "deprecation.h" #include "deprecation.h"
// Lua // Lua
@@ -37,12 +39,12 @@ extern "C" {
// C++ // C++
#include <exception> #include <exception>
#include <algorithm> #include <algorithm>
#include <set>
namespace love namespace love
{ {
// Forward declarations. // Forward declarations.
class Object;
class Module; class Module;
class Reference; class Reference;
@@ -59,21 +61,6 @@ enum Registry
REGISTRY_OBJECTS REGISTRY_OBJECTS
}; };
/**
* This structure wraps all Lua-exposed objects. It exists in the
* Lua state as a full userdata (so we can catch __gc "events"),
* though the Object it refers to is light userdata in the sense
* that it is not allocated by the Lua VM.
**/
struct Proxy
{
// Holds type information (see types.h).
love::Type *type;
// Pointer to the actual object.
Object *object;
};
/** /**
* A Module with Lua wrapper functions and other data. * A Module with Lua wrapper functions and other data.
**/ **/
@@ -190,6 +177,7 @@ bool luax_boolflag(lua_State *L, int table_index, const char *key, bool defaultV
int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue); int luax_intflag(lua_State *L, int table_index, const char *key, int defaultValue);
double luax_numberflag(lua_State *L, int table_index, const char *key, double defaultValue); double luax_numberflag(lua_State *L, int table_index, const char *key, double defaultValue);
bool luax_checkboolflag(lua_State *L, int table_index, const char *key);
int luax_checkintflag(lua_State *L, int table_index, const char *key); int luax_checkintflag(lua_State *L, int table_index, const char *key);
/** /**
@@ -214,6 +202,16 @@ inline float luax_checkfloat(lua_State *L, int idx)
return static_cast<float>(luaL_checknumber(L, idx)); return static_cast<float>(luaL_checknumber(L, idx));
} }
inline lua_Number luax_checknumberclamped(lua_State *L, int idx, double minv, double maxv)
{
return std::min(std::max(luaL_checknumber(L, idx), minv), maxv);
}
inline lua_Number luax_optnumberclamped(lua_State *L, int idx, double minv, double maxv, double def)
{
return std::min(std::max(luaL_optnumber(L, idx, def), minv), maxv);
}
inline lua_Number luax_checknumberclamped01(lua_State *L, int idx) inline lua_Number luax_checknumberclamped01(lua_State *L, int idx)
{ {
return std::min(std::max(luaL_checknumber(L, idx), 0.0), 1.0); return std::min(std::max(luaL_checknumber(L, idx), 0.0), 1.0);
@@ -354,6 +352,16 @@ void luax_pushtype(lua_State *L, StrongRef<T> &object)
**/ **/
void luax_rawnewtype(lua_State *L, love::Type &type, love::Object *object); void luax_rawnewtype(lua_State *L, love::Type &type, love::Object *object);
/**
* Stores the value at the given index on the stack into a Variant object.
*/
LOVE_EXPORT Variant luax_checkvariant(lua_State *L, int idx, bool allowuserdata = true, std::set<const void*> *tableSet = nullptr);
/**
* Pushes the contents of the given Variant index onto the stack.
*/
LOVE_EXPORT void luax_pushvariant(lua_State *L, const Variant &v);
/** /**
* Checks whether the value at idx is a certain type. * Checks whether the value at idx is a certain type.
* @param L The Lua state. * @param L The Lua state.
@@ -474,8 +482,8 @@ lua_State *luax_getpinnedthread(lua_State *L);
* Mark a function as deprecated. Should only be called inside wrapper function * Mark a function as deprecated. Should only be called inside wrapper function
* code. * code.
**/ **/
void luax_markdeprecated(lua_State *L, const char *name, APIType api); void luax_markdeprecated(lua_State *L, int level, const char *name, APIType api);
void luax_markdeprecated(lua_State *L, const char *name, APIType api, DeprecationType type, const char *replacement); void luax_markdeprecated(lua_State *L, int level, const char *name, APIType api, DeprecationType type, const char *replacement);
extern "C" { // Also called from luasocket extern "C" { // Also called from luasocket
int luax_typerror(lua_State *L, int narg, const char *tname); int luax_typerror(lua_State *L, int narg, const char *tname);
-1
View File
@@ -25,7 +25,6 @@
// STD // STD
#include <bitset> #include <bitset>
#include <vector>
namespace love namespace love
{ {
+2
View File
@@ -23,6 +23,8 @@
#ifdef LOVE_WINDOWS #ifdef LOVE_WINDOWS
#include <string> #include <string>
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
namespace love namespace love
+5 -5
View File
@@ -25,13 +25,13 @@ namespace love
{ {
// Version stuff. // Version stuff.
#define LOVE_VERSION_STRING "11.5" #define LOVE_VERSION_STRING "12.0"
static const int VERSION_MAJOR = 11; static const int VERSION_MAJOR = 12;
static const int VERSION_MINOR = 5; static const int VERSION_MINOR = 0;
static const int VERSION_REV = 0; static const int VERSION_REV = 0;
static const char *VERSION = LOVE_VERSION_STRING; static const char *VERSION = LOVE_VERSION_STRING;
static const char *VERSION_COMPATIBILITY[] = { VERSION, "11.0", "11.1", "11.2", "11.3", "11.4", 0 }; static const char *VERSION_COMPATIBILITY[] = { VERSION, 0 };
static const char *VERSION_CODENAME = "Mysterious Mysteries"; static const char *VERSION_CODENAME = "";
} // love } // love
-68
View File
@@ -1,68 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BOX2D_H
#define BOX2D_H
/**
\mainpage Box2D API Documentation
\section intro_sec Getting Started
For documentation please see http://box2d.org/documentation.html
For discussion please visit http://box2d.org/forum
*/
// These include files constitute the main Box2D API
#include <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/b2MotorJoint.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>
#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
#endif
@@ -1,105 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CHAIN_SHAPE_H
#define B2_CHAIN_SHAPE_H
#include <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();
/// Clear all data.
void Clear();
/// Create a loop. This automatically adjusts connectivity.
/// @param vertices an array of vertices, these are copied
/// @param count the vertex count
void CreateLoop(const b2Vec2* vertices, int32 count);
/// Create a chain with isolated end vertices.
/// @param vertices an array of vertices, these are copied
/// @param count the vertex count
void CreateChain(const b2Vec2* vertices, int32 count);
/// Establish connectivity to a vertex that precedes the first vertex.
/// Don't call this for loops.
void SetPrevVertex(const b2Vec2& prevVertex);
/// Establish connectivity to a vertex that follows the last vertex.
/// Don't call this for loops.
void SetNextVertex(const b2Vec2& nextVertex);
/// Implement b2Shape. Vertices are cloned using b2Alloc.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// Get a child edge.
void GetChildEdge(b2EdgeShape* edge, int32 index) const;
/// This always return false.
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// Chains have zero mass.
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// The vertices. Owned by this class.
b2Vec2* m_vertices;
/// The vertex count.
int32 m_count;
b2Vec2 m_prevVertex, m_nextVertex;
bool m_hasPrevVertex, m_hasNextVertex;
};
inline b2ChainShape::b2ChainShape()
{
m_type = e_chain;
m_radius = b2_polygonRadius;
m_vertices = NULL;
m_count = 0;
m_hasPrevVertex = false;
m_hasNextVertex = false;
}
#endif
@@ -1,91 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CIRCLE_SHAPE_H
#define B2_CIRCLE_SHAPE_H
#include <Box2D/Collision/Shapes/b2Shape.h>
/// A circle shape.
class b2CircleShape : public b2Shape
{
public:
b2CircleShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// Implement b2Shape.
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const { return 1; }
/// Get a vertex by index. Used by b2Distance.
const b2Vec2& GetVertex(int32 index) const;
/// Position
b2Vec2 m_p;
};
inline b2CircleShape::b2CircleShape()
{
m_type = e_circle;
m_radius = 0.0f;
m_p.SetZero();
}
inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const
{
B2_NOT_USED(d);
return 0;
}
inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const
{
B2_NOT_USED(d);
return m_p;
}
inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const
{
B2_NOT_USED(index);
b2Assert(index == 0);
return m_p;
}
#endif
@@ -1,74 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_EDGE_SHAPE_H
#define B2_EDGE_SHAPE_H
#include <Box2D/Collision/Shapes/b2Shape.h>
/// A line segment (edge) shape. These can be connected in chains or loops
/// to other edge shapes. The connectivity information is used to ensure
/// correct contact normals.
class b2EdgeShape : public b2Shape
{
public:
b2EdgeShape();
/// Set this as an isolated edge.
void Set(const b2Vec2& v1, const b2Vec2& v2);
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// These are the edge vertices
b2Vec2 m_vertex1, m_vertex2;
/// Optional adjacent vertices. These are used for smooth collision.
b2Vec2 m_vertex0, m_vertex3;
bool m_hasVertex0, m_hasVertex3;
};
inline b2EdgeShape::b2EdgeShape()
{
m_type = e_edge;
m_radius = b2_polygonRadius;
m_vertex0.x = 0.0f;
m_vertex0.y = 0.0f;
m_vertex3.x = 0.0f;
m_vertex3.y = 0.0f;
m_hasVertex0 = false;
m_hasVertex3 = false;
}
#endif
@@ -1,101 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_SHAPE_H
#define B2_POLYGON_SHAPE_H
#include <Box2D/Collision/Shapes/b2Shape.h>
/// A convex polygon. It is assumed that the interior of the polygon is to
/// the left of each edge.
/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices.
/// In most cases you should not need many vertices for a convex polygon.
class b2PolygonShape : public b2Shape
{
public:
b2PolygonShape();
/// Implement b2Shape.
b2Shape* Clone(b2BlockAllocator* allocator) const;
/// @see b2Shape::GetChildCount
int32 GetChildCount() const;
/// Create a convex hull from the given array of local points.
/// The count must be in the range [3, b2_maxPolygonVertices].
/// @warning the points may be re-ordered, even if they form a convex polygon
/// @warning collinear points are handled but not removed. Collinear points
/// may lead to poor stacking behavior.
void Set(const b2Vec2* points, int32 count);
/// Build vertices to represent an axis-aligned box centered on the local origin.
/// @param hx the half-width.
/// @param hy the half-height.
void SetAsBox(float32 hx, float32 hy);
/// Build vertices to represent an oriented box.
/// @param hx the half-width.
/// @param hy the half-height.
/// @param center the center of the box in local coordinates.
/// @param angle the rotation of the box in local coordinates.
void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);
/// @see b2Shape::TestPoint
bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
/// Implement b2Shape.
bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeAABB
void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
/// @see b2Shape::ComputeMass
void ComputeMass(b2MassData* massData, float32 density) const;
/// Get the vertex count.
int32 GetVertexCount() const { return m_count; }
/// Get a vertex by index.
const b2Vec2& GetVertex(int32 index) const;
/// Validate convexity. This is a very time consuming operation.
/// @returns true if valid
bool Validate() const;
b2Vec2 m_centroid;
b2Vec2 m_vertices[b2_maxPolygonVertices];
b2Vec2 m_normals[b2_maxPolygonVertices];
int32 m_count;
};
inline b2PolygonShape::b2PolygonShape()
{
m_type = e_polygon;
m_radius = b2_polygonRadius;
m_count = 0;
m_centroid.SetZero();
}
inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const
{
b2Assert(0 <= index && index < m_count);
return m_vertices[index];
}
#endif
@@ -1,698 +0,0 @@
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Collision/b2Collision.h>
#include <Box2D/Collision/Shapes/b2CircleShape.h>
#include <Box2D/Collision/Shapes/b2EdgeShape.h>
#include <Box2D/Collision/Shapes/b2PolygonShape.h>
// Compute contact points for edge versus circle.
// This accounts for edge connectivity.
void b2CollideEdgeAndCircle(b2Manifold* manifold,
const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2CircleShape* circleB, const b2Transform& xfB)
{
manifold->pointCount = 0;
// Compute circle in frame of edge
b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p));
b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2;
b2Vec2 e = B - A;
// Barycentric coordinates
float32 u = b2Dot(e, B - Q);
float32 v = b2Dot(e, Q - A);
float32 radius = edgeA->m_radius + circleB->m_radius;
b2ContactFeature cf;
cf.indexB = 0;
cf.typeB = b2ContactFeature::e_vertex;
// Region A
if (v <= 0.0f)
{
b2Vec2 P = A;
b2Vec2 d = Q - P;
float32 dd = b2Dot(d, d);
if (dd > radius * radius)
{
return;
}
// Is there an edge connected to A?
if (edgeA->m_hasVertex0)
{
b2Vec2 A1 = edgeA->m_vertex0;
b2Vec2 B1 = A;
b2Vec2 e1 = B1 - A1;
float32 u1 = b2Dot(e1, B1 - Q);
// Is the circle in Region AB of the previous edge?
if (u1 > 0.0f)
{
return;
}
}
cf.indexA = 0;
cf.typeA = b2ContactFeature::e_vertex;
manifold->pointCount = 1;
manifold->type = b2Manifold::e_circles;
manifold->localNormal.SetZero();
manifold->localPoint = P;
manifold->points[0].id.key = 0;
manifold->points[0].id.cf = cf;
manifold->points[0].localPoint = circleB->m_p;
return;
}
// Region B
if (u <= 0.0f)
{
b2Vec2 P = B;
b2Vec2 d = Q - P;
float32 dd = b2Dot(d, d);
if (dd > radius * radius)
{
return;
}
// Is there an edge connected to B?
if (edgeA->m_hasVertex3)
{
b2Vec2 B2 = edgeA->m_vertex3;
b2Vec2 A2 = B;
b2Vec2 e2 = B2 - A2;
float32 v2 = b2Dot(e2, Q - A2);
// Is the circle in Region AB of the next edge?
if (v2 > 0.0f)
{
return;
}
}
cf.indexA = 1;
cf.typeA = b2ContactFeature::e_vertex;
manifold->pointCount = 1;
manifold->type = b2Manifold::e_circles;
manifold->localNormal.SetZero();
manifold->localPoint = P;
manifold->points[0].id.key = 0;
manifold->points[0].id.cf = cf;
manifold->points[0].localPoint = circleB->m_p;
return;
}
// Region AB
float32 den = b2Dot(e, e);
b2Assert(den > 0.0f);
b2Vec2 P = (1.0f / den) * (u * A + v * B);
b2Vec2 d = Q - P;
float32 dd = b2Dot(d, d);
if (dd > radius * radius)
{
return;
}
b2Vec2 n(-e.y, e.x);
if (b2Dot(n, Q - A) < 0.0f)
{
n.Set(-n.x, -n.y);
}
n.Normalize();
cf.indexA = 0;
cf.typeA = b2ContactFeature::e_face;
manifold->pointCount = 1;
manifold->type = b2Manifold::e_faceA;
manifold->localNormal = n;
manifold->localPoint = A;
manifold->points[0].id.key = 0;
manifold->points[0].id.cf = cf;
manifold->points[0].localPoint = circleB->m_p;
}
// This structure is used to keep track of the best separating axis.
struct b2EPAxis
{
enum Type
{
e_unknown,
e_edgeA,
e_edgeB
};
Type type;
int32 index;
float32 separation;
};
// This holds polygon B expressed in frame A.
struct b2TempPolygon
{
b2Vec2 vertices[b2_maxPolygonVertices];
b2Vec2 normals[b2_maxPolygonVertices];
int32 count;
};
// Reference face used for clipping
struct b2ReferenceFace
{
int32 i1, i2;
b2Vec2 v1, v2;
b2Vec2 normal;
b2Vec2 sideNormal1;
float32 sideOffset1;
b2Vec2 sideNormal2;
float32 sideOffset2;
};
// This class collides and edge and a polygon, taking into account edge adjacency.
struct b2EPCollider
{
void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB);
b2EPAxis ComputeEdgeSeparation();
b2EPAxis ComputePolygonSeparation();
enum VertexType
{
e_isolated,
e_concave,
e_convex
};
b2TempPolygon m_polygonB;
b2Transform m_xf;
b2Vec2 m_centroidB;
b2Vec2 m_v0, m_v1, m_v2, m_v3;
b2Vec2 m_normal0, m_normal1, m_normal2;
b2Vec2 m_normal;
VertexType m_type1, m_type2;
b2Vec2 m_lowerLimit, m_upperLimit;
float32 m_radius;
bool m_front;
};
// Algorithm:
// 1. Classify v1 and v2
// 2. Classify polygon centroid as front or back
// 3. Flip normal if necessary
// 4. Initialize normal range to [-pi, pi] about face normal
// 5. Adjust normal range according to adjacent edges
// 6. Visit each separating axes, only accept axes within the range
// 7. Return if _any_ axis indicates separation
// 8. Clip
void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB)
{
m_xf = b2MulT(xfA, xfB);
m_centroidB = b2Mul(m_xf, polygonB->m_centroid);
m_v0 = edgeA->m_vertex0;
m_v1 = edgeA->m_vertex1;
m_v2 = edgeA->m_vertex2;
m_v3 = edgeA->m_vertex3;
bool hasVertex0 = edgeA->m_hasVertex0;
bool hasVertex3 = edgeA->m_hasVertex3;
b2Vec2 edge1 = m_v2 - m_v1;
edge1.Normalize();
m_normal1.Set(edge1.y, -edge1.x);
float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1);
float32 offset0 = 0.0f, offset2 = 0.0f;
bool convex1 = false, convex2 = false;
// Is there a preceding edge?
if (hasVertex0)
{
b2Vec2 edge0 = m_v1 - m_v0;
edge0.Normalize();
m_normal0.Set(edge0.y, -edge0.x);
convex1 = b2Cross(edge0, edge1) >= 0.0f;
offset0 = b2Dot(m_normal0, m_centroidB - m_v0);
}
// Is there a following edge?
if (hasVertex3)
{
b2Vec2 edge2 = m_v3 - m_v2;
edge2.Normalize();
m_normal2.Set(edge2.y, -edge2.x);
convex2 = b2Cross(edge1, edge2) > 0.0f;
offset2 = b2Dot(m_normal2, m_centroidB - m_v2);
}
// Determine front or back collision. Determine collision normal limits.
if (hasVertex0 && hasVertex3)
{
if (convex1 && convex2)
{
m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal0;
m_upperLimit = m_normal2;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = -m_normal1;
}
}
else if (convex1)
{
m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal0;
m_upperLimit = m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal2;
m_upperLimit = -m_normal1;
}
}
else if (convex2)
{
m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = m_normal2;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = -m_normal0;
}
}
else
{
m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal2;
m_upperLimit = -m_normal0;
}
}
}
else if (hasVertex0)
{
if (convex1)
{
m_front = offset0 >= 0.0f || offset1 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal0;
m_upperLimit = -m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = -m_normal1;
}
}
else
{
m_front = offset0 >= 0.0f && offset1 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = -m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = -m_normal0;
}
}
}
else if (hasVertex3)
{
if (convex2)
{
m_front = offset1 >= 0.0f || offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = m_normal2;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = m_normal1;
}
}
else
{
m_front = offset1 >= 0.0f && offset2 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = -m_normal2;
m_upperLimit = m_normal1;
}
}
}
else
{
m_front = offset1 >= 0.0f;
if (m_front)
{
m_normal = m_normal1;
m_lowerLimit = -m_normal1;
m_upperLimit = -m_normal1;
}
else
{
m_normal = -m_normal1;
m_lowerLimit = m_normal1;
m_upperLimit = m_normal1;
}
}
// Get polygonB in frameA
m_polygonB.count = polygonB->m_count;
for (int32 i = 0; i < polygonB->m_count; ++i)
{
m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]);
m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]);
}
m_radius = 2.0f * b2_polygonRadius;
manifold->pointCount = 0;
b2EPAxis edgeAxis = ComputeEdgeSeparation();
// If no valid normal can be found than this edge should not collide.
if (edgeAxis.type == b2EPAxis::e_unknown)
{
return;
}
if (edgeAxis.separation > m_radius)
{
return;
}
b2EPAxis polygonAxis = ComputePolygonSeparation();
if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius)
{
return;
}
// Use hysteresis for jitter reduction.
const float32 k_relativeTol = 0.98f;
const float32 k_absoluteTol = 0.001f;
b2EPAxis primaryAxis;
if (polygonAxis.type == b2EPAxis::e_unknown)
{
primaryAxis = edgeAxis;
}
else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
{
primaryAxis = polygonAxis;
}
else
{
primaryAxis = edgeAxis;
}
b2ClipVertex ie[2];
b2ReferenceFace rf;
if (primaryAxis.type == b2EPAxis::e_edgeA)
{
manifold->type = b2Manifold::e_faceA;
// Search for the polygon normal that is most anti-parallel to the edge normal.
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]);
for (int32 i = 1; i < m_polygonB.count; ++i)
{
float32 value = b2Dot(m_normal, m_polygonB.normals[i]);
if (value < bestValue)
{
bestValue = value;
bestIndex = i;
}
}
int32 i1 = bestIndex;
int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0;
ie[0].v = m_polygonB.vertices[i1];
ie[0].id.cf.indexA = 0;
ie[0].id.cf.indexB = static_cast<uint8>(i1);
ie[0].id.cf.typeA = b2ContactFeature::e_face;
ie[0].id.cf.typeB = b2ContactFeature::e_vertex;
ie[1].v = m_polygonB.vertices[i2];
ie[1].id.cf.indexA = 0;
ie[1].id.cf.indexB = static_cast<uint8>(i2);
ie[1].id.cf.typeA = b2ContactFeature::e_face;
ie[1].id.cf.typeB = b2ContactFeature::e_vertex;
if (m_front)
{
rf.i1 = 0;
rf.i2 = 1;
rf.v1 = m_v1;
rf.v2 = m_v2;
rf.normal = m_normal1;
}
else
{
rf.i1 = 1;
rf.i2 = 0;
rf.v1 = m_v2;
rf.v2 = m_v1;
rf.normal = -m_normal1;
}
}
else
{
manifold->type = b2Manifold::e_faceB;
ie[0].v = m_v1;
ie[0].id.cf.indexA = 0;
ie[0].id.cf.indexB = static_cast<uint8>(primaryAxis.index);
ie[0].id.cf.typeA = b2ContactFeature::e_vertex;
ie[0].id.cf.typeB = b2ContactFeature::e_face;
ie[1].v = m_v2;
ie[1].id.cf.indexA = 0;
ie[1].id.cf.indexB = static_cast<uint8>(primaryAxis.index);
ie[1].id.cf.typeA = b2ContactFeature::e_vertex;
ie[1].id.cf.typeB = b2ContactFeature::e_face;
rf.i1 = primaryAxis.index;
rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0;
rf.v1 = m_polygonB.vertices[rf.i1];
rf.v2 = m_polygonB.vertices[rf.i2];
rf.normal = m_polygonB.normals[rf.i1];
}
rf.sideNormal1.Set(rf.normal.y, -rf.normal.x);
rf.sideNormal2 = -rf.sideNormal1;
rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1);
rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2);
// Clip incident edge against extruded edge1 side edges.
b2ClipVertex clipPoints1[2];
b2ClipVertex clipPoints2[2];
int32 np;
// Clip to box side 1
np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1);
if (np < b2_maxManifoldPoints)
{
return;
}
// Clip to negative box side 1
np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);
if (np < b2_maxManifoldPoints)
{
return;
}
// Now clipPoints2 contains the clipped points.
if (primaryAxis.type == b2EPAxis::e_edgeA)
{
manifold->localNormal = rf.normal;
manifold->localPoint = rf.v1;
}
else
{
manifold->localNormal = polygonB->m_normals[rf.i1];
manifold->localPoint = polygonB->m_vertices[rf.i1];
}
int32 pointCount = 0;
for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
{
float32 separation;
separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1);
if (separation <= m_radius)
{
b2ManifoldPoint* cp = manifold->points + pointCount;
if (primaryAxis.type == b2EPAxis::e_edgeA)
{
cp->localPoint = b2MulT(m_xf, clipPoints2[i].v);
cp->id = clipPoints2[i].id;
}
else
{
cp->localPoint = clipPoints2[i].v;
cp->id.cf.typeA = clipPoints2[i].id.cf.typeB;
cp->id.cf.typeB = clipPoints2[i].id.cf.typeA;
cp->id.cf.indexA = clipPoints2[i].id.cf.indexB;
cp->id.cf.indexB = clipPoints2[i].id.cf.indexA;
}
++pointCount;
}
}
manifold->pointCount = pointCount;
}
b2EPAxis b2EPCollider::ComputeEdgeSeparation()
{
b2EPAxis axis;
axis.type = b2EPAxis::e_edgeA;
axis.index = m_front ? 0 : 1;
axis.separation = FLT_MAX;
for (int32 i = 0; i < m_polygonB.count; ++i)
{
float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1);
if (s < axis.separation)
{
axis.separation = s;
}
}
return axis;
}
b2EPAxis b2EPCollider::ComputePolygonSeparation()
{
b2EPAxis axis;
axis.type = b2EPAxis::e_unknown;
axis.index = -1;
axis.separation = -FLT_MAX;
b2Vec2 perp(-m_normal.y, m_normal.x);
for (int32 i = 0; i < m_polygonB.count; ++i)
{
b2Vec2 n = -m_polygonB.normals[i];
float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1);
float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2);
float32 s = b2Min(s1, s2);
if (s > m_radius)
{
// No collision
axis.type = b2EPAxis::e_edgeB;
axis.index = i;
axis.separation = s;
return axis;
}
// Adjacency
if (b2Dot(n, perp) >= 0.0f)
{
if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop)
{
continue;
}
}
else
{
if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop)
{
continue;
}
}
if (s > axis.separation)
{
axis.type = b2EPAxis::e_edgeB;
axis.index = i;
axis.separation = s;
}
}
return axis;
}
void b2CollideEdgeAndPolygon( b2Manifold* manifold,
const b2EdgeShape* edgeA, const b2Transform& xfA,
const b2PolygonShape* polygonB, const b2Transform& xfB)
{
b2EPCollider collider;
collider.Collide(manifold, edgeA, xfA, polygonB, xfB);
}
-141
View File
@@ -1,141 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DISTANCE_H
#define B2_DISTANCE_H
#include <Box2D/Common/b2Math.h>
class b2Shape;
/// A distance proxy is used by the GJK algorithm.
/// It encapsulates any shape.
struct b2DistanceProxy
{
b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {}
/// Initialize the proxy using the given shape. The shape
/// must remain in scope while the proxy is in use.
void Set(const b2Shape* shape, int32 index);
/// Get the supporting vertex index in the given direction.
int32 GetSupport(const b2Vec2& d) const;
/// Get the supporting vertex in the given direction.
const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
/// Get the vertex count.
int32 GetVertexCount() const;
/// Get a vertex by index. Used by b2Distance.
const b2Vec2& GetVertex(int32 index) const;
b2Vec2 m_buffer[2];
const b2Vec2* m_vertices;
int32 m_count;
float32 m_radius;
};
/// Used to warm start b2Distance.
/// Set count to zero on first call.
struct b2SimplexCache
{
float32 metric; ///< length or area
uint16 count;
uint8 indexA[3]; ///< vertices on shape A
uint8 indexB[3]; ///< vertices on shape B
};
/// Input for b2Distance.
/// You have to option to use the shape radii
/// in the computation. Even
struct b2DistanceInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Transform transformA;
b2Transform transformB;
bool useRadii;
};
/// Output for b2Distance.
struct b2DistanceOutput
{
b2Vec2 pointA; ///< closest point on shapeA
b2Vec2 pointB; ///< closest point on shapeB
float32 distance;
int32 iterations; ///< number of GJK iterations used
};
/// Compute the closest points between two shapes. Supports any combination of:
/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.
/// On the first call set b2SimplexCache.count to zero.
void b2Distance(b2DistanceOutput* output,
b2SimplexCache* cache,
const b2DistanceInput* input);
//////////////////////////////////////////////////////////////////////////
inline int32 b2DistanceProxy::GetVertexCount() const
{
return m_count;
}
inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const
{
b2Assert(0 <= index && index < m_count);
return m_vertices[index];
}
inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return bestIndex;
}
inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
{
int32 bestIndex = 0;
float32 bestValue = b2Dot(m_vertices[0], d);
for (int32 i = 1; i < m_count; ++i)
{
float32 value = b2Dot(m_vertices[i], d);
if (value > bestValue)
{
bestIndex = i;
bestValue = value;
}
}
return m_vertices[bestIndex];
}
#endif
@@ -1,58 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TIME_OF_IMPACT_H
#define B2_TIME_OF_IMPACT_H
#include <Box2D/Common/b2Math.h>
#include <Box2D/Collision/b2Distance.h>
/// Input parameters for b2TimeOfImpact
struct b2TOIInput
{
b2DistanceProxy proxyA;
b2DistanceProxy proxyB;
b2Sweep sweepA;
b2Sweep sweepB;
float32 tMax; // defines sweep interval [0, tMax]
};
// Output parameters for b2TimeOfImpact.
struct b2TOIOutput
{
enum State
{
e_unknown,
e_failed,
e_overlapped,
e_touching,
e_separated
};
State state;
float32 t;
};
/// Compute the upper bound on time before two shapes penetrate. Time is represented as
/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
/// non-tunneling collision. If you change the time interval, you should call this function
/// again.
/// Note: use b2Distance to compute the contact point and normal at the time of impact.
void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);
#endif
@@ -1,62 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_BLOCK_ALLOCATOR_H
#define B2_BLOCK_ALLOCATOR_H
#include <Box2D/Common/b2Settings.h>
const int32 b2_chunkSize = 16 * 1024;
const int32 b2_maxBlockSize = 640;
const int32 b2_blockSizes = 14;
const int32 b2_chunkArrayIncrement = 128;
struct b2Block;
struct b2Chunk;
/// This is a small object allocator used for allocating small
/// objects that persist for more than one time step.
/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
class b2BlockAllocator
{
public:
b2BlockAllocator();
~b2BlockAllocator();
/// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize.
void* Allocate(int32 size);
/// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize.
void Free(void* p, int32 size);
void Clear();
private:
b2Chunk* m_chunks;
int32 m_chunkCount;
int32 m_chunkSpace;
b2Block* m_freeLists[b2_blockSizes];
static int32 s_blockSizes[b2_blockSizes];
static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
static bool s_blockSizeLookupInitialized;
};
#endif
-44
View File
@@ -1,44 +0,0 @@
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Common/b2Draw.h>
b2Draw::b2Draw()
{
m_drawFlags = 0;
}
void b2Draw::SetFlags(uint32 flags)
{
m_drawFlags = flags;
}
uint32 b2Draw::GetFlags() const
{
return m_drawFlags;
}
void b2Draw::AppendFlags(uint32 flags)
{
m_drawFlags |= flags;
}
void b2Draw::ClearFlags(uint32 flags)
{
m_drawFlags &= ~flags;
}
-86
View File
@@ -1,86 +0,0 @@
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DRAW_H
#define B2_DRAW_H
#include <Box2D/Common/b2Math.h>
/// Color for debug drawing. Each value has the range [0,1].
struct b2Color
{
b2Color() {}
b2Color(float32 r, float32 g, float32 b, float32 a = 1.0f) : r(r), g(g), b(b), a(a) {}
void Set(float32 ri, float32 gi, float32 bi, float32 ai = 1.0f) { r = ri; g = gi; b = bi; a = ai; }
float32 r, g, b, a;
};
/// Implement and register this class with a b2World to provide debug drawing of physics
/// entities in your game.
class b2Draw
{
public:
b2Draw();
virtual ~b2Draw() {}
enum
{
e_shapeBit = 0x0001, ///< draw shapes
e_jointBit = 0x0002, ///< draw joint connections
e_aabbBit = 0x0004, ///< draw axis aligned bounding boxes
e_pairBit = 0x0008, ///< draw broad-phase pairs
e_centerOfMassBit = 0x0010 ///< draw center of mass frame
};
/// Set the drawing flags.
void SetFlags(uint32 flags);
/// Get the drawing flags.
uint32 GetFlags() const;
/// Append flags to the current flags.
void AppendFlags(uint32 flags);
/// Clear flags from the current flags.
void ClearFlags(uint32 flags);
/// Draw a closed polygon provided in CCW order.
virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a solid closed polygon provided in CCW order.
virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
/// Draw a circle.
virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
/// Draw a solid circle.
virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
/// Draw a line segment.
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
/// Draw a transform. Choose your own length scale.
/// @param xf a transform.
virtual void DrawTransform(const b2Transform& xf) = 0;
protected:
uint32 m_drawFlags;
};
#endif
@@ -1,85 +0,0 @@
/*
* Copyright (c) 2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_GROWABLE_STACK_H
#define B2_GROWABLE_STACK_H
#include <Box2D/Common/b2Settings.h>
#include <string.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
{
public:
b2GrowableStack()
{
m_stack = m_array;
m_count = 0;
m_capacity = N;
}
~b2GrowableStack()
{
if (m_stack != m_array)
{
b2Free(m_stack);
m_stack = NULL;
}
}
void Push(const T& element)
{
if (m_count == m_capacity)
{
T* old = m_stack;
m_capacity *= 2;
m_stack = (T*)b2Alloc(m_capacity * sizeof(T));
memcpy(m_stack, old, m_count * sizeof(T));
if (old != m_array)
{
b2Free(old);
}
}
m_stack[m_count] = element;
++m_count;
}
T Pop()
{
b2Assert(m_count > 0);
--m_count;
return m_stack[m_count];
}
int32 GetCount()
{
return m_count;
}
private:
T* m_stack;
T m_array[N];
int32 m_count;
int32 m_capacity;
};
#endif
-94
View File
@@ -1,94 +0,0 @@
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Common/b2Math.h>
const b2Vec2 b2Vec2_zero(0.0f, 0.0f);
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const
{
float32 det = b2Dot(ex, b2Cross(ey, ez));
if (det != 0.0f)
{
det = 1.0f / det;
}
b2Vec3 x;
x.x = det * b2Dot(b, b2Cross(ey, ez));
x.y = det * b2Dot(ex, b2Cross(b, ez));
x.z = det * b2Dot(ex, b2Cross(ey, b));
return x;
}
/// Solve A * x = b, where b is a column vector. This is more efficient
/// than computing the inverse in one-shot cases.
b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const
{
float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
float32 det = a11 * a22 - a12 * a21;
if (det != 0.0f)
{
det = 1.0f / det;
}
b2Vec2 x;
x.x = det * (a22 * b.x - a12 * b.y);
x.y = det * (a11 * b.y - a21 * b.x);
return x;
}
///
void b2Mat33::GetInverse22(b2Mat33* M) const
{
float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
float32 det = a * d - b * c;
if (det != 0.0f)
{
det = 1.0f / det;
}
M->ex.x = det * d; M->ey.x = -det * b; M->ex.z = 0.0f;
M->ex.y = -det * c; M->ey.y = det * a; M->ey.z = 0.0f;
M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f;
}
/// Returns the zero matrix if singular.
void b2Mat33::GetSymInverse33(b2Mat33* M) const
{
float32 det = b2Dot(ex, b2Cross(ey, ez));
if (det != 0.0f)
{
det = 1.0f / det;
}
float32 a11 = ex.x, a12 = ey.x, a13 = ez.x;
float32 a22 = ey.y, a23 = ez.y;
float32 a33 = ez.z;
M->ex.x = det * (a22 * a33 - a23 * a23);
M->ex.y = det * (a13 * a23 - a12 * a33);
M->ex.z = det * (a12 * a23 - a13 * a22);
M->ey.x = M->ex.y;
M->ey.y = det * (a11 * a33 - a13 * a13);
M->ey.z = det * (a13 * a12 - a11 * a23);
M->ez.x = M->ex.z;
M->ez.y = M->ey.z;
M->ez.z = det * (a11 * a22 - a12 * a12);
}
-52
View File
@@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Common/b2Settings.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "common/Exception.h"
b2Version b2_version = {2, 3, 2};
// Memory allocators. Modify these to use your own allocator.
void* b2Alloc(int32 size)
{
return malloc(size);
}
void b2Free(void* mem)
{
free(mem);
}
// You can modify this to use your logging facility.
void b2Log(const char* string, ...)
{
va_list args;
va_start(args, string);
vprintf(string, args);
va_end(args);
}
void loveAssert(bool test, const char *teststr)
{
if (!test)
throw love::Exception("Box2D assertion failed: %s", teststr);
}
@@ -1,83 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Common/b2StackAllocator.h>
#include <Box2D/Common/b2Math.h>
b2StackAllocator::b2StackAllocator()
{
m_index = 0;
m_allocation = 0;
m_maxAllocation = 0;
m_entryCount = 0;
}
b2StackAllocator::~b2StackAllocator()
{
b2Assert(m_index == 0);
b2Assert(m_entryCount == 0);
}
void* b2StackAllocator::Allocate(int32 size)
{
b2Assert(m_entryCount < b2_maxStackEntries);
b2StackEntry* entry = m_entries + m_entryCount;
entry->size = size;
if (m_index + size > b2_stackSize)
{
entry->data = (char*)b2Alloc(size);
entry->usedMalloc = true;
}
else
{
entry->data = m_data + m_index;
entry->usedMalloc = false;
m_index += size;
}
m_allocation += size;
m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
++m_entryCount;
return entry->data;
}
void b2StackAllocator::Free(void* p)
{
b2Assert(m_entryCount > 0);
b2StackEntry* entry = m_entries + m_entryCount - 1;
b2Assert(p == entry->data);
if (entry->usedMalloc)
{
b2Free(p);
}
else
{
m_index -= entry->size;
}
m_allocation -= entry->size;
--m_entryCount;
p = NULL;
}
int32 b2StackAllocator::GetMaxAllocation() const
{
return m_maxAllocation;
}
@@ -1,60 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_STACK_ALLOCATOR_H
#define B2_STACK_ALLOCATOR_H
#include <Box2D/Common/b2Settings.h>
const int32 b2_stackSize = 100 * 1024; // 100k
const int32 b2_maxStackEntries = 32;
struct b2StackEntry
{
char* data;
int32 size;
bool usedMalloc;
};
// This is a stack allocator used for fast per step allocations.
// You must nest allocate/free pairs. The code will assert
// if you try to interleave multiple allocate/free pairs.
class b2StackAllocator
{
public:
b2StackAllocator();
~b2StackAllocator();
void* Allocate(int32 size);
void Free(void* p);
int32 GetMaxAllocation() const;
private:
char m_data[b2_stackSize];
int32 m_index;
int32 m_allocation;
int32 m_maxAllocation;
b2StackEntry m_entries[b2_maxStackEntries];
int32 m_entryCount;
};
#endif
-101
View File
@@ -1,101 +0,0 @@
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Common/b2Timer.h>
#if defined(_WIN32)
float64 b2Timer::s_invFrequency = 0.0f;
#define WIN32_LEAN_AND_MEAN
#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()
{
LARGE_INTEGER largeInteger;
QueryPerformanceCounter(&largeInteger);
m_start = float64(largeInteger.QuadPart);
}
float32 b2Timer::GetMilliseconds() const
{
LARGE_INTEGER largeInteger;
QueryPerformanceCounter(&largeInteger);
float64 count = float64(largeInteger.QuadPart);
float32 ms = float32(s_invFrequency * (count - m_start));
return ms;
}
#elif defined(__linux__) || defined (__APPLE__)
#include <sys/time.h>
b2Timer::b2Timer()
{
Reset();
}
void b2Timer::Reset()
{
timeval t;
gettimeofday(&t, 0);
m_start_sec = t.tv_sec;
m_start_usec = t.tv_usec;
}
float32 b2Timer::GetMilliseconds() const
{
timeval t;
gettimeofday(&t, 0);
return 1000.0f * (t.tv_sec - m_start_sec) + 0.001f * (t.tv_usec - m_start_usec);
}
#else
b2Timer::b2Timer()
{
}
void b2Timer::Reset()
{
}
float32 b2Timer::GetMilliseconds() const
{
return 0.0f;
}
#endif
-50
View File
@@ -1,50 +0,0 @@
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_TIMER_H
#define B2_TIMER_H
#include <Box2D/Common/b2Settings.h>
/// Timer for profiling. This has platform specific code and may
/// not work on every platform.
class b2Timer
{
public:
/// Constructor
b2Timer();
/// Reset the timer.
void Reset();
/// Get the time since construction or the last reset.
float32 GetMilliseconds() const;
private:
#if defined(_WIN32)
float64 m_start;
static float64 s_invFrequency;
#elif defined(__linux__) || defined (__APPLE__)
unsigned long m_start_sec;
unsigned long m_start_usec;
#endif
};
#endif
@@ -1,53 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Contacts/b2ChainAndCircleContact.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <Box2D/Collision/Shapes/b2ChainShape.h>
#include <Box2D/Collision/Shapes/b2EdgeShape.h>
#include <new>
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);
}
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CHAIN_AND_CIRCLE_CONTACT_H
#define B2_CHAIN_AND_CIRCLE_CONTACT_H
#include <Box2D/Dynamics/Contacts/b2Contact.h>
class b2BlockAllocator;
class b2ChainAndCircleContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2ChainAndCircleContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
~b2ChainAndCircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
@@ -1,53 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Contacts/b2ChainAndPolygonContact.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <Box2D/Collision/Shapes/b2ChainShape.h>
#include <Box2D/Collision/Shapes/b2EdgeShape.h>
#include <new>
b2Contact* b2ChainAndPolygonContact::Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2ChainAndPolygonContact));
return new (mem) b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB);
}
void b2ChainAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2ChainAndPolygonContact*)contact)->~b2ChainAndPolygonContact();
allocator->Free(contact, sizeof(b2ChainAndPolygonContact));
}
b2ChainAndPolygonContact::b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB)
: b2Contact(fixtureA, indexA, fixtureB, indexB)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_chain);
b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
}
void b2ChainAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2ChainShape* chain = (b2ChainShape*)m_fixtureA->GetShape();
b2EdgeShape edge;
chain->GetChildEdge(&edge, m_indexA);
b2CollideEdgeAndPolygon( manifold, &edge, xfA,
(b2PolygonShape*)m_fixtureB->GetShape(), xfB);
}
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CHAIN_AND_POLYGON_CONTACT_H
#define B2_CHAIN_AND_POLYGON_CONTACT_H
#include <Box2D/Dynamics/Contacts/b2Contact.h>
class b2BlockAllocator;
class b2ChainAndPolygonContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2ChainAndPolygonContact(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB);
~b2ChainAndPolygonContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
@@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Contacts/b2CircleContact.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <Box2D/Dynamics/b2WorldCallbacks.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <Box2D/Collision/b2TimeOfImpact.h>
#include <new>
b2Contact* b2CircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2CircleContact));
return new (mem) b2CircleContact(fixtureA, fixtureB);
}
void b2CircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2CircleContact*)contact)->~b2CircleContact();
allocator->Free(contact, sizeof(b2CircleContact));
}
b2CircleContact::b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_circle);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2CircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollideCircles(manifold,
(b2CircleShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CIRCLE_CONTACT_H
#define B2_CIRCLE_CONTACT_H
#include <Box2D/Dynamics/Contacts/b2Contact.h>
class b2BlockAllocator;
class b2CircleContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2CircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2CircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
@@ -1,95 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_SOLVER_H
#define B2_CONTACT_SOLVER_H
#include <Box2D/Common/b2Math.h>
#include <Box2D/Collision/b2Collision.h>
#include <Box2D/Dynamics/b2TimeStep.h>
class b2Contact;
class b2Body;
class b2StackAllocator;
struct b2ContactPositionConstraint;
struct b2VelocityConstraintPoint
{
b2Vec2 rA;
b2Vec2 rB;
float32 normalImpulse;
float32 tangentImpulse;
float32 normalMass;
float32 tangentMass;
float32 velocityBias;
};
struct b2ContactVelocityConstraint
{
b2VelocityConstraintPoint points[b2_maxManifoldPoints];
b2Vec2 normal;
b2Mat22 normalMass;
b2Mat22 K;
int32 indexA;
int32 indexB;
float32 invMassA, invMassB;
float32 invIA, invIB;
float32 friction;
float32 restitution;
float32 tangentSpeed;
int32 pointCount;
int32 contactIndex;
};
struct b2ContactSolverDef
{
b2TimeStep step;
b2Contact** contacts;
int32 count;
b2Position* positions;
b2Velocity* velocities;
b2StackAllocator* allocator;
};
class b2ContactSolver
{
public:
b2ContactSolver(b2ContactSolverDef* def);
~b2ContactSolver();
void InitializeVelocityConstraints();
void WarmStart();
void SolveVelocityConstraints();
void StoreImpulses();
bool SolvePositionConstraints();
bool SolveTOIPositionConstraints(int32 toiIndexA, int32 toiIndexB);
b2TimeStep m_step;
b2Position* m_positions;
b2Velocity* m_velocities;
b2StackAllocator* m_allocator;
b2ContactPositionConstraint* m_positionConstraints;
b2ContactVelocityConstraint* m_velocityConstraints;
b2Contact** m_contacts;
int m_count;
};
#endif
@@ -1,49 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Contacts/b2EdgeAndCircleContact.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <new>
b2Contact* b2EdgeAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2EdgeAndCircleContact));
return new (mem) b2EdgeAndCircleContact(fixtureA, fixtureB);
}
void b2EdgeAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2EdgeAndCircleContact*)contact)->~b2EdgeAndCircleContact();
allocator->Free(contact, sizeof(b2EdgeAndCircleContact));
}
b2EdgeAndCircleContact::b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_edge);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2EdgeAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollideEdgeAndCircle( manifold,
(b2EdgeShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_EDGE_AND_CIRCLE_CONTACT_H
#define B2_EDGE_AND_CIRCLE_CONTACT_H
#include <Box2D/Dynamics/Contacts/b2Contact.h>
class b2BlockAllocator;
class b2EdgeAndCircleContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2EdgeAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2EdgeAndCircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
@@ -1,49 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Contacts/b2EdgeAndPolygonContact.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <new>
b2Contact* b2EdgeAndPolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2EdgeAndPolygonContact));
return new (mem) b2EdgeAndPolygonContact(fixtureA, fixtureB);
}
void b2EdgeAndPolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2EdgeAndPolygonContact*)contact)->~b2EdgeAndPolygonContact();
allocator->Free(contact, sizeof(b2EdgeAndPolygonContact));
}
b2EdgeAndPolygonContact::b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_edge);
b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
}
void b2EdgeAndPolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollideEdgeAndPolygon( manifold,
(b2EdgeShape*)m_fixtureA->GetShape(), xfA,
(b2PolygonShape*)m_fixtureB->GetShape(), xfB);
}
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_EDGE_AND_POLYGON_CONTACT_H
#define B2_EDGE_AND_POLYGON_CONTACT_H
#include <Box2D/Dynamics/Contacts/b2Contact.h>
class b2BlockAllocator;
class b2EdgeAndPolygonContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2EdgeAndPolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2EdgeAndPolygonContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
@@ -1,49 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Contacts/b2PolygonAndCircleContact.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <new>
b2Contact* b2PolygonAndCircleContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2PolygonAndCircleContact));
return new (mem) b2PolygonAndCircleContact(fixtureA, fixtureB);
}
void b2PolygonAndCircleContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2PolygonAndCircleContact*)contact)->~b2PolygonAndCircleContact();
allocator->Free(contact, sizeof(b2PolygonAndCircleContact));
}
b2PolygonAndCircleContact::b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
b2Assert(m_fixtureB->GetType() == b2Shape::e_circle);
}
void b2PolygonAndCircleContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollidePolygonAndCircle( manifold,
(b2PolygonShape*)m_fixtureA->GetShape(), xfA,
(b2CircleShape*)m_fixtureB->GetShape(), xfB);
}
@@ -1,38 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_AND_CIRCLE_CONTACT_H
#define B2_POLYGON_AND_CIRCLE_CONTACT_H
#include <Box2D/Dynamics/Contacts/b2Contact.h>
class b2BlockAllocator;
class b2PolygonAndCircleContact : public b2Contact
{
public:
static b2Contact* Create(b2Fixture* fixtureA, int32 indexA, b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2PolygonAndCircleContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2PolygonAndCircleContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
@@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Contacts/b2PolygonContact.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <Box2D/Collision/b2TimeOfImpact.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2Fixture.h>
#include <Box2D/Dynamics/b2WorldCallbacks.h>
#include <new>
b2Contact* b2PolygonContact::Create(b2Fixture* fixtureA, int32, b2Fixture* fixtureB, int32, b2BlockAllocator* allocator)
{
void* mem = allocator->Allocate(sizeof(b2PolygonContact));
return new (mem) b2PolygonContact(fixtureA, fixtureB);
}
void b2PolygonContact::Destroy(b2Contact* contact, b2BlockAllocator* allocator)
{
((b2PolygonContact*)contact)->~b2PolygonContact();
allocator->Free(contact, sizeof(b2PolygonContact));
}
b2PolygonContact::b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB)
: b2Contact(fixtureA, 0, fixtureB, 0)
{
b2Assert(m_fixtureA->GetType() == b2Shape::e_polygon);
b2Assert(m_fixtureB->GetType() == b2Shape::e_polygon);
}
void b2PolygonContact::Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB)
{
b2CollidePolygons( manifold,
(b2PolygonShape*)m_fixtureA->GetShape(), xfA,
(b2PolygonShape*)m_fixtureB->GetShape(), xfB);
}
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_POLYGON_CONTACT_H
#define B2_POLYGON_CONTACT_H
#include <Box2D/Dynamics/Contacts/b2Contact.h>
class b2BlockAllocator;
class b2PolygonContact : public b2Contact
{
public:
static b2Contact* Create( b2Fixture* fixtureA, int32 indexA,
b2Fixture* fixtureB, int32 indexB, b2BlockAllocator* allocator);
static void Destroy(b2Contact* contact, b2BlockAllocator* allocator);
b2PolygonContact(b2Fixture* fixtureA, b2Fixture* fixtureB);
~b2PolygonContact() {}
void Evaluate(b2Manifold* manifold, const b2Transform& xfA, const b2Transform& xfB);
};
#endif
@@ -1,260 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2TimeStep.h>
// 1-D constrained system
// m (v2 - v1) = lambda
// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
// x2 = x1 + h * v2
// 1-D mass-damper-spring system
// m (v2 - v1) + h * d * v2 + h * k *
// C = norm(p2 - p1) - L
// u = (p2 - p1) / norm(p2 - p1)
// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
// J = [-u -cross(r1, u) u cross(r2, u)]
// K = J * invM * JT
// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
const b2Vec2& anchor1, const b2Vec2& anchor2)
{
bodyA = b1;
bodyB = b2;
localAnchorA = bodyA->GetLocalPoint(anchor1);
localAnchorB = bodyB->GetLocalPoint(anchor2);
b2Vec2 d = anchor2 - anchor1;
length = d.Length();
}
b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_length = def->length;
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_impulse = 0.0f;
m_gamma = 0.0f;
m_bias = 0.0f;
}
void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
m_u = cB + m_rB - cA - m_rA;
// Handle singularity.
float32 length = m_u.Length();
if (length > b2_linearSlop)
{
m_u *= 1.0f / length;
}
else
{
m_u.Set(0.0f, 0.0f);
}
float32 crAu = b2Cross(m_rA, m_u);
float32 crBu = b2Cross(m_rB, m_u);
float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;
// Compute the effective mass matrix.
m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
if (m_frequencyHz > 0.0f)
{
float32 C = length - m_length;
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * m_mass * m_dampingRatio * omega;
// Spring stiffness
float32 k = m_mass * omega * omega;
// magic formulas
float32 h = data.step.dt;
m_gamma = h * (d + h * k);
m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
m_bias = C * h * k * m_gamma;
invMass += m_gamma;
m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
}
else
{
m_gamma = 0.0f;
m_bias = 0.0f;
}
if (data.step.warmStarting)
{
// Scale the impulse to support a variable time step.
m_impulse *= data.step.dtRatio;
b2Vec2 P = m_impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
}
else
{
m_impulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
// Cdot = dot(u, v + cross(w, r))
b2Vec2 vpA = vA + b2Cross(wA, m_rA);
b2Vec2 vpB = vB + b2Cross(wB, m_rB);
float32 Cdot = b2Dot(m_u, vpB - vpA);
float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
m_impulse += impulse;
b2Vec2 P = impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data)
{
if (m_frequencyHz > 0.0f)
{
// There is no position correction for soft distance constraints.
return true;
}
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 u = cB + rB - cA - rA;
float32 length = u.Normalize();
float32 C = length - m_length;
C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
float32 impulse = -m_mass * C;
b2Vec2 P = impulse * u;
cA -= m_invMassA * P;
aA -= m_invIA * b2Cross(rA, P);
cB += m_invMassB * P;
aB += m_invIB * b2Cross(rB, P);
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return b2Abs(C) < b2_linearSlop;
}
b2Vec2 b2DistanceJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2DistanceJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 F = (inv_dt * m_impulse) * m_u;
return F;
}
float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}
void b2DistanceJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2DistanceJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.length = %.15lef;\n", m_length);
b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
@@ -1,169 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_DISTANCE_JOINT_H
#define B2_DISTANCE_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Distance joint definition. This requires defining an
/// anchor point on both bodies and the non-zero length of the
/// distance joint. The definition uses local anchor points
/// so that the initial configuration can violate the constraint
/// slightly. This helps when saving and loading a game.
/// @warning Do not use a zero or short length.
struct b2DistanceJointDef : public b2JointDef
{
b2DistanceJointDef()
{
type = e_distanceJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
length = 1.0f;
frequencyHz = 0.0f;
dampingRatio = 0.0f;
}
/// Initialize the bodies, anchors, and length using the world
/// anchors.
void Initialize(b2Body* bodyA, b2Body* bodyB,
const b2Vec2& anchorA, const b2Vec2& anchorB);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The natural length between the anchor points.
float32 length;
/// The mass-spring-damper frequency in Hertz. A value of 0
/// disables softness.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A distance joint constrains two points on two bodies
/// to remain at a fixed distance from each other. You can view
/// this as a massless, rigid rod.
class b2DistanceJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
/// Get the reaction force given the inverse time step.
/// Unit is N.
b2Vec2 GetReactionForce(float32 inv_dt) const;
/// Get the reaction torque given the inverse time step.
/// Unit is N*m. This is always zero for a distance joint.
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Set/get the natural length.
/// Manipulating the length can lead to non-physical behavior when the frequency is zero.
void SetLength(float32 length);
float32 GetLength() const;
/// Set/get frequency in Hz.
void SetFrequency(float32 hz);
float32 GetFrequency() const;
/// Set/get damping ratio.
void SetDampingRatio(float32 ratio);
float32 GetDampingRatio() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2DistanceJoint(const b2DistanceJointDef* data);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_bias;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_gamma;
float32 m_impulse;
float32 m_length;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_u;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
float32 m_mass;
};
inline void b2DistanceJoint::SetLength(float32 length)
{
m_length = length;
}
inline float32 b2DistanceJoint::GetLength() const
{
return m_length;
}
inline void b2DistanceJoint::SetFrequency(float32 hz)
{
m_frequencyHz = hz;
}
inline float32 b2DistanceJoint::GetFrequency() const
{
return m_frequencyHz;
}
inline void b2DistanceJoint::SetDampingRatio(float32 ratio)
{
m_dampingRatio = ratio;
}
inline float32 b2DistanceJoint::GetDampingRatio() const
{
return m_dampingRatio;
}
#endif
@@ -1,119 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_FRICTION_JOINT_H
#define B2_FRICTION_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Friction joint definition.
struct b2FrictionJointDef : public b2JointDef
{
b2FrictionJointDef()
{
type = e_frictionJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
maxForce = 0.0f;
maxTorque = 0.0f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The maximum friction force in N.
float32 maxForce;
/// The maximum friction torque in N-m.
float32 maxTorque;
};
/// Friction joint. This is used for top-down friction.
/// It provides 2D translational friction and angular friction.
class b2FrictionJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Set the maximum friction force in N.
void SetMaxForce(float32 force);
/// Get the maximum friction force in N.
float32 GetMaxForce() const;
/// Set the maximum friction torque in N*m.
void SetMaxTorque(float32 torque);
/// Get the maximum friction torque in N*m.
float32 GetMaxTorque() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2FrictionJoint(const b2FrictionJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
// Solver shared
b2Vec2 m_linearImpulse;
float32 m_angularImpulse;
float32 m_maxForce;
float32 m_maxTorque;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Mat22 m_linearMass;
float32 m_angularMass;
};
#endif
@@ -1,125 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_GEAR_JOINT_H
#define B2_GEAR_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Gear joint definition. This definition requires two existing
/// revolute or prismatic joints (any combination will work).
struct b2GearJointDef : public b2JointDef
{
b2GearJointDef()
{
type = e_gearJoint;
joint1 = NULL;
joint2 = NULL;
ratio = 1.0f;
}
/// The first revolute/prismatic joint attached to the gear joint.
b2Joint* joint1;
/// The second revolute/prismatic joint attached to the gear joint.
b2Joint* joint2;
/// The gear ratio.
/// @see b2GearJoint for explanation.
float32 ratio;
};
/// A gear joint is used to connect two joints together. Either joint
/// can be a revolute or prismatic joint. You specify a gear ratio
/// to bind the motions together:
/// coordinate1 + ratio * coordinate2 = constant
/// The ratio can be negative or positive. If one joint is a revolute joint
/// and the other joint is a prismatic joint, then the ratio will have units
/// of length or units of 1/length.
/// @warning You have to manually destroy the gear joint if joint1 or joint2
/// is destroyed.
class b2GearJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Get the first joint.
b2Joint* GetJoint1() { return m_joint1; }
/// Get the second joint.
b2Joint* GetJoint2() { return m_joint2; }
/// Set/Get the gear ratio.
void SetRatio(float32 ratio);
float32 GetRatio() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2GearJoint(const b2GearJointDef* data);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
b2Joint* m_joint1;
b2Joint* m_joint2;
b2JointType m_typeA;
b2JointType m_typeB;
// Body A is connected to body C
// Body B is connected to body D
b2Body* m_bodyC;
b2Body* m_bodyD;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localAnchorC;
b2Vec2 m_localAnchorD;
b2Vec2 m_localAxisC;
b2Vec2 m_localAxisD;
float32 m_referenceAngleA;
float32 m_referenceAngleB;
float32 m_constant;
float32 m_ratio;
float32 m_impulse;
// Solver temp
int32 m_indexA, m_indexB, m_indexC, m_indexD;
b2Vec2 m_lcA, m_lcB, m_lcC, m_lcD;
float32 m_mA, m_mB, m_mC, m_mD;
float32 m_iA, m_iB, m_iC, m_iD;
b2Vec2 m_JvAC, m_JvBD;
float32 m_JwA, m_JwB, m_JwC, m_JwD;
float32 m_mass;
};
#endif
@@ -1,211 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Joints/b2Joint.h>
#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
#include <Box2D/Dynamics/Joints/b2MouseJoint.h>
#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
#include <Box2D/Dynamics/Joints/b2GearJoint.h>
#include <Box2D/Dynamics/Joints/b2WeldJoint.h>
#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>
#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
#include <Box2D/Dynamics/Joints/b2MotorJoint.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2World.h>
#include <Box2D/Common/b2BlockAllocator.h>
#include <new>
b2Joint* b2Joint::Create(const b2JointDef* def, b2BlockAllocator* allocator)
{
b2Joint* joint = NULL;
switch (def->type)
{
case e_distanceJoint:
{
void* mem = allocator->Allocate(sizeof(b2DistanceJoint));
joint = new (mem) b2DistanceJoint(static_cast<const b2DistanceJointDef*>(def));
}
break;
case e_mouseJoint:
{
void* mem = allocator->Allocate(sizeof(b2MouseJoint));
joint = new (mem) b2MouseJoint(static_cast<const b2MouseJointDef*>(def));
}
break;
case e_prismaticJoint:
{
void* mem = allocator->Allocate(sizeof(b2PrismaticJoint));
joint = new (mem) b2PrismaticJoint(static_cast<const b2PrismaticJointDef*>(def));
}
break;
case e_revoluteJoint:
{
void* mem = allocator->Allocate(sizeof(b2RevoluteJoint));
joint = new (mem) b2RevoluteJoint(static_cast<const b2RevoluteJointDef*>(def));
}
break;
case e_pulleyJoint:
{
void* mem = allocator->Allocate(sizeof(b2PulleyJoint));
joint = new (mem) b2PulleyJoint(static_cast<const b2PulleyJointDef*>(def));
}
break;
case e_gearJoint:
{
void* mem = allocator->Allocate(sizeof(b2GearJoint));
joint = new (mem) b2GearJoint(static_cast<const b2GearJointDef*>(def));
}
break;
case e_wheelJoint:
{
void* mem = allocator->Allocate(sizeof(b2WheelJoint));
joint = new (mem) b2WheelJoint(static_cast<const b2WheelJointDef*>(def));
}
break;
case e_weldJoint:
{
void* mem = allocator->Allocate(sizeof(b2WeldJoint));
joint = new (mem) b2WeldJoint(static_cast<const b2WeldJointDef*>(def));
}
break;
case e_frictionJoint:
{
void* mem = allocator->Allocate(sizeof(b2FrictionJoint));
joint = new (mem) b2FrictionJoint(static_cast<const b2FrictionJointDef*>(def));
}
break;
case e_ropeJoint:
{
void* mem = allocator->Allocate(sizeof(b2RopeJoint));
joint = new (mem) b2RopeJoint(static_cast<const b2RopeJointDef*>(def));
}
break;
case e_motorJoint:
{
void* mem = allocator->Allocate(sizeof(b2MotorJoint));
joint = new (mem) b2MotorJoint(static_cast<const b2MotorJointDef*>(def));
}
break;
default:
b2Assert(false);
break;
}
return joint;
}
void b2Joint::Destroy(b2Joint* joint, b2BlockAllocator* allocator)
{
joint->~b2Joint();
switch (joint->m_type)
{
case e_distanceJoint:
allocator->Free(joint, sizeof(b2DistanceJoint));
break;
case e_mouseJoint:
allocator->Free(joint, sizeof(b2MouseJoint));
break;
case e_prismaticJoint:
allocator->Free(joint, sizeof(b2PrismaticJoint));
break;
case e_revoluteJoint:
allocator->Free(joint, sizeof(b2RevoluteJoint));
break;
case e_pulleyJoint:
allocator->Free(joint, sizeof(b2PulleyJoint));
break;
case e_gearJoint:
allocator->Free(joint, sizeof(b2GearJoint));
break;
case e_wheelJoint:
allocator->Free(joint, sizeof(b2WheelJoint));
break;
case e_weldJoint:
allocator->Free(joint, sizeof(b2WeldJoint));
break;
case e_frictionJoint:
allocator->Free(joint, sizeof(b2FrictionJoint));
break;
case e_ropeJoint:
allocator->Free(joint, sizeof(b2RopeJoint));
break;
case e_motorJoint:
allocator->Free(joint, sizeof(b2MotorJoint));
break;
default:
b2Assert(false);
break;
}
}
b2Joint::b2Joint(const b2JointDef* def)
{
b2Assert(def->bodyA != def->bodyB);
m_type = def->type;
m_prev = NULL;
m_next = NULL;
m_bodyA = def->bodyA;
m_bodyB = def->bodyB;
m_index = 0;
m_collideConnected = def->collideConnected;
m_islandFlag = false;
m_userData = def->userData;
m_edgeA.joint = NULL;
m_edgeA.other = NULL;
m_edgeA.prev = NULL;
m_edgeA.next = NULL;
m_edgeB.joint = NULL;
m_edgeB.other = NULL;
m_edgeB.prev = NULL;
m_edgeB.next = NULL;
}
bool b2Joint::IsActive() const
{
return m_bodyA->IsActive() && m_bodyB->IsActive();
}
@@ -1,133 +0,0 @@
/*
* Copyright (c) 2006-2012 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_MOTOR_JOINT_H
#define B2_MOTOR_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Motor joint definition.
struct b2MotorJointDef : public b2JointDef
{
b2MotorJointDef()
{
type = e_motorJoint;
linearOffset.SetZero();
angularOffset = 0.0f;
maxForce = 1.0f;
maxTorque = 1.0f;
correctionFactor = 0.3f;
}
/// Initialize the bodies and offsets using the current transforms.
void Initialize(b2Body* bodyA, b2Body* bodyB);
/// Position of bodyB minus the position of bodyA, in bodyA's frame, in meters.
b2Vec2 linearOffset;
/// The bodyB angle minus bodyA angle in radians.
float32 angularOffset;
/// The maximum motor force in N.
float32 maxForce;
/// The maximum motor torque in N-m.
float32 maxTorque;
/// Position correction factor in the range [0,1].
float32 correctionFactor;
};
/// A motor joint is used to control the relative motion
/// between two bodies. A typical usage is to control the movement
/// of a dynamic body with respect to the ground.
class b2MotorJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// Set/get the target linear offset, in frame A, in meters.
void SetLinearOffset(const b2Vec2& linearOffset);
const b2Vec2& GetLinearOffset() const;
/// Set/get the target angular offset, in radians.
void SetAngularOffset(float32 angularOffset);
float32 GetAngularOffset() const;
/// Set the maximum friction force in N.
void SetMaxForce(float32 force);
/// Get the maximum friction force in N.
float32 GetMaxForce() const;
/// Set the maximum friction torque in N*m.
void SetMaxTorque(float32 torque);
/// Get the maximum friction torque in N*m.
float32 GetMaxTorque() const;
/// Set the position correction factor in the range [0,1].
void SetCorrectionFactor(float32 factor);
/// Get the position correction factor in the range [0,1].
float32 GetCorrectionFactor() const;
/// Dump to b2Log
void Dump();
protected:
friend class b2Joint;
b2MotorJoint(const b2MotorJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
// Solver shared
b2Vec2 m_linearOffset;
float32 m_angularOffset;
b2Vec2 m_linearImpulse;
float32 m_angularImpulse;
float32 m_maxForce;
float32 m_maxTorque;
float32 m_correctionFactor;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
b2Vec2 m_linearError;
float32 m_angularError;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Mat22 m_linearMass;
float32 m_angularMass;
};
#endif
@@ -1,129 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_MOUSE_JOINT_H
#define B2_MOUSE_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Mouse joint definition. This requires a world target point,
/// tuning parameters, and the time step.
struct b2MouseJointDef : public b2JointDef
{
b2MouseJointDef()
{
type = e_mouseJoint;
target.Set(0.0f, 0.0f);
maxForce = 0.0f;
frequencyHz = 5.0f;
dampingRatio = 0.7f;
}
/// The initial world target point. This is assumed
/// to coincide with the body anchor initially.
b2Vec2 target;
/// The maximum constraint force that can be exerted
/// to move the candidate body. Usually you will express
/// as some multiple of the weight (multiplier * mass * gravity).
float32 maxForce;
/// The response speed.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A mouse joint is used to make a point on a body track a
/// specified world point. This a soft constraint with a maximum
/// force. This allows the constraint to stretch and without
/// applying huge forces.
/// NOTE: this joint is not documented in the manual because it was
/// developed to be used in the testbed. If you want to learn how to
/// use the mouse joint, look at the testbed.
class b2MouseJoint : public b2Joint
{
public:
/// Implements b2Joint.
b2Vec2 GetAnchorA() const;
/// Implements b2Joint.
b2Vec2 GetAnchorB() const;
/// Implements b2Joint.
b2Vec2 GetReactionForce(float32 inv_dt) const;
/// Implements b2Joint.
float32 GetReactionTorque(float32 inv_dt) const;
/// Use this to update the target point.
void SetTarget(const b2Vec2& target);
const b2Vec2& GetTarget() const;
/// Set/get the maximum force in Newtons.
void SetMaxForce(float32 force);
float32 GetMaxForce() const;
/// Set/get the frequency in Hertz.
void SetFrequency(float32 hz);
float32 GetFrequency() const;
/// Set/get the damping ratio (dimensionless).
void SetDampingRatio(float32 ratio);
float32 GetDampingRatio() const;
/// The mouse joint does not support dumping.
void Dump() { b2Log("Mouse joint dumping is not supported.\n"); }
/// Implement b2Joint::ShiftOrigin
void ShiftOrigin(const b2Vec2& newOrigin);
protected:
friend class b2Joint;
b2MouseJoint(const b2MouseJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
b2Vec2 m_localAnchorB;
b2Vec2 m_targetA;
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_beta;
// Solver shared
b2Vec2 m_impulse;
float32 m_maxForce;
float32 m_gamma;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rB;
b2Vec2 m_localCenterB;
float32 m_invMassB;
float32 m_invIB;
b2Mat22 m_mass;
b2Vec2 m_C;
};
#endif
@@ -1,629 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2TimeStep.h>
// Linear constraint (point-to-line)
// d = p2 - p1 = x2 + r2 - x1 - r1
// C = dot(perp, d)
// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
//
// Angular constraint
// C = a2 - a1 + a_initial
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
//
// K = J * invM * JT
//
// J = [-a -s1 a s2]
// [0 -1 0 1]
// a = perp
// s1 = cross(d + r1, a) = cross(p2 - x1, a)
// s2 = cross(r2, a) = cross(p2 - x2, a)
// Motor/Limit linear constraint
// C = dot(ax1, d)
// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
// Block Solver
// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
// when the mass has poor distribution (leading to large torques about the joint anchor points).
//
// The Jacobian has 3 rows:
// J = [-uT -s1 uT s2] // linear
// [0 -1 0 1] // angular
// [-vT -a1 vT a2] // limit
//
// u = perp
// v = axis
// s1 = cross(d + r1, u), s2 = cross(r2, u)
// a1 = cross(d + r1, v), a2 = cross(r2, v)
// M * (v2 - v1) = JT * df
// J * v2 = bias
//
// v2 = v1 + invM * JT * df
// J * (v1 + invM * JT * df) = bias
// K * df = bias - J * v1 = -Cdot
// K = J * invM * JT
// Cdot = J * v1 - bias
//
// Now solve for f2.
// df = f2 - f1
// K * (f2 - f1) = -Cdot
// f2 = invK * (-Cdot) + f1
//
// Clamp accumulated limit impulse.
// lower: f2(3) = max(f2(3), 0)
// upper: f2(3) = min(f2(3), 0)
//
// Solve for correct f2(1:2)
// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1
// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)
// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)
// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
//
// Now compute impulse to be applied:
// df = f2 - f1
void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
localAxisA = bodyA->GetLocalVector(axis);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_localXAxisA = def->localAxisA;
m_localXAxisA.Normalize();
m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
m_referenceAngle = def->referenceAngle;
m_impulse.SetZero();
m_motorMass = 0.0f;
m_motorImpulse = 0.0f;
m_lowerTranslation = def->lowerTranslation;
m_upperTranslation = def->upperTranslation;
m_maxMotorForce = def->maxMotorForce;
m_motorSpeed = def->motorSpeed;
m_enableLimit = def->enableLimit;
m_enableMotor = def->enableMotor;
m_limitState = e_inactiveLimit;
m_axis.SetZero();
m_perp.SetZero();
}
void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
// Compute the effective masses.
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = (cB - cA) + rB - rA;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
// Compute motor Jacobian and effective mass.
{
m_axis = b2Mul(qA, m_localXAxisA);
m_a1 = b2Cross(d + rA, m_axis);
m_a2 = b2Cross(rB, m_axis);
m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
if (m_motorMass > 0.0f)
{
m_motorMass = 1.0f / m_motorMass;
}
}
// Prismatic constraint.
{
m_perp = b2Mul(qA, m_localYAxisA);
m_s1 = b2Cross(d + rA, m_perp);
m_s2 = b2Cross(rB, m_perp);
float32 s1test;
s1test = b2Cross(rA, m_perp);
float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2;
float32 k12 = iA * m_s1 + iB * m_s2;
float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2;
float32 k22 = iA + iB;
if (k22 == 0.0f)
{
// For bodies with fixed rotation.
k22 = 1.0f;
}
float32 k23 = iA * m_a1 + iB * m_a2;
float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
m_K.ex.Set(k11, k12, k13);
m_K.ey.Set(k12, k22, k23);
m_K.ez.Set(k13, k23, k33);
}
// Compute motor and limit terms.
if (m_enableLimit)
{
float32 jointTranslation = b2Dot(m_axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
m_limitState = e_equalLimits;
}
else if (jointTranslation <= m_lowerTranslation)
{
if (m_limitState != e_atLowerLimit)
{
m_limitState = e_atLowerLimit;
m_impulse.z = 0.0f;
}
}
else if (jointTranslation >= m_upperTranslation)
{
if (m_limitState != e_atUpperLimit)
{
m_limitState = e_atUpperLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
if (m_enableMotor == false)
{
m_motorImpulse = 0.0f;
}
if (data.step.warmStarting)
{
// Account for variable time step.
m_impulse *= data.step.dtRatio;
m_motorImpulse *= data.step.dtRatio;
b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis;
float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1;
float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
else
{
m_impulse.SetZero();
m_motorImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
// Solve linear motor constraint.
if (m_enableMotor && m_limitState != e_equalLimits)
{
float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
float32 impulse = m_motorMass * (m_motorSpeed - Cdot);
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = data.step.dt * m_maxMotorForce;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
b2Vec2 P = impulse * m_axis;
float32 LA = impulse * m_a1;
float32 LB = impulse * m_a2;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
b2Vec2 Cdot1;
Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA;
Cdot1.y = wB - wA;
if (m_enableLimit && m_limitState != e_inactiveLimit)
{
// Solve prismatic and limit constraint in block form.
float32 Cdot2;
Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 f1 = m_impulse;
b2Vec3 df = m_K.Solve33(-Cdot);
m_impulse += df;
if (m_limitState == e_atLowerLimit)
{
m_impulse.z = b2Max(m_impulse.z, 0.0f);
}
else if (m_limitState == e_atUpperLimit)
{
m_impulse.z = b2Min(m_impulse.z, 0.0f);
}
// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y);
b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y);
m_impulse.x = f2r.x;
m_impulse.y = f2r.y;
df = m_impulse - f1;
b2Vec2 P = df.x * m_perp + df.z * m_axis;
float32 LA = df.x * m_s1 + df.y + df.z * m_a1;
float32 LB = df.x * m_s2 + df.y + df.z * m_a2;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
else
{
// Limit is inactive, just solve the prismatic constraint in block form.
b2Vec2 df = m_K.Solve22(-Cdot1);
m_impulse.x += df.x;
m_impulse.y += df.y;
b2Vec2 P = df.x * m_perp;
float32 LA = df.x * m_s1 + df.y;
float32 LB = df.x * m_s2 + df.y;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
// Compute fresh Jacobians
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = cB + rB - cA - rA;
b2Vec2 axis = b2Mul(qA, m_localXAxisA);
float32 a1 = b2Cross(d + rA, axis);
float32 a2 = b2Cross(rB, axis);
b2Vec2 perp = b2Mul(qA, m_localYAxisA);
float32 s1 = b2Cross(d + rA, perp);
float32 s2 = b2Cross(rB, perp);
b2Vec3 impulse;
b2Vec2 C1;
C1.x = b2Dot(perp, d);
C1.y = aB - aA - m_referenceAngle;
float32 linearError = b2Abs(C1.x);
float32 angularError = b2Abs(C1.y);
bool active = false;
float32 C2 = 0.0f;
if (m_enableLimit)
{
float32 translation = b2Dot(axis, d);
if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
{
// Prevent large angular corrections
C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
linearError = b2Max(linearError, b2Abs(translation));
active = true;
}
else if (translation <= m_lowerTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
linearError = b2Max(linearError, m_lowerTranslation - translation);
active = true;
}
else if (translation >= m_upperTranslation)
{
// Prevent large linear corrections and allow some slop.
C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
linearError = b2Max(linearError, translation - m_upperTranslation);
active = true;
}
}
if (active)
{
float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
float32 k12 = iA * s1 + iB * s2;
float32 k13 = iA * s1 * a1 + iB * s2 * a2;
float32 k22 = iA + iB;
if (k22 == 0.0f)
{
// For fixed rotation
k22 = 1.0f;
}
float32 k23 = iA * a1 + iB * a2;
float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;
b2Mat33 K;
K.ex.Set(k11, k12, k13);
K.ey.Set(k12, k22, k23);
K.ez.Set(k13, k23, k33);
b2Vec3 C;
C.x = C1.x;
C.y = C1.y;
C.z = C2;
impulse = K.Solve33(-C);
}
else
{
float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
float32 k12 = iA * s1 + iB * s2;
float32 k22 = iA + iB;
if (k22 == 0.0f)
{
k22 = 1.0f;
}
b2Mat22 K;
K.ex.Set(k11, k12);
K.ey.Set(k12, k22);
b2Vec2 impulse1 = K.Solve(-C1);
impulse.x = impulse1.x;
impulse.y = impulse1.y;
impulse.z = 0.0f;
}
b2Vec2 P = impulse.x * perp + impulse.z * axis;
float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1;
float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2;
cA -= mA * P;
aA -= iA * LA;
cB += mB * P;
aB += iB * LB;
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return linearError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2PrismaticJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2PrismaticJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis);
}
float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.y;
}
float32 b2PrismaticJoint::GetJointTranslation() const
{
b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA);
b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB);
b2Vec2 d = pB - pA;
b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA);
float32 translation = b2Dot(d, axis);
return translation;
}
float32 b2PrismaticJoint::GetJointSpeed() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter);
b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter);
b2Vec2 p1 = bA->m_sweep.c + rA;
b2Vec2 p2 = bB->m_sweep.c + rB;
b2Vec2 d = p2 - p1;
b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA);
b2Vec2 vA = bA->m_linearVelocity;
b2Vec2 vB = bB->m_linearVelocity;
float32 wA = bA->m_angularVelocity;
float32 wB = bB->m_angularVelocity;
float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA));
return speed;
}
bool b2PrismaticJoint::IsLimitEnabled() const
{
return m_enableLimit;
}
void b2PrismaticJoint::EnableLimit(bool flag)
{
if (flag != m_enableLimit)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableLimit = flag;
m_impulse.z = 0.0f;
}
}
float32 b2PrismaticJoint::GetLowerLimit() const
{
return m_lowerTranslation;
}
float32 b2PrismaticJoint::GetUpperLimit() const
{
return m_upperTranslation;
}
void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)
{
b2Assert(lower <= upper);
if (lower != m_lowerTranslation || upper != m_upperTranslation)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_lowerTranslation = lower;
m_upperTranslation = upper;
m_impulse.z = 0.0f;
}
}
bool b2PrismaticJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2PrismaticJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
void b2PrismaticJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2PrismaticJoint::SetMaxMotorForce(float32 force)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorForce = force;
}
float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
void b2PrismaticJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2PrismaticJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation);
b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation);
b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
@@ -1,502 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2TimeStep.h>
// Point-to-point constraint
// C = p2 - p1
// Cdot = v2 - v1
// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
// J = [-I -r1_skew I r2_skew ]
// Identity used:
// w k % (rx i + ry j) = w * (-ry i + rx j)
// Motor constraint
// Cdot = w2 - w1
// J = [0 0 -1 0 0 1]
// K = invI1 + invI2
void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
}
b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_referenceAngle = def->referenceAngle;
m_impulse.SetZero();
m_motorImpulse = 0.0f;
m_lowerAngle = def->lowerAngle;
m_upperAngle = def->upperAngle;
m_maxMotorTorque = def->maxMotorTorque;
m_motorSpeed = def->motorSpeed;
m_enableLimit = def->enableLimit;
m_enableMotor = def->enableMotor;
m_limitState = e_inactiveLimit;
}
void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
// r_skew = [-ry; rx]
// Matlab
// K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
// [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
// [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
bool fixedRotation = (iA + iB == 0.0f);
m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB;
m_mass.ex.y = m_mass.ey.x;
m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
m_mass.ez.y = m_rA.x * iA + m_rB.x * iB;
m_mass.ex.z = m_mass.ez.x;
m_mass.ey.z = m_mass.ez.y;
m_mass.ez.z = iA + iB;
m_motorMass = iA + iB;
if (m_motorMass > 0.0f)
{
m_motorMass = 1.0f / m_motorMass;
}
if (m_enableMotor == false || fixedRotation)
{
m_motorImpulse = 0.0f;
}
if (m_enableLimit && fixedRotation == false)
{
float32 jointAngle = aB - aA - m_referenceAngle;
if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop)
{
m_limitState = e_equalLimits;
}
else if (jointAngle <= m_lowerAngle)
{
if (m_limitState != e_atLowerLimit)
{
m_impulse.z = 0.0f;
}
m_limitState = e_atLowerLimit;
}
else if (jointAngle >= m_upperAngle)
{
if (m_limitState != e_atUpperLimit)
{
m_impulse.z = 0.0f;
}
m_limitState = e_atUpperLimit;
}
else
{
m_limitState = e_inactiveLimit;
m_impulse.z = 0.0f;
}
}
else
{
m_limitState = e_inactiveLimit;
}
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
m_impulse *= data.step.dtRatio;
m_motorImpulse *= data.step.dtRatio;
b2Vec2 P(m_impulse.x, m_impulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z);
}
else
{
m_impulse.SetZero();
m_motorImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
bool fixedRotation = (iA + iB == 0.0f);
// Solve motor constraint.
if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false)
{
float32 Cdot = wB - wA - m_motorSpeed;
float32 impulse = -m_motorMass * Cdot;
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = data.step.dt * m_maxMotorTorque;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
wA -= iA * impulse;
wB += iB * impulse;
}
// Solve limit constraint.
if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
{
b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
float32 Cdot2 = wB - wA;
b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
b2Vec3 impulse = -m_mass.Solve33(Cdot);
if (m_limitState == e_equalLimits)
{
m_impulse += impulse;
}
else if (m_limitState == e_atLowerLimit)
{
float32 newImpulse = m_impulse.z + impulse.z;
if (newImpulse < 0.0f)
{
b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
b2Vec2 reduced = m_mass.Solve22(rhs);
impulse.x = reduced.x;
impulse.y = reduced.y;
impulse.z = -m_impulse.z;
m_impulse.x += reduced.x;
m_impulse.y += reduced.y;
m_impulse.z = 0.0f;
}
else
{
m_impulse += impulse;
}
}
else if (m_limitState == e_atUpperLimit)
{
float32 newImpulse = m_impulse.z + impulse.z;
if (newImpulse > 0.0f)
{
b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
b2Vec2 reduced = m_mass.Solve22(rhs);
impulse.x = reduced.x;
impulse.y = reduced.y;
impulse.z = -m_impulse.z;
m_impulse.x += reduced.x;
m_impulse.y += reduced.y;
m_impulse.z = 0.0f;
}
else
{
m_impulse += impulse;
}
}
b2Vec2 P(impulse.x, impulse.y);
vA -= mA * P;
wA -= iA * (b2Cross(m_rA, P) + impulse.z);
vB += mB * P;
wB += iB * (b2Cross(m_rB, P) + impulse.z);
}
else
{
// Solve point-to-point constraint
b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
b2Vec2 impulse = m_mass.Solve22(-Cdot);
m_impulse.x += impulse.x;
m_impulse.y += impulse.y;
vA -= mA * impulse;
wA -= iA * b2Cross(m_rA, impulse);
vB += mB * impulse;
wB += iB * b2Cross(m_rB, impulse);
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
float32 angularError = 0.0f;
float32 positionError = 0.0f;
bool fixedRotation = (m_invIA + m_invIB == 0.0f);
// Solve angular limit constraint.
if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
{
float32 angle = aB - aA - m_referenceAngle;
float32 limitImpulse = 0.0f;
if (m_limitState == e_equalLimits)
{
// Prevent large angular corrections
float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
limitImpulse = -m_motorMass * C;
angularError = b2Abs(C);
}
else if (m_limitState == e_atLowerLimit)
{
float32 C = angle - m_lowerAngle;
angularError = -C;
// Prevent large angular corrections and allow some slop.
C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);
limitImpulse = -m_motorMass * C;
}
else if (m_limitState == e_atUpperLimit)
{
float32 C = angle - m_upperAngle;
angularError = C;
// Prevent large angular corrections and allow some slop.
C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection);
limitImpulse = -m_motorMass * C;
}
aA -= m_invIA * limitImpulse;
aB += m_invIB * limitImpulse;
}
// Solve point-to-point constraint.
{
qA.Set(aA);
qB.Set(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 C = cB + rB - cA - rA;
positionError = C.Length();
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Mat22 K;
K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
K.ey.x = K.ex.y;
K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;
b2Vec2 impulse = -K.Solve(C);
cA -= mA * impulse;
aA -= iA * b2Cross(rA, impulse);
cB += mB * impulse;
aB += iB * b2Cross(rB, impulse);
}
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
}
b2Vec2 b2RevoluteJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2RevoluteJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 P(m_impulse.x, m_impulse.y);
return inv_dt * P;
}
float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_impulse.z;
}
float32 b2RevoluteJoint::GetJointAngle() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;
}
float32 b2RevoluteJoint::GetJointSpeed() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
return bB->m_angularVelocity - bA->m_angularVelocity;
}
bool b2RevoluteJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2RevoluteJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
void b2RevoluteJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorTorque = torque;
}
bool b2RevoluteJoint::IsLimitEnabled() const
{
return m_enableLimit;
}
void b2RevoluteJoint::EnableLimit(bool flag)
{
if (flag != m_enableLimit)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableLimit = flag;
m_impulse.z = 0.0f;
}
}
float32 b2RevoluteJoint::GetLowerLimit() const
{
return m_lowerAngle;
}
float32 b2RevoluteJoint::GetUpperLimit() const
{
return m_upperAngle;
}
void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)
{
b2Assert(lower <= upper);
if (lower != m_lowerAngle || upper != m_upperAngle)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_impulse.z = 0.0f;
m_lowerAngle = lower;
m_upperAngle = upper;
}
}
void b2RevoluteJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2RevoluteJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle);
b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle);
b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
@@ -1,241 +0,0 @@
/*
* Copyright (c) 2007-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2TimeStep.h>
// Limit:
// C = norm(pB - pA) - L
// u = (pB - pA) / norm(pB - pA)
// Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA))
// J = [-u -cross(rA, u) u cross(rB, u)]
// K = J * invM * JT
// = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2
b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_maxLength = def->maxLength;
m_mass = 0.0f;
m_impulse = 0.0f;
m_state = e_inactiveLimit;
m_length = 0.0f;
}
void b2RopeJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
m_u = cB + m_rB - cA - m_rA;
m_length = m_u.Length();
float32 C = m_length - m_maxLength;
if (C > 0.0f)
{
m_state = e_atUpperLimit;
}
else
{
m_state = e_inactiveLimit;
}
if (m_length > b2_linearSlop)
{
m_u *= 1.0f / m_length;
}
else
{
m_u.SetZero();
m_mass = 0.0f;
m_impulse = 0.0f;
return;
}
// Compute effective mass.
float32 crA = b2Cross(m_rA, m_u);
float32 crB = b2Cross(m_rB, m_u);
float32 invMass = m_invMassA + m_invIA * crA * crA + m_invMassB + m_invIB * crB * crB;
m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
if (data.step.warmStarting)
{
// Scale the impulse to support a variable time step.
m_impulse *= data.step.dtRatio;
b2Vec2 P = m_impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
}
else
{
m_impulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2RopeJoint::SolveVelocityConstraints(const b2SolverData& data)
{
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
// Cdot = dot(u, v + cross(w, r))
b2Vec2 vpA = vA + b2Cross(wA, m_rA);
b2Vec2 vpB = vB + b2Cross(wB, m_rB);
float32 C = m_length - m_maxLength;
float32 Cdot = b2Dot(m_u, vpB - vpA);
// Predictive constraint.
if (C < 0.0f)
{
Cdot += data.step.inv_dt * C;
}
float32 impulse = -m_mass * Cdot;
float32 oldImpulse = m_impulse;
m_impulse = b2Min(0.0f, m_impulse + impulse);
impulse = m_impulse - oldImpulse;
b2Vec2 P = impulse * m_u;
vA -= m_invMassA * P;
wA -= m_invIA * b2Cross(m_rA, P);
vB += m_invMassB * P;
wB += m_invIB * b2Cross(m_rB, P);
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2RopeJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 u = cB + rB - cA - rA;
float32 length = u.Normalize();
float32 C = length - m_maxLength;
C = b2Clamp(C, 0.0f, b2_maxLinearCorrection);
float32 impulse = -m_mass * C;
b2Vec2 P = impulse * u;
cA -= m_invMassA * P;
aA -= m_invIA * b2Cross(rA, P);
cB += m_invMassB * P;
aB += m_invIB * b2Cross(rB, P);
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return length - m_maxLength < b2_linearSlop;
}
b2Vec2 b2RopeJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2RopeJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2RopeJoint::GetReactionForce(float32 inv_dt) const
{
b2Vec2 F = (inv_dt * m_impulse) * m_u;
return F;
}
float32 b2RopeJoint::GetReactionTorque(float32 inv_dt) const
{
B2_NOT_USED(inv_dt);
return 0.0f;
}
float32 b2RopeJoint::GetMaxLength() const
{
return m_maxLength;
}
b2LimitState b2RopeJoint::GetLimitState() const
{
return m_state;
}
void b2RopeJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2RopeJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.maxLength = %.15lef;\n", m_maxLength);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
@@ -1,114 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_ROPE_JOINT_H
#define B2_ROPE_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Rope joint definition. This requires two body anchor points and
/// a maximum lengths.
/// Note: by default the connected objects will not collide.
/// see collideConnected in b2JointDef.
struct b2RopeJointDef : public b2JointDef
{
b2RopeJointDef()
{
type = e_ropeJoint;
localAnchorA.Set(-1.0f, 0.0f);
localAnchorB.Set(1.0f, 0.0f);
maxLength = 0.0f;
}
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The maximum length of the rope.
/// Warning: this must be larger than b2_linearSlop or
/// the joint will have no effect.
float32 maxLength;
};
/// A rope joint enforces a maximum distance between two points
/// on two bodies. It has no other effect.
/// Warning: if you attempt to change the maximum length during
/// the simulation you will get some non-physical behavior.
/// A model that would allow you to dynamically modify the length
/// would have some sponginess, so I chose not to implement it
/// that way. See b2DistanceJoint if you want to dynamically
/// control length.
class b2RopeJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Set/Get the maximum length of the rope.
void SetMaxLength(float32 length) { m_maxLength = length; }
float32 GetMaxLength() const;
b2LimitState GetLimitState() const;
/// Dump joint to dmLog
void Dump();
protected:
friend class b2Joint;
b2RopeJoint(const b2RopeJointDef* data);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_maxLength;
float32 m_length;
float32 m_impulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_u;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
float32 m_mass;
b2LimitState m_state;
};
#endif
@@ -1,126 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_WELD_JOINT_H
#define B2_WELD_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Weld joint definition. You need to specify local anchor points
/// where they are attached and the relative body angle. The position
/// of the anchor points is important for computing the reaction torque.
struct b2WeldJointDef : public b2JointDef
{
b2WeldJointDef()
{
type = e_weldJoint;
localAnchorA.Set(0.0f, 0.0f);
localAnchorB.Set(0.0f, 0.0f);
referenceAngle = 0.0f;
frequencyHz = 0.0f;
dampingRatio = 0.0f;
}
/// Initialize the bodies, anchors, and reference angle using a world
/// anchor point.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The bodyB angle minus bodyA angle in the reference state (radians).
float32 referenceAngle;
/// The mass-spring-damper frequency in Hertz. Rotation only.
/// Disable softness with a value of 0.
float32 frequencyHz;
/// The damping ratio. 0 = no damping, 1 = critical damping.
float32 dampingRatio;
};
/// A weld joint essentially glues two bodies together. A weld joint may
/// distort somewhat because the island constraint solver is approximate.
class b2WeldJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// Get the reference angle.
float32 GetReferenceAngle() const { return m_referenceAngle; }
/// Set/get frequency in Hz.
void SetFrequency(float32 hz) { m_frequencyHz = hz; }
float32 GetFrequency() const { return m_frequencyHz; }
/// Set/get damping ratio.
void SetDampingRatio(float32 ratio) { m_dampingRatio = ratio; }
float32 GetDampingRatio() const { return m_dampingRatio; }
/// Dump to b2Log
void Dump();
protected:
friend class b2Joint;
b2WeldJoint(const b2WeldJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
float32 m_frequencyHz;
float32 m_dampingRatio;
float32 m_bias;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
float32 m_referenceAngle;
float32 m_gamma;
b2Vec3 m_impulse;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_rA;
b2Vec2 m_rB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Mat33 m_mass;
};
#endif
@@ -1,419 +0,0 @@
/*
* Copyright (c) 2006-2007 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
#include <Box2D/Dynamics/b2Body.h>
#include <Box2D/Dynamics/b2TimeStep.h>
// Linear constraint (point-to-line)
// d = pB - pA = xB + rB - xA - rA
// C = dot(ay, d)
// Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA))
// = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB)
// J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)]
// Spring linear constraint
// C = dot(ax, d)
// Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB)
// J = [-ax -cross(d+rA, ax) ax cross(rB, ax)]
// Motor rotational constraint
// Cdot = wB - wA
// J = [0 0 -1 0 0 1]
void b2WheelJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
{
bodyA = bA;
bodyB = bB;
localAnchorA = bodyA->GetLocalPoint(anchor);
localAnchorB = bodyB->GetLocalPoint(anchor);
localAxisA = bodyA->GetLocalVector(axis);
}
b2WheelJoint::b2WheelJoint(const b2WheelJointDef* def)
: b2Joint(def)
{
m_localAnchorA = def->localAnchorA;
m_localAnchorB = def->localAnchorB;
m_localXAxisA = def->localAxisA;
m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
m_mass = 0.0f;
m_impulse = 0.0f;
m_motorMass = 0.0f;
m_motorImpulse = 0.0f;
m_springMass = 0.0f;
m_springImpulse = 0.0f;
m_maxMotorTorque = def->maxMotorTorque;
m_motorSpeed = def->motorSpeed;
m_enableMotor = def->enableMotor;
m_frequencyHz = def->frequencyHz;
m_dampingRatio = def->dampingRatio;
m_bias = 0.0f;
m_gamma = 0.0f;
m_ax.SetZero();
m_ay.SetZero();
}
void b2WheelJoint::InitVelocityConstraints(const b2SolverData& data)
{
m_indexA = m_bodyA->m_islandIndex;
m_indexB = m_bodyB->m_islandIndex;
m_localCenterA = m_bodyA->m_sweep.localCenter;
m_localCenterB = m_bodyB->m_sweep.localCenter;
m_invMassA = m_bodyA->m_invMass;
m_invMassB = m_bodyB->m_invMass;
m_invIA = m_bodyA->m_invI;
m_invIB = m_bodyB->m_invI;
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
b2Rot qA(aA), qB(aB);
// Compute the effective masses.
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = cB + rB - cA - rA;
// Point to line constraint
{
m_ay = b2Mul(qA, m_localYAxisA);
m_sAy = b2Cross(d + rA, m_ay);
m_sBy = b2Cross(rB, m_ay);
m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy;
if (m_mass > 0.0f)
{
m_mass = 1.0f / m_mass;
}
}
// Spring constraint
m_springMass = 0.0f;
m_bias = 0.0f;
m_gamma = 0.0f;
if (m_frequencyHz > 0.0f)
{
m_ax = b2Mul(qA, m_localXAxisA);
m_sAx = b2Cross(d + rA, m_ax);
m_sBx = b2Cross(rB, m_ax);
float32 invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx;
if (invMass > 0.0f)
{
m_springMass = 1.0f / invMass;
float32 C = b2Dot(d, m_ax);
// Frequency
float32 omega = 2.0f * b2_pi * m_frequencyHz;
// Damping coefficient
float32 d = 2.0f * m_springMass * m_dampingRatio * omega;
// Spring stiffness
float32 k = m_springMass * omega * omega;
// magic formulas
float32 h = data.step.dt;
m_gamma = h * (d + h * k);
if (m_gamma > 0.0f)
{
m_gamma = 1.0f / m_gamma;
}
m_bias = C * h * k * m_gamma;
m_springMass = invMass + m_gamma;
if (m_springMass > 0.0f)
{
m_springMass = 1.0f / m_springMass;
}
}
}
else
{
m_springImpulse = 0.0f;
}
// Rotational motor
if (m_enableMotor)
{
m_motorMass = iA + iB;
if (m_motorMass > 0.0f)
{
m_motorMass = 1.0f / m_motorMass;
}
}
else
{
m_motorMass = 0.0f;
m_motorImpulse = 0.0f;
}
if (data.step.warmStarting)
{
// Account for variable time step.
m_impulse *= data.step.dtRatio;
m_springImpulse *= data.step.dtRatio;
m_motorImpulse *= data.step.dtRatio;
b2Vec2 P = m_impulse * m_ay + m_springImpulse * m_ax;
float32 LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse;
float32 LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse;
vA -= m_invMassA * P;
wA -= m_invIA * LA;
vB += m_invMassB * P;
wB += m_invIB * LB;
}
else
{
m_impulse = 0.0f;
m_springImpulse = 0.0f;
m_motorImpulse = 0.0f;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
void b2WheelJoint::SolveVelocityConstraints(const b2SolverData& data)
{
float32 mA = m_invMassA, mB = m_invMassB;
float32 iA = m_invIA, iB = m_invIB;
b2Vec2 vA = data.velocities[m_indexA].v;
float32 wA = data.velocities[m_indexA].w;
b2Vec2 vB = data.velocities[m_indexB].v;
float32 wB = data.velocities[m_indexB].w;
// Solve spring constraint
{
float32 Cdot = b2Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA;
float32 impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse);
m_springImpulse += impulse;
b2Vec2 P = impulse * m_ax;
float32 LA = impulse * m_sAx;
float32 LB = impulse * m_sBx;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
// Solve rotational motor constraint
{
float32 Cdot = wB - wA - m_motorSpeed;
float32 impulse = -m_motorMass * Cdot;
float32 oldImpulse = m_motorImpulse;
float32 maxImpulse = data.step.dt * m_maxMotorTorque;
m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
impulse = m_motorImpulse - oldImpulse;
wA -= iA * impulse;
wB += iB * impulse;
}
// Solve point to line constraint
{
float32 Cdot = b2Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA;
float32 impulse = -m_mass * Cdot;
m_impulse += impulse;
b2Vec2 P = impulse * m_ay;
float32 LA = impulse * m_sAy;
float32 LB = impulse * m_sBy;
vA -= mA * P;
wA -= iA * LA;
vB += mB * P;
wB += iB * LB;
}
data.velocities[m_indexA].v = vA;
data.velocities[m_indexA].w = wA;
data.velocities[m_indexB].v = vB;
data.velocities[m_indexB].w = wB;
}
bool b2WheelJoint::SolvePositionConstraints(const b2SolverData& data)
{
b2Vec2 cA = data.positions[m_indexA].c;
float32 aA = data.positions[m_indexA].a;
b2Vec2 cB = data.positions[m_indexB].c;
float32 aB = data.positions[m_indexB].a;
b2Rot qA(aA), qB(aB);
b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
b2Vec2 d = (cB - cA) + rB - rA;
b2Vec2 ay = b2Mul(qA, m_localYAxisA);
float32 sAy = b2Cross(d + rA, ay);
float32 sBy = b2Cross(rB, ay);
float32 C = b2Dot(d, ay);
float32 k = m_invMassA + m_invMassB + m_invIA * m_sAy * m_sAy + m_invIB * m_sBy * m_sBy;
float32 impulse;
if (k != 0.0f)
{
impulse = - C / k;
}
else
{
impulse = 0.0f;
}
b2Vec2 P = impulse * ay;
float32 LA = impulse * sAy;
float32 LB = impulse * sBy;
cA -= m_invMassA * P;
aA -= m_invIA * LA;
cB += m_invMassB * P;
aB += m_invIB * LB;
data.positions[m_indexA].c = cA;
data.positions[m_indexA].a = aA;
data.positions[m_indexB].c = cB;
data.positions[m_indexB].a = aB;
return b2Abs(C) <= b2_linearSlop;
}
b2Vec2 b2WheelJoint::GetAnchorA() const
{
return m_bodyA->GetWorldPoint(m_localAnchorA);
}
b2Vec2 b2WheelJoint::GetAnchorB() const
{
return m_bodyB->GetWorldPoint(m_localAnchorB);
}
b2Vec2 b2WheelJoint::GetReactionForce(float32 inv_dt) const
{
return inv_dt * (m_impulse * m_ay + m_springImpulse * m_ax);
}
float32 b2WheelJoint::GetReactionTorque(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
float32 b2WheelJoint::GetJointTranslation() const
{
b2Body* bA = m_bodyA;
b2Body* bB = m_bodyB;
b2Vec2 pA = bA->GetWorldPoint(m_localAnchorA);
b2Vec2 pB = bB->GetWorldPoint(m_localAnchorB);
b2Vec2 d = pB - pA;
b2Vec2 axis = bA->GetWorldVector(m_localXAxisA);
float32 translation = b2Dot(d, axis);
return translation;
}
float32 b2WheelJoint::GetJointSpeed() const
{
float32 wA = m_bodyA->m_angularVelocity;
float32 wB = m_bodyB->m_angularVelocity;
return wB - wA;
}
bool b2WheelJoint::IsMotorEnabled() const
{
return m_enableMotor;
}
void b2WheelJoint::EnableMotor(bool flag)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_enableMotor = flag;
}
void b2WheelJoint::SetMotorSpeed(float32 speed)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_motorSpeed = speed;
}
void b2WheelJoint::SetMaxMotorTorque(float32 torque)
{
m_bodyA->SetAwake(true);
m_bodyB->SetAwake(true);
m_maxMotorTorque = torque;
}
float32 b2WheelJoint::GetMotorTorque(float32 inv_dt) const
{
return inv_dt * m_motorImpulse;
}
void b2WheelJoint::Dump()
{
int32 indexA = m_bodyA->m_islandIndex;
int32 indexB = m_bodyB->m_islandIndex;
b2Log(" b2WheelJointDef jd;\n");
b2Log(" jd.bodyA = bodies[%d];\n", indexA);
b2Log(" jd.bodyB = bodies[%d];\n", indexB);
b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz);
b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio);
b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
}
@@ -1,210 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_WHEEL_JOINT_H
#define B2_WHEEL_JOINT_H
#include <Box2D/Dynamics/Joints/b2Joint.h>
/// Wheel joint definition. This requires defining a line of
/// motion using an axis and an anchor point. The definition uses local
/// anchor points and a local axis so that the initial configuration
/// can violate the constraint slightly. The joint translation is zero
/// when the local anchor points coincide in world space. Using local
/// anchors and a local axis helps when saving and loading a game.
struct b2WheelJointDef : public b2JointDef
{
b2WheelJointDef()
{
type = e_wheelJoint;
localAnchorA.SetZero();
localAnchorB.SetZero();
localAxisA.Set(1.0f, 0.0f);
enableMotor = false;
maxMotorTorque = 0.0f;
motorSpeed = 0.0f;
frequencyHz = 2.0f;
dampingRatio = 0.7f;
}
/// Initialize the bodies, anchors, axis, and reference angle using the world
/// anchor and world axis.
void Initialize(b2Body* bodyA, b2Body* bodyB, const b2Vec2& anchor, const b2Vec2& axis);
/// The local anchor point relative to bodyA's origin.
b2Vec2 localAnchorA;
/// The local anchor point relative to bodyB's origin.
b2Vec2 localAnchorB;
/// The local translation axis in bodyA.
b2Vec2 localAxisA;
/// Enable/disable the joint motor.
bool enableMotor;
/// The maximum motor torque, usually in N-m.
float32 maxMotorTorque;
/// The desired motor speed in radians per second.
float32 motorSpeed;
/// Suspension frequency, zero indicates no suspension
float32 frequencyHz;
/// Suspension damping ratio, one indicates critical damping
float32 dampingRatio;
};
/// A wheel joint. This joint provides two degrees of freedom: translation
/// along an axis fixed in bodyA and rotation in the plane. In other words, it is a point to
/// line constraint with a rotational motor and a linear spring/damper.
/// This joint is designed for vehicle suspensions.
class b2WheelJoint : public b2Joint
{
public:
b2Vec2 GetAnchorA() const;
b2Vec2 GetAnchorB() const;
b2Vec2 GetReactionForce(float32 inv_dt) const;
float32 GetReactionTorque(float32 inv_dt) const;
/// The local anchor point relative to bodyA's origin.
const b2Vec2& GetLocalAnchorA() const { return m_localAnchorA; }
/// The local anchor point relative to bodyB's origin.
const b2Vec2& GetLocalAnchorB() const { return m_localAnchorB; }
/// The local joint axis relative to bodyA.
const b2Vec2& GetLocalAxisA() const { return m_localXAxisA; }
/// Get the current joint translation, usually in meters.
float32 GetJointTranslation() const;
/// Get the current joint translation speed, usually in meters per second.
float32 GetJointSpeed() const;
/// Is the joint motor enabled?
bool IsMotorEnabled() const;
/// Enable/disable the joint motor.
void EnableMotor(bool flag);
/// Set the motor speed, usually in radians per second.
void SetMotorSpeed(float32 speed);
/// Get the motor speed, usually in radians per second.
float32 GetMotorSpeed() const;
/// Set/Get the maximum motor force, usually in N-m.
void SetMaxMotorTorque(float32 torque);
float32 GetMaxMotorTorque() const;
/// Get the current motor torque given the inverse time step, usually in N-m.
float32 GetMotorTorque(float32 inv_dt) const;
/// Set/Get the spring frequency in hertz. Setting the frequency to zero disables the spring.
void SetSpringFrequencyHz(float32 hz);
float32 GetSpringFrequencyHz() const;
/// Set/Get the spring damping ratio
void SetSpringDampingRatio(float32 ratio);
float32 GetSpringDampingRatio() const;
/// Dump to b2Log
void Dump();
protected:
friend class b2Joint;
b2WheelJoint(const b2WheelJointDef* def);
void InitVelocityConstraints(const b2SolverData& data);
void SolveVelocityConstraints(const b2SolverData& data);
bool SolvePositionConstraints(const b2SolverData& data);
float32 m_frequencyHz;
float32 m_dampingRatio;
// Solver shared
b2Vec2 m_localAnchorA;
b2Vec2 m_localAnchorB;
b2Vec2 m_localXAxisA;
b2Vec2 m_localYAxisA;
float32 m_impulse;
float32 m_motorImpulse;
float32 m_springImpulse;
float32 m_maxMotorTorque;
float32 m_motorSpeed;
bool m_enableMotor;
// Solver temp
int32 m_indexA;
int32 m_indexB;
b2Vec2 m_localCenterA;
b2Vec2 m_localCenterB;
float32 m_invMassA;
float32 m_invMassB;
float32 m_invIA;
float32 m_invIB;
b2Vec2 m_ax, m_ay;
float32 m_sAx, m_sBx;
float32 m_sAy, m_sBy;
float32 m_mass;
float32 m_motorMass;
float32 m_springMass;
float32 m_bias;
float32 m_gamma;
};
inline float32 b2WheelJoint::GetMotorSpeed() const
{
return m_motorSpeed;
}
inline float32 b2WheelJoint::GetMaxMotorTorque() const
{
return m_maxMotorTorque;
}
inline void b2WheelJoint::SetSpringFrequencyHz(float32 hz)
{
m_frequencyHz = hz;
}
inline float32 b2WheelJoint::GetSpringFrequencyHz() const
{
return m_frequencyHz;
}
inline void b2WheelJoint::SetSpringDampingRatio(float32 ratio)
{
m_dampingRatio = ratio;
}
inline float32 b2WheelJoint::GetSpringDampingRatio() const
{
return m_dampingRatio;
}
#endif
@@ -1,52 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef B2_CONTACT_MANAGER_H
#define B2_CONTACT_MANAGER_H
#include <Box2D/Collision/b2BroadPhase.h>
class b2Contact;
class b2ContactFilter;
class b2ContactListener;
class b2BlockAllocator;
// Delegate of b2World.
class b2ContactManager
{
public:
b2ContactManager();
// Broad-phase callback.
void AddPair(void* proxyUserDataA, void* proxyUserDataB);
void FindNewContacts();
void Destroy(b2Contact* c);
void Collide();
b2BroadPhase m_broadPhase;
b2Contact* m_contactList;
int32 m_contactCount;
b2ContactFilter* m_contactFilter;
b2ContactListener* m_contactListener;
b2BlockAllocator* m_allocator;
};
#endif

Some files were not shown because too many files have changed in this diff Show More