├── doc
├── powered-by-lua.gif
├── Makefile
├── collisionhandler.adoc
├── toolbox.adoc
├── index.adoc
├── preface.adoc
├── introduction.adoc
├── arbiter.adoc
├── body.adoc
├── datatypes.adoc
├── shape.adoc
├── space.adoc
└── miscellanea.adoc
├── src
├── _make
├── moonchipmunk.h
├── tracing.c
├── Makefile
├── udata.h
├── simple_motor.c
├── enums.h
├── gear_joint.c
├── rotary_limit_joint.c
├── ratchet_joint.c
├── pin_joint.c
├── pivot_joint.c
├── groove_joint.c
├── slide_joint.c
├── circle.c
├── main.c
├── constraint.h
├── flags.c
├── segment.c
├── damped_rotary_spring.c
├── poly.c
├── damped_spring.c
├── objects.c
└── collision_handler.c
├── examples
├── sprites
│ ├── block.png
│ ├── awesomeface.png
│ └── LICENSE
├── sounds
│ ├── Shoot_00.wav
│ ├── Explosion_00.wav
│ ├── Jingle_Win_00.wav
│ └── LICENSE
├── ttf-bitstream-vera-1.10
│ ├── Vera.ttf
│ ├── VeraBI.ttf
│ ├── VeraBd.ttf
│ ├── VeraIt.ttf
│ ├── VeraSe.ttf
│ ├── VeraMoBI.ttf
│ ├── VeraMoBd.ttf
│ ├── VeraMoIt.ttf
│ ├── VeraMono.ttf
│ ├── VeraSeBd.ttf
│ ├── README.TXT
│ ├── local.conf
│ └── COPYRIGHT.TXT
├── version.lua
├── enumsandflags.lua
├── hello.lua
├── demo
│ ├── 01-pyramid-stack.lua
│ ├── 05-pyramid-topple.lua
│ ├── 06-planet.lua
│ ├── 20-convex.lua
│ ├── 11-one-way.lua
│ ├── 02-plink.lua
│ ├── 04-tumble.lua
│ ├── 14-chains.lua
│ └── 10-query.lua
└── toolboxtest.lua
├── .gitignore
├── Makefile
├── thirdparty
├── powered-by-lua-license
├── lua-compat-5.3-license
├── openbsd-tree-license
└── asciidoctor-styles-license
├── LICENSE
├── CMakeLists.txt
└── README.md
/doc/powered-by-lua.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/doc/powered-by-lua.gif
--------------------------------------------------------------------------------
/src/_make:
--------------------------------------------------------------------------------
1 | sudo make LUAVER=5.4 uninstall && make LUAVER=5.4 D=$1 && sudo make LUAVER=5.4 install
2 |
--------------------------------------------------------------------------------
/examples/sprites/block.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/sprites/block.png
--------------------------------------------------------------------------------
/examples/sounds/Shoot_00.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/sounds/Shoot_00.wav
--------------------------------------------------------------------------------
/examples/sounds/Explosion_00.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/sounds/Explosion_00.wav
--------------------------------------------------------------------------------
/examples/sounds/Jingle_Win_00.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/sounds/Jingle_Win_00.wav
--------------------------------------------------------------------------------
/examples/sprites/awesomeface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/sprites/awesomeface.png
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/Vera.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/Vera.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraBI.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraBI.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraBd.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraBd.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraIt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraIt.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraSe.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraSe.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraMoBI.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraMoBI.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraMoBd.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraMoBd.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraMoIt.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraMoIt.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraMono.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraMono.ttf
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/VeraSeBd.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stetre/moonchipmunk/HEAD/examples/ttf-bitstream-vera-1.10/VeraSeBd.ttf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.dylib
3 | *.log
4 | *.so
5 | *.dll
6 | *.o
7 | *.swp
8 | *.symbols
9 | core.*
10 | local/
11 | src/TODO
12 | src/DIFF
13 |
--------------------------------------------------------------------------------
/examples/version.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | -- MoonChipmunk example: version.lua
3 | local cp = require("moonchipmunk")
4 |
5 | print(cp._VERSION)
6 | print(cp._CHIPMUNK_VERSION)
7 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | default: build
3 |
4 | build install uninstall where:
5 | @cd src; $(MAKE) $@
6 |
7 | clean :
8 | @cd src; $(MAKE) $@
9 | @cd doc; $(MAKE) $@
10 |
11 | docs:
12 | @cd doc; $(MAKE)
13 |
14 | cleanall: clean
15 |
16 | backup: clean
17 |
--------------------------------------------------------------------------------
/examples/sounds/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The sound samples contained in this directory are taken from the
3 | '8 Bit Sound Effects Library', by Little Robot Sound Factory:
4 | https://opengameart.org/content/8-bit-sound-effects-library
5 |
6 | License: CC-BY 3.0 (https://creativecommons.org/licenses/by/3.0/).
7 |
8 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | TgtAdoc := index
2 |
3 | Stylesdir = ./
4 | Stylesheet = colony.css
5 | Style = -a stylesheet=$(Stylesheet) -a stylesdir=$(Stylesdir)
6 | Style =
7 |
8 | Src = $(TgtAdoc).adoc
9 |
10 | default: html
11 |
12 | check:
13 |
14 | clean:
15 | @-rm -f *~
16 | @-rm -f *.html
17 |
18 | install:
19 |
20 | html: clean
21 | @asciidoctor $(Style) $(Src)
22 |
23 | docs: html
24 |
--------------------------------------------------------------------------------
/examples/sprites/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | The sprite renderer in moonchipmunk/toolbox.lua is based on the
3 | Learn OpenGL tutorial by Joey de Vries, at:
4 | https://learnopengl.com/#!In-Practice/2D-Game/Rendering-Sprites
5 |
6 | The texture images contained in this directory are taken from the
7 | same source, and are covered by the CC-BY 4.0 license
8 | (https://creativecommons.org/licenses/by/4.0/)
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/README.TXT:
--------------------------------------------------------------------------------
1 | Contained herin is the Bitstream Vera font family.
2 |
3 | The Copyright information is found in the COPYRIGHT.TXT file (along
4 | with being incoporated into the fonts themselves).
5 |
6 | The releases notes are found in the file "RELEASENOTES.TXT".
7 |
8 | We hope you enjoy Vera!
9 |
10 | Bitstream, Inc.
11 | The Gnome Project
12 |
--------------------------------------------------------------------------------
/thirdparty/powered-by-lua-license:
--------------------------------------------------------------------------------
1 | The 'powered by Lua' logo (doc/powered-by-lua.gif ) is taken from:
2 | http://www.lua.org/images .
3 |
4 | Below is a copy of the copyright notice from the same web-page.
5 |
6 | Stefano Trettel
7 |
8 | ===========================================================================
9 | Copyright © 1998 Lua.org. Graphic design by Alexandre Nakonechnyj.
10 |
11 | Permission is hereby granted, without written agreement and without license
12 | or royalty fees, to use, copy, and distribute this logo for any purpose,
13 | including commercial applications, subject to the following conditions:
14 |
15 | - The origin of this logo must not be misrepresented; you must not claim that
16 | you drew the original logo.
17 | - The only modification you can make is to adapt the orbiting text to your
18 | product name.
19 | - The logo can be used in any scale as long as the relative proportions of its
20 | elements are maintained.
21 |
--------------------------------------------------------------------------------
/examples/enumsandflags.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | -- MoonChipmunk example: enumsandflags.lua
3 | local cp = require("moonchipmunk")
4 |
5 | -- Enums
6 | print(table.unpack(cp.enum('bodytype')))
7 |
8 | -- Flags
9 | print(cp.debugdrawflags(-1))
10 | print(string.format("0x%.8x", cp.debugdrawflags('shapes', 'constraints', 'points')))
11 |
12 | print(string.format("SPACE_DEBUG_DRAW_SHAPES 0x%x", cp.SPACE_DEBUG_DRAW_SHAPES))
13 | print(string.format("SPACE_DEBUG_DRAW_CONSTRAINTS 0x%x", cp.SPACE_DEBUG_DRAW_CONSTRAINTS))
14 | print(string.format("SPACE_DEBUG_DRAW_COLLISION_POINTS 0x%x", cp.SPACE_DEBUG_DRAW_COLLISION_POINTS))
15 | local flags = cp.SPACE_DEBUG_DRAW_SHAPES|cp.SPACE_DEBUG_DRAW_CONSTRAINTS|cp.SPACE_DEBUG_DRAW_COLLISION_POINTS
16 | print(string.format("0x%.8x", flags))
17 |
18 | -- Constants
19 | print(string.format("NO_GROUP 0x%x", cp.NO_GROUP))
20 | print(string.format("ALL_CATEGORIES 0x%x", cp.ALL_CATEGORIES))
21 | print(string.format("WILDCARD_COLLISION_TYPE 0x%x", cp.WILDCARD_COLLISION_TYPE))
22 |
23 |
24 | print(string.format("~ALL_CATEGORIES 0x%x", ~cp.ALL_CATEGORIES))
25 | print(string.format("~WILDCARD_COLLISION_TYPE 0x%x", ~cp.WILDCARD_COLLISION_TYPE))
26 |
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/local.conf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 | serif
16 |
17 | Bitstream Vera Serif
18 |
19 |
20 |
21 | sans-serif
22 |
23 | Bitstream Vera Sans
24 |
25 |
26 |
27 | monospace
28 |
29 | Bitstream Vera Sans Mono
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/doc/collisionhandler.adoc:
--------------------------------------------------------------------------------
1 |
2 | [[collision_handler]]
3 | === Collision handlers
4 |
5 | [small]#Rfr: https://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_collision_handler.html[cpCollisionHandler].#
6 |
7 | [[space_add_collision_handler]]
8 | * _collision_handler_ = _space_++:++*add_default_collision_handler*( ) +
9 | _collision_handler_ = _space_++:++*add_collision_handler*(_type~a~_, _type~b~_) +
10 | _collision_handler_ = _space_++:++*add_wildcard_handler*(_type_) +
11 | [small]#_type_, _type~a~_, _type~b~_: integer (cpCollisionType).#
12 |
13 | [[collision_handler_free]]
14 | * _collision_handler_++:++*free*( ) +
15 | [small]#Delete _collision_handler_.#
16 |
17 | [[collision_handler_xxx]]
18 | * _type~a~_, _type~b~_ = _collision_handler_++:++*get_types*( ) +
19 | _collision_handler_++:++*set_begin_func*(_func_) +
20 | _collision_handler_++:++*set_pre_solve_func*(_func_) +
21 | _collision_handler_++:++*set_post_solve_func*(_func_) +
22 | _collision_handler_++:++*set_separate_func*(_func_) +
23 | [small]#The callbacks are executed as follows: +
24 | pass:[-] begin: *boolean = func(<>, space)*. +
25 | pass:[-] pre solve: *boolean = func(<>, space)*. +
26 | pass:[-] post solve: *func(<>, space)*. +
27 | pass:[-] separate: *func(<>, space)*.#
28 |
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Stefano Trettel
4 |
5 | Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | SOFTWARE.
24 |
25 |
26 | (See also the THIRD-PARTY LICENSES contained in the thirdparty/ directory
27 | of the Software repository.)
28 |
29 |
--------------------------------------------------------------------------------
/doc/toolbox.adoc:
--------------------------------------------------------------------------------
1 |
2 | [[toolbox]]
3 | == Toolbox
4 |
5 | MoonChipmunk comes with a 'toolbox' submodule, located in `moonchipmunk/toolbox.lua`.
6 | This submodule provides the tools that are used in examples and demos for rendering, input
7 | handling, and more.
8 |
9 | In addition to MoonChipmunk itself, the toolbox uses (and thus requires) the following
10 | libraries from the https://github.com/stetre/moonlibs[MoonLibs collection]:
11 |
12 | * https://github.com/stetre/moongl[MoonGL]: bindings to the OpenGL API, for graphics rendering.
13 | * https://github.com/stetre/moonglfw[MoonGLFW]: bindings to GLFW, for window/surface creation and input handling.
14 | * https://github.com/stetre/moonglmath[MoonGLMATH]: graphics math library.
15 | * https://github.com/stetre/moonfreetype[MoonFreeType]: bindings to FreeType, for loading fonts.
16 | * https://github.com/stetre/moonimage[MoonImage]: bindings to stb_image, for loading images.
17 | * https://github.com/stetre/moonsndfile[MoonSndFile]: bindings to libsndfile, for loading sound samples.
18 | * https://github.com/stetre/moonal[MoonAL]: bindings to OpenAL, for rendering audio.
19 |
20 | (Note that MoonChipmunk itself does not depend on the above libraries. Only the toolbox does,
21 | and its use in an application is optional).
22 |
23 | The examples and demos, together with the comments in the toolbox script, should hopefully
24 | suffice to show how the tools are meant to be used.
25 |
26 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.17)
2 |
3 | project(moonchipmunk)
4 |
5 | find_package(Lua REQUIRED)
6 |
7 | #needs to be manually created until chipmunk provides a chipmunkConfig.cmake
8 | find_package(chipmunk REQUIRED)
9 |
10 | add_library(moonchipmunk SHARED
11 | src/compat-5.3.h
12 | src/constraint.h
13 | src/enums.h
14 | src/internal.h
15 | src/moonchipmunk.h
16 | src/objects.h
17 | src/tree.h
18 | src/udata.h
19 | src/arbiter.c
20 | src/body.c
21 | src/circle.c
22 | src/collision_handler.c
23 | src/compat-5.3.c
24 | src/constraint.c
25 | src/damped_rotary_spring.c
26 | src/damped_spring.c
27 | src/datastructs.c
28 | src/enums.c
29 | src/flags.c
30 | src/gear_joint.c
31 | src/groove_joint.c
32 | src/main.c
33 | src/misc.c
34 | src/objects.c
35 | src/pin_joint.c
36 | src/pivot_joint.c
37 | src/poly.c
38 | src/ratchet_joint.c
39 | src/rotary_limit_joint.c
40 | src/segment.c
41 | src/shape.c
42 | src/simple_motor.c
43 | src/slide_joint.c
44 | src/space.c
45 | src/tracing.c
46 | src/udata.c
47 | src/utils.c
48 | )
49 |
50 | target_include_directories(moonchipmunk PUBLIC
51 | ${LUA_INCLUDE_DIR}
52 | ${chipmunk_INCLUDE_DIR}
53 | )
54 |
55 | target_link_libraries(moonchipmunk
56 | ${LUA_LIBRARIES}
57 | ${chipmunk_LIBS}
58 | )
59 |
60 | install(TARGETS moonchipmunk LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
61 | install(TARGETS moonchipmunk RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
62 |
--------------------------------------------------------------------------------
/thirdparty/lua-compat-5.3-license:
--------------------------------------------------------------------------------
1 | The src/compat-5.3.h and src/compat-5.3.c files are taken from:
2 | https://github.com/keplerproject/lua-compat-5.3
3 |
4 | Below is a copy of the original copyright notice, from the same source.
5 |
6 | Stefano Trettel
7 |
8 | ===========================================================================
9 |
10 | The MIT License (MIT)
11 |
12 | Copyright (c) 2015 Kepler Project.
13 |
14 | Permission is hereby granted, free of charge, to any person obtaining a copy of
15 | this software and associated documentation files (the "Software"), to deal in
16 | the Software without restriction, including without limitation the rights to
17 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
18 | the Software, and to permit persons to whom the Software is furnished to do so,
19 | subject to the following conditions:
20 |
21 | The above copyright notice and this permission notice shall be included in all
22 | copies or substantial portions of the Software.
23 |
24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
26 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
27 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
28 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 |
--------------------------------------------------------------------------------
/thirdparty/openbsd-tree-license:
--------------------------------------------------------------------------------
1 | The src/tree.h module is taken from:
2 | http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/sys/tree.h
3 |
4 | Below is a copy of the copyright notice included in the module.
5 |
6 | Stefano Trettel
7 |
8 | ===========================================================================
9 | /*
10 | * Copyright 2002 Niels Provos
11 | * All rights reserved.
12 | *
13 | * Redistribution and use in source and binary forms, with or without
14 | * modification, are permitted provided that the following conditions
15 | * are met:
16 | * 1. Redistributions of source code must retain the above copyright
17 | * notice, this list of conditions and the following disclaimer.
18 | * 2. Redistributions in binary form must reproduce the above copyright
19 | * notice, this list of conditions and the following disclaimer in the
20 | * documentation and/or other materials provided with the distribution.
21 | *
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 | */
33 |
34 |
--------------------------------------------------------------------------------
/src/moonchipmunk.h:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #ifndef moonchipmunkDEFINED
27 | #define moonchipmunkDEFINED
28 |
29 | #include
30 | #include "lualib.h"
31 | #include "lauxlib.h"
32 | #include "compat-5.3.h"
33 |
34 | #undef CP_SPACE_DISABLE_DEBUG_API
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 |
43 | #define MOONCHIPMUNK_VERSION "0.1"
44 |
45 | #endif /* moonchipmunkDEFINED */
46 |
47 |
--------------------------------------------------------------------------------
/doc/index.adoc:
--------------------------------------------------------------------------------
1 | = MoonChipmunk Reference Manual
2 | Stefano Trettel
3 | v0.1, 2020-02-25
4 | :toc: left
5 | :toclevels: 3
6 | :stylesdir: ./
7 | :stylesheet: colony.css
8 | :source-highlighter: pygments
9 | :pygments-style: autumn
10 | :source-language: lua
11 | :exampledir: ../examples
12 |
13 | image::powered-by-lua.gif[Lua logo, link=http://www.lua.org]
14 |
15 | // Macros for trees: {tS} = " ", {tI} = "│ ", {tH} = "├─ ", {tL} = "└─ "
16 | :tS:
17 | :tI: │
18 | :tH: ├─
19 | :tL: └─
20 |
21 | include::preface.adoc[]
22 | include::introduction.adoc[]
23 |
24 | == Objects
25 |
26 | Listed below are the Lua object types in MoonChipmunk, together with the corresponding
27 | original types in Chipmunk2D:
28 |
29 | [small]#Objects: +
30 | <> _(cpSpace, cpHastySpace)_ +
31 | <> _(cpBody)_ +
32 | <> _(cpShape)_ +
33 | {tH}<> _(cpCircleShape)_ +
34 | {tH}<> _(cpSegmentShape)_ +
35 | {tL}<> _(cpPolyShape)_ +
36 | <> _(cpConstraint)_ +
37 | {tH}<> _(cpPinJoint)_ +
38 | {tH}<> _(cpSlideJoint)_ +
39 | {tH}<> _(cpPivotJoint)_ +
40 | {tH}<> _(cpGrooveJoint)_ +
41 | {tH}<> _(cpDampedSpring)_ +
42 | {tH}<> _(cpDampedRotarySpring)_ +
43 | {tH}<> _(cpRotaryLimitJoint)_ +
44 | {tH}<> _(cpRatchetJoint)_ +
45 | {tH}<> _(cpGearJoint)_ +
46 | {tL}<> _(cpSimpleMotor)_ +
47 | <> _(cpCollisionHandler)_ +
48 | <> _(cpArbiter)_#
49 |
50 |
51 | include::space.adoc[]
52 | include::body.adoc[]
53 | include::shape.adoc[]
54 | include::constraint.adoc[]
55 | include::collisionhandler.adoc[]
56 | include::arbiter.adoc[]
57 |
58 | include::miscellanea.adoc[]
59 | include::datatypes.adoc[]
60 | include::toolbox.adoc[]
61 |
62 |
63 |
--------------------------------------------------------------------------------
/thirdparty/asciidoctor-styles-license:
--------------------------------------------------------------------------------
1 | The CSS used for the Reference Manual is taken from the
2 | Asciidoctor styles project
3 | (https://github.com/asciidoctor/asciidoctor-stylesheet-factory ).
4 |
5 | Below is a copy of the Asciidoctor styles copyright notice.
6 |
7 | Stefano Trettel
8 |
9 | ========================================================================
10 |
11 | Asciidoctor styles
12 | ------------------
13 |
14 | Copyright (c) 2013 Dan Allen
15 |
16 | MIT License
17 |
18 | Permission is hereby granted, free of charge, to any person obtaining
19 | a copy of this software and associated documentation files (the
20 | "Software"), to deal in the Software without restriction, including
21 | without limitation the rights to use, copy, modify, merge, publish,
22 | distribute, sublicense, and/or sell copies of the Software, and to
23 | permit persons to whom the Software is furnished to do so, subject to
24 | the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be
27 | included in all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 |
37 |
38 | Other licensed work
39 | -------------------
40 |
41 | - Foundation 4 by Zurb, on which the themes are built, is licensed under the
42 | Apache License, v2.0:
43 |
44 | http://apache.org/licenses/LICENSE-2.0
45 | http://foundation.zurb.com
46 |
47 | - The riak theme is derived from the Riak documentation theme by Basho,
48 | licensed under the Creative Commons Attribution 3.0 Unported License:
49 |
50 | http://creativecommons.org/licenses/by/3.0/us
51 | http://docs.basho.org
52 |
53 | - The iconic theme is inspired by O'Reilly typography and Atlas manual.
54 |
55 | http://oreilly.com
56 |
--------------------------------------------------------------------------------
/doc/preface.adoc:
--------------------------------------------------------------------------------
1 |
2 | == Preface
3 |
4 | This is the reference manual of *MoonChipmunk*, which is a
5 | https://www.lua.org[*Lua*] binding library for Scott Lembcke's
6 | http://chipmunk-physics.net/[*Chipmunk2D*] physics engine.
7 | footnote:[
8 | This manual is written in
9 | http://www.methods.co.nz/asciidoc/[AsciiDoc], rendered with
10 | http://asciidoctor.org/[AsciiDoctor] and a CSS from the
11 | https://github.com/asciidoctor/asciidoctor-stylesheet-factory[AsciiDoctor Stylesheet Factory].]
12 |
13 | It is assumed that the reader is familiar with both Chipmunk2D and the Lua programming language.
14 |
15 | For convenience of reference, this document contains external (deep) links to the
16 | https://www.lua.org/manual/5.3/manual.html[Lua Reference Manual] and the
17 | http://chipmunk-physics.net/documentation.php[Chipmunk2D Documentation].
18 |
19 | === Getting and installing
20 |
21 | For installation intructions, refer to the README file in the
22 | https://github.com/stetre/moonchipmunk[*MoonChipmunk official repository*]
23 | on GitHub.
24 |
25 | === Module organization
26 |
27 | The MoonChipmunk module is loaded using Lua's
28 | http://www.lua.org/manual/5.3/manual.html#pdf-require[require]() and
29 | returns a table containing the functions it provides
30 | (as usual with Lua modules). This manual assumes that such
31 | table is named *cp*, i.e. that it is loaded with:
32 |
33 | [source,lua,indent=1]
34 | ----
35 | cp = require("moonchipmunk")
36 | ----
37 |
38 | but nothing forbids the use of a different name.
39 |
40 | === Examples
41 |
42 | Complete examples can be found in the *examples/* directory of the release package.
43 |
44 | === License
45 |
46 | MoonChipmunk is released under the *MIT/X11 license* (same as
47 | http://www.lua.org/license.html[Lua], and with the same only requirement to give proper
48 | credits to the original author).
49 | The copyright notice is in the LICENSE file in the base directory
50 | of the https://github.com/stetre/moonchipmunk[official repository] on GitHub.
51 |
52 | [[see-also]]
53 | === See also
54 |
55 | MoonChipmunk is part of https://github.com/stetre/moonlibs[MoonLibs], a collection of
56 | Lua libraries for graphics and audio programming.
57 |
58 |
--------------------------------------------------------------------------------
/src/tracing.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | int trace_objects = 0;
29 |
30 | static int TraceObjects(lua_State *L)
31 | {
32 | trace_objects = checkboolean(L, 1);
33 | return 0;
34 | }
35 |
36 | static int Now(lua_State *L)
37 | {
38 | lua_pushnumber(L, now());
39 | return 1;
40 | }
41 |
42 | static int Since(lua_State *L)
43 | {
44 | double t = luaL_checknumber(L, 1);
45 | lua_pushnumber(L, since(t));
46 | return 1;
47 | }
48 |
49 | /* ----------------------------------------------------------------------- */
50 |
51 | static const struct luaL_Reg Functions[] =
52 | {
53 | { "trace_objects", TraceObjects },
54 | { "now", Now },
55 | { "since", Since },
56 | { NULL, NULL } /* sentinel */
57 | };
58 |
59 | void moonchipmunk_open_tracing(lua_State *L)
60 | {
61 | luaL_setfuncs(L, Functions, 0);
62 | }
63 |
64 |
65 |
--------------------------------------------------------------------------------
/doc/introduction.adoc:
--------------------------------------------------------------------------------
1 |
2 | == Introduction
3 |
4 | MoonChipmunk is an almost one-to-one Lua binding library to the Chipmunk2D physics engine.
5 | This means that by and large, it is intended to be used as described in the http://chipmunk-physics.net/release/ChipmunkLatest-Docs/[Chipmunk2D Manual] (apart from coding in Lua, of course).
6 |
7 | This section gives a brief overview of the binding library, while the details are given
8 | in the sections that follow.
9 |
10 | MoonChipmunk binds Chipmunk2D *objects* (_space_, _body_, etc.) to Lua userdata, which are
11 | returned by the creating functions (_cp.space_new_( ), _cp.body_new_( ), etc) and are then used to refer to objects in Lua in the same way as one would use Chipmunk2D handles in C.
12 |
13 | As a general rule, Chipmunk2D functions are bound to MoonChipmunk functions or methods
14 | whose names are https://en.wikipedia.org/wiki/Snake_case[snake_case] versions of the original ones.
15 |
16 | The functions related to an object type - with the exception of the creating function - are
17 | bounded to methods of that object (e.g. the C function _cpSpaceSetGravity(space,...)_ becomes the method _space:set_gravity(...)_ in Lua.
18 |
19 | Objects are *garbage collected at exit* (which includes on error), and automatically
20 | deleted at the Chipmunk2D level, so there is no need to explicitly invoke their _free_( ) methods at exit for cleanup.
21 |
22 | Apart from at exit, however, objects are not automatically garbage collected
23 | footnote:[Objects are anchored to the Lua registry at their creation, so even if the script does not
24 | have references to an object, a reference always exists on the registry and this prevents the
25 | GC to collect it.]
26 | and one must release them explicitly when needed, e.g. to release resources when the
27 | application is not exiting and some objects are no longer needed.
28 |
29 | Releasing an object causes the automatic (pre) destruction of all its children
30 | objects, and the invalidation of any reference to the object and to its children.
31 | footnote:[It is good practice to not leave invalid references to objects around, because
32 | they prevent the GC to collect the memory associated with the userdata.]
33 |
34 | If not stated otherwise, *on error* all MoonChipmunk functions raise a
35 | http://www.lua.org/manual/5.3/manual.html#lua_error[Lua error].
36 | If needed, this behaviour can be overridden by wrapping function calls in the standard Lua
37 | http://www.lua.org/manual/5.3/manual.html#pdf-pcall[pcall]( ).
38 |
39 |
--------------------------------------------------------------------------------
/examples/hello.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | -- MoonChipmunk example: hello.lua
3 | -- This is a port of the "Hello Chipmunk (World)" example from the Chipmunk manual:
4 | -- (see http://chipmunk-physics.net/release/ChipmunkLatest-Docs/#Intro-HelloChipmunk )
5 |
6 | local cp = require("moonchipmunk")
7 |
8 | -- Create an empty space and set the gravity for it.
9 | local space = cp.space_new()
10 | space:set_gravity({0, -100})
11 |
12 | -- Add a static line segment shape for the ground.
13 | -- We'll make it slightly tilted so the ball will roll off.
14 | -- We attach it to a static body to tell Chipmunk it shouldn't be movable.
15 | local ground = cp.segment_shape_new(space:get_static_body(), {-20, 5}, {20, -5}, 0)
16 | ground:set_friction(1)
17 | space:add_shape(ground)
18 |
19 | -- Now let's make a ball that falls onto the line and rolls off.
20 | -- First we need to make a body to hold the physical properties of the object.
21 | -- These include the mass, position, velocity, angle, etc. of the object.
22 | -- Then we attach collision shapes to the body to give it a size and shape.
23 | local radius = 5
24 | local mass = 1
25 | -- The moment of inertia is like mass for rotation
26 | -- Use the cp.moment_for*() functions to help you approximate it.
27 | local moment = cp.moment_for_circle(mass, 0, radius, {0, 0})
28 |
29 | -- The space:add*() methods return the thing that you are adding.
30 | -- It's convenient to create and add an object in one line.
31 | local ballBody = space:add_body(cp.body_new(mass, moment))
32 | ballBody:set_position({0, 15})
33 |
34 | -- Now we create the collision shape for the ball.
35 | -- You can create multiple collision shapes that point to the same body.
36 | -- They will all be attached to the body and move around to follow it.
37 | local ballShape = space:add_shape(cp.circle_shape_new(ballBody, radius, {0, 0}))
38 | ballShape:set_friction(0.7)
39 |
40 | -- Now that it's all set up, we simulate all the objects in the space by
41 | -- stepping forward through time in small increments called steps.
42 | -- It is *highly* recommended to use a fixed size time step.
43 | local timeStep = 1.0/60.0
44 | for time = 0, 2, timeStep do
45 | local pos = ballBody:get_position()
46 | local vel = ballBody:get_velocity()
47 | print(string.format(
48 | "Time is %5.2f. ballBody is at (%5.2f, %5.2f). It's velocity is (%5.2f, %5.2f)",
49 | time, pos[1], pos[2], vel[1], vel[2]))
50 | space:step(timeStep)
51 | end
52 |
53 | -- No need to delete objects here (they are are automatically deleted ad exit).
54 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 |
2 | ifdef MINGW_PREFIX
3 | MINGW=1
4 | else
5 | LINUX=1
6 | endif
7 |
8 | # Lua version
9 | LUAVER?=$(shell lua -e 'print(string.match(_VERSION, "%d+%.%d+") or "5.3")')
10 | ifeq ($(LUAVER),)
11 | # lua-interpreter not found
12 | LUAVER=5.3
13 | endif
14 |
15 | # Base install directory
16 | ifdef LINUX
17 | PREFIX?=/usr/local
18 | endif
19 | ifdef MINGW
20 | PREFIX?=$(MINGW_PREFIX)
21 | endif
22 |
23 | # Directory where to install Lua modules
24 | L_DIR=$(PREFIX)/share/lua/$(LUAVER)
25 | # Directory where to install Lua C modules
26 | C_DIR=$(PREFIX)/lib/lua/$(LUAVER)
27 | # Directory where to install C headers
28 | H_DIR=$(PREFIX)/include
29 | # Directory where to install C libraries
30 | S_DIR=$(PREFIX)/lib
31 |
32 | ifeq ($(D),1)
33 | DEBUG=1
34 | endif
35 |
36 | ifdef LINUX
37 | LIBS = -lchipmunk -lpthread
38 | endif
39 | ifdef MINGW
40 | LIBS = -lchipmunk -llua
41 | endif
42 |
43 | Tgt := moonchipmunk
44 | Src := $(wildcard *.c)
45 | Objs := $(Src:.c=.o)
46 |
47 | INCDIR = -I. -I/usr/include/lua$(LUAVER)
48 |
49 | COPT += -O2
50 | #COPT += -O0 -g
51 | #COPT += -m32
52 | COPT += -Wfatal-errors
53 | COPT += -Wall -Wextra -Wpedantic
54 | COPT += -DCOMPAT53_PREFIX=moonchipmunk_compat_
55 | COPT += -std=gnu99
56 | COPT += -DLUAVER=$(LUAVER)
57 | ifdef LINUX
58 | COPT += -fpic
59 | COPT += -DLINUX
60 | endif
61 | ifdef MINGW
62 | COPT += -DMINGW
63 | endif
64 | ifdef DEBUG
65 | COPT += -DDEBUG
66 | COPT += -Wshadow -Wsign-compare -Wundef -Wwrite-strings
67 | COPT += -Wdisabled-optimization -Wdeclaration-after-statement
68 | COPT += -Wmissing-prototypes -Wstrict-prototypes -Wnested-externs
69 | COPT += -Wold-style-definition
70 | #COPT += -Wc++-compat
71 | endif
72 |
73 | override CFLAGS = $(COPT) $(INCDIR)
74 |
75 | default: build
76 |
77 | where:
78 | @echo "PREFIX="$(PREFIX)
79 | @echo "LUAVER="$(LUAVER)
80 | @echo $(L_DIR)
81 | @echo $(C_DIR)
82 | @echo $(H_DIR)
83 | @echo $(S_DIR)
84 |
85 | clean:
86 | @-rm -f *.so *.dll *.o *.err *.map *.S *~ *.log
87 | @-rm -f $(Tgt).symbols
88 |
89 | install:
90 | @-mkdir -pv $(H_DIR)
91 | @-mkdir -pv $(C_DIR)
92 | @-mkdir -pv $(S_DIR)
93 | @-mkdir -pv $(L_DIR)
94 | @-cp -fpv $(Tgt).h $(H_DIR)
95 | @-cp -fpvr ../$(Tgt) $(L_DIR)
96 | ifdef LINUX
97 | @-cp -fpv $(Tgt).so $(C_DIR)
98 | @-ln -fsv $(C_DIR)/$(Tgt).so $(S_DIR)/lib$(Tgt).so
99 | endif
100 | ifdef MINGW
101 | @-cp -fpv $(Tgt).dll $(C_DIR)
102 | endif
103 |
104 | uninstall:
105 | @-rm -f $(H_DIR)/$(Tgt).h
106 | @-rm -f $(C_DIR)/$(Tgt).so
107 | @-rm -f $(S_DIR)/lib$(Tgt).so
108 | @-rm -fr $(L_DIR)/$(Tgt)
109 | @-rm -f $(C_DIR)/$(Tgt).dll
110 |
111 | build: clean $(Tgt)
112 |
113 | symbols: build
114 | @objdump -T $(Tgt).so > $(Tgt).symbols
115 |
116 | $(Tgt): $(Objs)
117 | ifdef LINUX
118 | @$(CXX) -shared -o $(Tgt).so $(Objs) $(LIBDIR) $(LIBS)
119 | endif
120 | ifdef MINGW
121 | @-$(CXX) -shared -o $(Tgt).dll $(Objs) $(LIBDIR) $(LIBS)
122 | endif
123 | @-rm -f $(Objs)
124 | @echo
125 |
126 |
--------------------------------------------------------------------------------
/src/udata.h:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | #include
32 | #include "lua.h"
33 | #include "lauxlib.h"
34 | #include "compat-5.3.h"
35 |
36 | #ifndef Malloc
37 | #define Malloc moonchipmunk_Malloc
38 | void *Malloc(lua_State *L, size_t size);
39 | #define Free moonchipmunk_Free
40 | void Free(lua_State *L, void *ptr);
41 | #endif
42 |
43 | #define udata_t moonchipmunk_udata_t
44 | #define udata_s moonchipmunk_udata_s
45 | #define moonchipmunk_udata_t struct moonchipmunk_udata_s
46 |
47 | #define udata_new moonchipmunk_udata_new
48 | void *udata_new(lua_State*, size_t, uint64_t, const char*);
49 | #define udata_unref moonchipmunk_udata_unref
50 | int udata_unref(lua_State *L, uint64_t);
51 | #define udata_free moonchipmunk_udata_free
52 | int udata_free(lua_State*, uint64_t);
53 | #define udata_mem moonchipmunk_udata_mem
54 | void *udata_mem(uint64_t);
55 | #define udata_push moonchipmunk_udata_push
56 | int udata_push(lua_State*, uint64_t);
57 | #define udata_free_all moonchipmunk_udata_free_all
58 | void udata_free_all(lua_State *L);
59 | #define udata_scan moonchipmunk_udata_scan
60 | int udata_scan(lua_State *L, const char *mt,
61 | void *info, int (*func)(lua_State *L, const void *mem, const char* mt, const void *info));
62 | #define udata_define moonchipmunk_udata_define
63 | int udata_define(lua_State*, const char*, const luaL_Reg*, const luaL_Reg*);
64 | #define udata_inherit moonchipmunk_udata_inherit
65 | int udata_inherit(lua_State*, const char*, const char*);
66 | #define udata_test moonchipmunk_udata_test
67 | void *udata_test(lua_State*, int, const char*);
68 | #define udata_addmethods moonchipmunk_udata_addmethods
69 | int udata_addmethods(lua_State*, const char*, const luaL_Reg*);
70 |
71 | #ifdef __cplusplus
72 | }
73 | #endif
74 |
75 |
--------------------------------------------------------------------------------
/src/simple_motor.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freesimple_motor(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "simple_motor")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newsimple_motor(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, SIMPLE_MOTOR_MT, "simple_motor");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freesimple_motor;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | body_t *a = checkbody(L, 1, NULL);
50 | body_t *b = checkbody(L, 2, NULL);
51 | double rate = luaL_checknumber(L, 3);
52 | constraint_t *constraint = cpSimpleMotorNew(a, b, rate);
53 | return newsimple_motor(L, constraint);
54 | }
55 |
56 | SETDOUBLE(SetRate, cpSimpleMotorSetRate, simple_motor)
57 | GETDOUBLE(GetRate, cpSimpleMotorGetRate, simple_motor)
58 |
59 | DESTROY_FUNC(simple_motor)
60 |
61 | static const struct luaL_Reg Methods[] =
62 | {
63 | { "free", Destroy },
64 | { "set_rate", SetRate },
65 | { "get_rate", GetRate },
66 | { NULL, NULL } /* sentinel */
67 | };
68 |
69 | static const struct luaL_Reg MetaMethods[] =
70 | {
71 | { "__gc", Destroy },
72 | { NULL, NULL } /* sentinel */
73 | };
74 |
75 | static const struct luaL_Reg Functions[] =
76 | {
77 | { "simple_motor_new", Create },
78 | { NULL, NULL } /* sentinel */
79 | };
80 |
81 | void moonchipmunk_open_simple_motor(lua_State *L)
82 | {
83 | udata_define(L, SIMPLE_MOTOR_MT, Methods, MetaMethods);
84 | udata_inherit(L, SIMPLE_MOTOR_MT, CONSTRAINT_MT);
85 | luaL_setfuncs(L, Functions, 0);
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/src/enums.h:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #ifndef enumsDEFINED
27 | #define enumsDEFINED
28 |
29 | /* enums.c */
30 | #define enums_free_all moonchipmunk_enums_free_all
31 | void enums_free_all(lua_State *L);
32 | #define enums_test moonchipmunk_enums_test
33 | int enums_test(lua_State *L, int domain, int arg, int *err);
34 | #define enums_opt moonchipmunk_enums_opt
35 | int enums_opt(lua_State *L, int domain, int arg, int defval);
36 | #define enums_check moonchipmunk_enums_check
37 | int enums_check(lua_State *L, int domain, int arg);
38 | #define enums_push moonchipmunk_enums_push
39 | int enums_push(lua_State *L, int domain, int code);
40 | #define enums_values moonchipmunk_enums_values
41 | int enums_values(lua_State *L, int domain);
42 | #define enums_checklist moonchipmunk_enums_checklist
43 | int* enums_checklist(lua_State *L, int domain, int arg, int *count, int *err);
44 | #define enums_freelist moonchipmunk_enums_freelist
45 | void enums_freelist(lua_State *L, int *list);
46 |
47 |
48 | /* Enum domains */
49 | #define DOMAIN_ 0
50 | #define DOMAIN_BODY_TYPE 1
51 |
52 | #define testbodytype(L, arg, err) enums_test((L), DOMAIN_BODY_TYPE, (arg), (err))
53 | #define optbodytype(L, arg, defval) enums_opt((L), DOMAIN_BODY_TYPE, (arg), (defval))
54 | #define checkbodytype(L, arg) enums_check((L), DOMAIN_BODY_TYPE, (arg))
55 | #define pushbodytype(L, val) enums_push((L), DOMAIN_BODY_TYPE, (int)(val))
56 | #define valuesbodytype(L) enums_values((L), DOMAIN_BODY_TYPE)
57 |
58 | #if 0 /* scaffolding 7yy */
59 | #define testxxx(L, arg, err) enums_test((L), DOMAIN_XXX, (arg), (err))
60 | #define optxxx(L, arg, defval) enums_opt((L), DOMAIN_XXX, (arg), (defval))
61 | #define checkxxx(L, arg) enums_check((L), DOMAIN_XXX, (arg))
62 | #define pushxxx(L, val) enums_push((L), DOMAIN_XXX, (int)(val))
63 | #define valuesxxx(L) enums_values((L), DOMAIN_XXX)
64 | CASE(xxx);
65 |
66 | #endif
67 |
68 | #endif /* enumsDEFINED */
69 |
70 |
71 |
--------------------------------------------------------------------------------
/doc/arbiter.adoc:
--------------------------------------------------------------------------------
1 |
2 | [[arbiter]]
3 | === Arbiters
4 |
5 | [small]#Rfr: https://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__cp_arbiter.html[cpArbiter].#
6 |
7 | From the point of view of the Lua scripts, an arbiter object is automatically created when it
8 | is received as argument to some callback function, and automatically deleted as soon as the
9 | function returns.
10 |
11 | [[arbiter_set_float]]
12 | * _arbiter_++:++*set_restitution*(_value_) +
13 | _arbiter_++:++*set_friction*(_value_) +
14 | _value_ = _arbiter_++:++*get_restitution*( ) +
15 | _value_ = _arbiter_++:++*get_friction*( ) +
16 | _value_ = _arbiter_++:++*total_ke*( ) +
17 | [small]#_value_: float.#
18 |
19 | [[arbiter_set_vec]]
20 | * _arbiter_++:++*set_surface_velocity*(<>) +
21 | <> = _arbiter_++:++*get_surface_velocity*( ) +
22 | <> = _arbiter_++:++*get_normal*( ) +
23 | <> = _arbiter_++:++*total_impulse*( ) +
24 |
25 | [[arbiter_get_boolean]]
26 | * _boolean_ = _arbiter_++:++*ignore*( ) +
27 | _boolean_ = _arbiter_++:++*is_first_contact*( ) +
28 | _boolean_ = _arbiter_++:++*is_removal*( ) +
29 |
30 | [[arbiter_get_shapes]]
31 | * <>, <> = _arbiter_++:++*get_shapes*( ) +
32 | <>, <> = _arbiter_++:++*get_bodies*( ) +
33 |
34 | [[arbiter_contact_point_set]]
35 | * _arbiter_++:++*set_contact_point_set*(_normal_, _{points}_) +
36 | _normal_, _{points}_ = _arbiter_++:++*get_contact_point_set*( ) +
37 | [small]#_normal_: <>. +
38 | _{points}_: {<>}.#
39 |
40 | [[arbiter_get_points]]
41 | * _npoints_ = _arbiter_++:++*get_count*( ) +
42 | _{point~a~}_, _{point~b~}_, _{depth}_ = _arbiter_++:++*get_points*( ) +
43 | [small]#_{point~a~}_, _{point~b~}_: {<>}. +
44 | _{depth}_: {float}.#
45 |
46 | [[arbiter_call_wildcard]]
47 | * _boolean_ = _arbiter_++:++*call_wildcard_begin_a*(_arbiter_, _space_) +
48 | _boolean_ = _arbiter_++:++*call_wildcard_begin_b*(_arbiter_, _space_) +
49 | _boolean_ = _arbiter_++:++*call_wildcard_pre_solve_a*(_arbiter_, _space_) +
50 | _boolean_ = _arbiter_++:++*call_wildcard_pre_solve_b*(_arbiter_, _space_) +
51 | _arbiter_++:++*call_wildcard_post_solve_a*(_arbiter_, _space_) +
52 | _arbiter_++:++*call_wildcard_post_solve_b*(_arbiter_, _space_) +
53 | _arbiter_++:++*call_wildcard_separate_a*(_arbiter_, _space_) +
54 | _arbiter_++:++*call_wildcard_separate_b*(_arbiter_, _space_) +
55 |
56 | [[arbiter_get_user_data]]
57 | * _value_ = _arbiter_++:++*get_user_index*( ) +
58 | _arbiter_++:++*set_user_index*(_value_) +
59 | [small]#Set/get a user-defined integer index associated with the arbiter. +
60 | This is a limited binding to _cpArbiterSetUserData( )_ and _cpArbiterGetUserData( )_:
61 | it doesn't allow you to directly associate a generic user data value with the arbiter,
62 | but you can store it in a table and associate with the arbiter the corresponding index instead. +
63 | Note that you can't use the _arbiter_ itself to index the user data table, because the arbiter Lua
64 | object is actually a singleton that is reused every time a _cpArbiter_ is passed to a callback.
65 | (From the Chipmunk Manual: _"[...] you should never store a reference to an arbiter as you don’t
66 | know when they will be freed or reused."_).#
67 |
68 |
--------------------------------------------------------------------------------
/doc/body.adoc:
--------------------------------------------------------------------------------
1 |
2 | [[body]]
3 | === Rigid bodies
4 |
5 | [small]#Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__cp_body.html[cpBody].#
6 |
7 | * _body_ = *body_new*(_mass_, _moment_) +
8 | _body_ = *body_new_kinematic*( ) +
9 | _body_ = *body_new_static*( ) +
10 | _body_++:++*free*( ) +
11 | [small]#Create/delete a rigid body.#
12 |
13 | [[body_get_space]]
14 | * <>|_nil_ = _body_++:++*get_space*( ) +
15 |
16 | [[body_set_type]]
17 | * _body_++:++*set_type*(_type_) +
18 | _type_ = _body_++:++*get_type*( ) +
19 | [small]#_type_: '_dynamic_' |, '_kinematic_' | '_static_'.#
20 |
21 | [[body_set_xxx]]
22 | * _body_++:++*set_mass*(_value_) +
23 | _body_++:++*set_moment*(_value_) +
24 | _body_++:++*set_angle*(_value_) +
25 | _body_++:++*set_angular_velocity*(_value_) +
26 | _body_++:++*set_torque*(_value_) +
27 | _value_ = _body_++:++*get_mass*( ) +
28 | _value_ = _body_++:++*get_moment*( ) +
29 | _value_ = _body_++:++*get_angle*( ) +
30 | _value_ = _body_++:++*get_angular_velocity*( ) +
31 | _value_ = _body_++:++*get_torque*( ) +
32 | _value_ = _body_++:++*kinetic_energy*( ) +
33 | [small]#_value_: float. +
34 | Angles are in radians.#
35 |
36 | [[body_set_vec]]
37 | * _body_++:++*set_position*(<>) +
38 | _body_++:++*set_center_of_gravity*(<>) +
39 | _body_++:++*set_velocity*(<>) +
40 | _body_++:++*set_force*(<>) +
41 | <> = _body_++:++*get_position*( ) +
42 | <> = _body_++:++*get_center_of_gravity*( ) +
43 | <> = _body_++:++*get_velocity*( ) +
44 | <> = _body_++:++*get_force*( ) +
45 | <> = _body_++:++*get_rotation*( )
46 |
47 | [[body_local_to_world]]
48 | * <> = _body_++:++*local_to_world*(<>) +
49 | <> = _body_++:++*world_to_local*(<>) +
50 | <> = _body_++:++*get_velocity_at_world_point*(<>) +
51 | <> = _body_++:++*get_velocity_at_local_point*(<>) +
52 |
53 | [[body_apply_xxx]]
54 | * _body_++:++*apply_force_at_world_point*(_point_, _value_) +
55 | _body_++:++*apply_force_at_local_point*(_point_, _value_) +
56 | _body_++:++*apply_impulse_at_world_point*(_point_, _value_) +
57 | _body_++:++*apply_impulse_at_local_point*(_point_, _value_) +
58 | [small]#_point_, _value_: <>.#
59 |
60 | [[body_update]]
61 | * _body_++:++*update_position*(_dt_) +
62 | _body_++:++*update_velocity*(_gravity_, _damping_, _dt_) +
63 | _body_++:++*set_position_update_func*(_func_) +
64 | _body_++:++*set_velocity_update_func*(_func_) +
65 | [small]#_dt_, _damping_: float. +
66 | _gravity_: <>. +
67 | The update callbacks are executed as follows: +
68 | pass:[-] position update: *func(body, dt)*. +
69 | pass:[-] velocity update: *func(body, gravity, damping, dt)*.#
70 |
71 |
72 |
73 | [[body_sleep]]
74 | * _body_++:++*sleep*( ) +
75 | _body_++:++*sleep_with_group*([_group_]) +
76 | _body_++:++*activate*( ) +
77 | _body_++:++*activate_static*([_filter_]) +
78 | _boolean_ = _body_++:++*is_sleeping*( ) +
79 | [small]#_group_: <>. +
80 | _filter_: <>.#
81 |
82 |
83 | [[body_each_xxx]]
84 | * _body_++:++*each_shape*(_func_) +
85 | _body_++:++*each_constraint*(_func_) +
86 | _body_++:++*each_arbiter*(_func_) +
87 | [small]#Execute _func_ as *func(body, object)* for each object of the given type.#
88 |
89 |
--------------------------------------------------------------------------------
/src/gear_joint.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freegear_joint(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "gear_joint")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newgear_joint(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, GEAR_JOINT_MT, "gear_joint");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freegear_joint;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | body_t *a = checkbody(L, 1, NULL);
50 | body_t *b = checkbody(L, 2, NULL);
51 | double phase = luaL_checknumber(L, 3);
52 | double ratio = luaL_checknumber(L, 4);
53 | constraint_t *constraint = cpGearJointNew(a, b, phase, ratio);
54 | return newgear_joint(L, constraint);
55 | }
56 |
57 | SETDOUBLE(SetPhase, cpGearJointSetPhase, gear_joint)
58 | SETDOUBLE(SetRatio, cpGearJointSetRatio, gear_joint)
59 | GETDOUBLE(GetPhase, cpGearJointGetPhase, gear_joint)
60 | GETDOUBLE(GetRatio, cpGearJointGetRatio, gear_joint)
61 |
62 | DESTROY_FUNC(gear_joint)
63 |
64 | static const struct luaL_Reg Methods[] =
65 | {
66 | { "free", Destroy },
67 | { "set_phase", SetPhase },
68 | { "set_ratio", SetRatio },
69 | { "get_phase", GetPhase },
70 | { "get_ratio", GetRatio },
71 | { NULL, NULL } /* sentinel */
72 | };
73 |
74 | static const struct luaL_Reg MetaMethods[] =
75 | {
76 | { "__gc", Destroy },
77 | { NULL, NULL } /* sentinel */
78 | };
79 |
80 | static const struct luaL_Reg Functions[] =
81 | {
82 | { "gear_joint_new", Create },
83 | { NULL, NULL } /* sentinel */
84 | };
85 |
86 | void moonchipmunk_open_gear_joint(lua_State *L)
87 | {
88 | udata_define(L, GEAR_JOINT_MT, Methods, MetaMethods);
89 | udata_inherit(L, GEAR_JOINT_MT, CONSTRAINT_MT);
90 | luaL_setfuncs(L, Functions, 0);
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/src/rotary_limit_joint.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freerotary_limit_joint(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "rotary_limit_joint")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newrotary_limit_joint(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, ROTARY_LIMIT_JOINT_MT, "rotary_limit_joint");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freerotary_limit_joint;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | body_t *a = checkbody(L, 1, NULL);
50 | body_t *b = checkbody(L, 2, NULL);
51 | double min = luaL_checknumber(L, 3);
52 | double max = luaL_checknumber(L, 4);
53 | constraint_t *constraint = cpRotaryLimitJointNew(a, b, min, max);
54 | return newrotary_limit_joint(L, constraint);
55 | }
56 |
57 | SETDOUBLE(SetMin, cpRotaryLimitJointSetMin, rotary_limit_joint)
58 | SETDOUBLE(SetMax, cpRotaryLimitJointSetMax, rotary_limit_joint)
59 | GETDOUBLE(GetMin, cpRotaryLimitJointGetMin, rotary_limit_joint)
60 | GETDOUBLE(GetMax, cpRotaryLimitJointGetMax, rotary_limit_joint)
61 |
62 | DESTROY_FUNC(rotary_limit_joint)
63 |
64 | static const struct luaL_Reg Methods[] =
65 | {
66 | { "free", Destroy },
67 | { "set_min", SetMin },
68 | { "set_max", SetMax },
69 | { "get_min", GetMin },
70 | { "get_max", GetMax },
71 | { NULL, NULL } /* sentinel */
72 | };
73 |
74 | static const struct luaL_Reg MetaMethods[] =
75 | {
76 | { "__gc", Destroy },
77 | { NULL, NULL } /* sentinel */
78 | };
79 |
80 | static const struct luaL_Reg Functions[] =
81 | {
82 | { "rotary_limit_joint_new", Create },
83 | { NULL, NULL } /* sentinel */
84 | };
85 |
86 | void moonchipmunk_open_rotary_limit_joint(lua_State *L)
87 | {
88 | udata_define(L, ROTARY_LIMIT_JOINT_MT, Methods, MetaMethods);
89 | udata_inherit(L, ROTARY_LIMIT_JOINT_MT, CONSTRAINT_MT);
90 | luaL_setfuncs(L, Functions, 0);
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/src/ratchet_joint.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freeratchet_joint(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "ratchet_joint")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newratchet_joint(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, RATCHET_JOINT_MT, "ratchet_joint");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freeratchet_joint;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | body_t *a = checkbody(L, 1, NULL);
50 | body_t *b = checkbody(L, 2, NULL);
51 | double phase = luaL_checknumber(L, 3);
52 | double ratchet = luaL_checknumber(L, 4);
53 | constraint_t *constraint = cpRatchetJointNew(a, b, phase, ratchet);
54 | return newratchet_joint(L, constraint);
55 | }
56 |
57 | SETDOUBLE(SetAngle, cpRatchetJointSetAngle, ratchet_joint)
58 | SETDOUBLE(SetPhase, cpRatchetJointSetPhase, ratchet_joint)
59 | SETDOUBLE(SetRatchet, cpRatchetJointSetRatchet, ratchet_joint)
60 | GETDOUBLE(GetAngle, cpRatchetJointGetAngle, ratchet_joint)
61 | GETDOUBLE(GetPhase, cpRatchetJointGetPhase, ratchet_joint)
62 | GETDOUBLE(GetRatchet, cpRatchetJointGetRatchet, ratchet_joint)
63 |
64 | DESTROY_FUNC(ratchet_joint)
65 |
66 | static const struct luaL_Reg Methods[] =
67 | {
68 | { "free", Destroy },
69 | { "set_angle", SetAngle },
70 | { "set_phase", SetPhase },
71 | { "set_ratchet", SetRatchet },
72 | { "get_angle", GetAngle },
73 | { "get_phase", GetPhase },
74 | { "get_ratchet", GetRatchet },
75 | { NULL, NULL } /* sentinel */
76 | };
77 |
78 | static const struct luaL_Reg MetaMethods[] =
79 | {
80 | { "__gc", Destroy },
81 | { NULL, NULL } /* sentinel */
82 | };
83 |
84 | static const struct luaL_Reg Functions[] =
85 | {
86 | { "ratchet_joint_new", Create },
87 | { NULL, NULL } /* sentinel */
88 | };
89 |
90 | void moonchipmunk_open_ratchet_joint(lua_State *L)
91 | {
92 | udata_define(L, RATCHET_JOINT_MT, Methods, MetaMethods);
93 | udata_inherit(L, RATCHET_JOINT_MT, CONSTRAINT_MT);
94 | luaL_setfuncs(L, Functions, 0);
95 | }
96 |
97 |
--------------------------------------------------------------------------------
/src/pin_joint.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freepin_joint(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "pin_joint")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newpin_joint(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, PIN_JOINT_MT, "pin_joint");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freepin_joint;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | vec_t anchorA, anchorB;
50 | constraint_t *constraint;
51 | body_t *a = checkbody(L, 1, NULL);
52 | body_t *b = checkbody(L, 2, NULL);
53 | checkvec(L, 3, &anchorA);
54 | checkvec(L, 4, &anchorB);
55 | constraint = cpPinJointNew(a, b, anchorA, anchorB);
56 | return newpin_joint(L, constraint);
57 | }
58 |
59 | SETVEC(SetAnchorA, cpPinJointSetAnchorA, pin_joint)
60 | SETVEC(SetAnchorB, cpPinJointSetAnchorB, pin_joint)
61 | GETVEC(GetAnchorA, cpPinJointGetAnchorA, pin_joint)
62 | GETVEC(GetAnchorB, cpPinJointGetAnchorB, pin_joint)
63 | SETDOUBLE(SetDist, cpPinJointSetDist, pin_joint)
64 | GETDOUBLE(GetDist, cpPinJointGetDist, pin_joint)
65 |
66 | DESTROY_FUNC(pin_joint)
67 |
68 | static const struct luaL_Reg Methods[] =
69 | {
70 | { "free", Destroy },
71 | { "set_anchor_a", SetAnchorA },
72 | { "set_anchor_b", SetAnchorB },
73 | { "get_anchor_a", GetAnchorA },
74 | { "get_anchor_b", GetAnchorB },
75 | { "set_dist", SetDist },
76 | { "get_dist", GetDist },
77 | { NULL, NULL } /* sentinel */
78 | };
79 |
80 | static const struct luaL_Reg MetaMethods[] =
81 | {
82 | { "__gc", Destroy },
83 | { NULL, NULL } /* sentinel */
84 | };
85 |
86 | static const struct luaL_Reg Functions[] =
87 | {
88 | { "pin_joint_new", Create },
89 | { NULL, NULL } /* sentinel */
90 | };
91 |
92 | void moonchipmunk_open_pin_joint(lua_State *L)
93 | {
94 | udata_define(L, PIN_JOINT_MT, Methods, MetaMethods);
95 | udata_inherit(L, PIN_JOINT_MT, CONSTRAINT_MT);
96 | luaL_setfuncs(L, Functions, 0);
97 | }
98 |
99 |
100 |
--------------------------------------------------------------------------------
/src/pivot_joint.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freepivot_joint(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "pivot_joint")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newpivot_joint(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, PIVOT_JOINT_MT, "pivot_joint");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freepivot_joint;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | vec_t pivot, anchorA, anchorB;
50 | constraint_t *constraint;
51 | body_t *a = checkbody(L, 1, NULL);
52 | body_t *b = checkbody(L, 2, NULL);
53 | if(lua_isnoneornil(L, 4))
54 | {
55 | checkvec(L, 3, &pivot);
56 | constraint = cpPivotJointNew(a, b, pivot);
57 | }
58 | else
59 | {
60 | checkvec(L, 3, &anchorA);
61 | checkvec(L, 4, &anchorB);
62 | constraint = cpPivotJointNew2(a, b, anchorA, anchorB);
63 | }
64 | return newpivot_joint(L, constraint);
65 | }
66 |
67 | SETVEC(SetAnchorA, cpPivotJointSetAnchorA, pivot_joint)
68 | SETVEC(SetAnchorB, cpPivotJointSetAnchorB, pivot_joint)
69 | GETVEC(GetAnchorA, cpPivotJointGetAnchorA, pivot_joint)
70 | GETVEC(GetAnchorB, cpPivotJointGetAnchorB, pivot_joint)
71 |
72 | DESTROY_FUNC(pivot_joint)
73 |
74 | static const struct luaL_Reg Methods[] =
75 | {
76 | { "free", Destroy },
77 | { "set_anchor_a", SetAnchorA },
78 | { "set_anchor_b", SetAnchorB },
79 | { "get_anchor_a", GetAnchorA },
80 | { "get_anchor_b", GetAnchorB },
81 | { NULL, NULL } /* sentinel */
82 | };
83 |
84 | static const struct luaL_Reg MetaMethods[] =
85 | {
86 | { "__gc", Destroy },
87 | { NULL, NULL } /* sentinel */
88 | };
89 |
90 | static const struct luaL_Reg Functions[] =
91 | {
92 | { "pivot_joint_new", Create },
93 | { NULL, NULL } /* sentinel */
94 | };
95 |
96 | void moonchipmunk_open_pivot_joint(lua_State *L)
97 | {
98 | udata_define(L, PIVOT_JOINT_MT, Methods, MetaMethods);
99 | udata_inherit(L, PIVOT_JOINT_MT, CONSTRAINT_MT);
100 | luaL_setfuncs(L, Functions, 0);
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/src/groove_joint.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freegroove_joint(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "groove_joint")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newgroove_joint(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, GROOVE_JOINT_MT, "groove_joint");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freegroove_joint;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | vec_t grooveA, grooveB, anchorB;
50 | constraint_t *constraint;
51 | body_t *a = checkbody(L, 1, NULL);
52 | body_t *b = checkbody(L, 2, NULL);
53 | checkvec(L, 3, &grooveA);
54 | checkvec(L, 4, &grooveB);
55 | checkvec(L, 5, &anchorB);
56 | constraint = cpGrooveJointNew(a, b, grooveA, grooveB, anchorB);
57 | return newgroove_joint(L, constraint);
58 | }
59 |
60 | SETVEC(SetGrooveA, cpGrooveJointSetGrooveA, groove_joint)
61 | SETVEC(SetGrooveB, cpGrooveJointSetGrooveB, groove_joint)
62 | SETVEC(SetAnchorB, cpGrooveJointSetAnchorB, groove_joint)
63 | GETVEC(GetGrooveA, cpGrooveJointGetGrooveA, groove_joint)
64 | GETVEC(GetGrooveB, cpGrooveJointGetGrooveB, groove_joint)
65 | GETVEC(GetAnchorB, cpGrooveJointGetAnchorB, groove_joint)
66 |
67 | DESTROY_FUNC(groove_joint)
68 |
69 | static const struct luaL_Reg Methods[] =
70 | {
71 | { "free", Destroy },
72 | { "set_groove_a", SetGrooveA },
73 | { "set_groove_b", SetGrooveB },
74 | { "set_anchor_b", SetAnchorB },
75 | { "get_groove_a", GetGrooveA },
76 | { "get_groove_b", GetGrooveB },
77 | { "get_anchor_b", GetAnchorB },
78 | { NULL, NULL } /* sentinel */
79 | };
80 |
81 | static const struct luaL_Reg MetaMethods[] =
82 | {
83 | { "__gc", Destroy },
84 | { NULL, NULL } /* sentinel */
85 | };
86 |
87 | static const struct luaL_Reg Functions[] =
88 | {
89 | { "groove_joint_new", Create },
90 | { NULL, NULL } /* sentinel */
91 | };
92 |
93 | void moonchipmunk_open_groove_joint(lua_State *L)
94 | {
95 | udata_define(L, GROOVE_JOINT_MT, Methods, MetaMethods);
96 | udata_inherit(L, GROOVE_JOINT_MT, CONSTRAINT_MT);
97 | luaL_setfuncs(L, Functions, 0);
98 | }
99 |
100 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## MoonChipmunk: Lua bindings for Chipmunk2D
2 |
3 | MoonChipmunk is a Lua binding library for Scott Lembcke's [Chipmunk2D](http://chipmunk-physics.net/) physics engine.
4 |
5 | It runs on GNU/Linux and on Windows (MSYS2/MinGW) and requires
6 | [Lua](http://www.lua.org/) (>=5.3) and [Chipmunk2D](http://chipmunk-physics.net/downloads.php) (>= 7.0.3).
7 |
8 | _Author:_ _[Stefano Trettel](https://www.linkedin.com/in/stetre)_
9 |
10 | [](http://www.lua.org/)
11 |
12 | #### License
13 |
14 | MIT/X11 license (same as Lua). See [LICENSE](./LICENSE).
15 |
16 | #### Documentation
17 |
18 | See the [Reference Manual](https://stetre.github.io/moonchipmunk/doc/index.html).
19 |
20 | #### Getting and installing
21 |
22 | Setup the build environment as described [here](https://github.com/stetre/moonlibs), then:
23 |
24 | ```sh
25 | $ git clone https://github.com/stetre/moonchipmunk/
26 | $ cd moonchipmunk
27 | moonchipmunk$ make
28 | moonchipmunk$ sudo make install
29 | ```
30 |
31 | #### Example
32 |
33 | The example below is a port of the ["Hello Chipmunk (World)" example](http://chipmunk-physics.net/release/ChipmunkLatest-Docs/#Intro-HelloChipmunk) from the Chipmunk2D manual.
34 |
35 | Other examples, including a Lua port of the Chipmunk2D demos, can be found in the **examples/** directory.
36 |
37 | ```lua
38 | -- MoonChipmunk example: hello.lua
39 | local cp = require("moonchipmunk")
40 |
41 | -- Create an empty space and set the gravity for it.
42 | local space = cp.space_new()
43 | space:set_gravity({0, -100})
44 |
45 | -- Add a static line segment shape for the ground.
46 | -- We'll make it slightly tilted so the ball will roll off.
47 | -- We attach it to a static body to tell Chipmunk it shouldn't be movable.
48 | local ground = cp.segment_shape_new(space:get_static_body(), {-20, 5}, {20, -5}, 0)
49 | ground:set_friction(1)
50 | space:add_shape(ground)
51 |
52 | -- Now let's make a ball that falls onto the line and rolls off.
53 | -- First we need to make a body to hold the physical properties of the object.
54 | -- These include the mass, position, velocity, angle, etc. of the object.
55 | -- Then we attach collision shapes to the body to give it a size and shape.
56 | local radius = 5
57 | local mass = 1
58 | -- The moment of inertia is like mass for rotation
59 | -- Use the cp.moment_for*() functions to help you approximate it.
60 | local moment = cp.moment_for_circle(mass, 0, radius, {0, 0})
61 |
62 | -- The space:add*() methods return the thing that you are adding.
63 | -- It's convenient to create and add an object in one line.
64 | local ballBody = space:add_body(cp.body_new(mass, moment))
65 | ballBody:set_position({0, 15})
66 |
67 | -- Now we create the collision shape for the ball.
68 | -- You can create multiple collision shapes that point to the same body.
69 | -- They will all be attached to the body and move around to follow it.
70 | local ballShape = space:add_shape(cp.circle_shape_new(ballBody, radius, {0, 0}))
71 | ballShape:set_friction(0.7)
72 |
73 | -- Now that it's all set up, we simulate all the objects in the space by
74 | -- stepping forward through time in small increments called steps.
75 | -- It is *highly* recommended to use a fixed size time step.
76 | local timeStep = 1.0/60.0
77 | for time = 0, 2, timeStep do
78 | local pos = ballBody:get_position()
79 | local vel = ballBody:get_velocity()
80 | print(string.format(
81 | "Time is %5.2f. ballBody is at (%5.2f, %5.2f). It's velocity is (%5.2f, %5.2f)",
82 | time, pos[1], pos[2], vel[1], vel[2]))
83 | space:step(timeStep)
84 | end
85 |
86 | -- No need to delete objects here (they are are automatically deleted ad exit).
87 | ```
88 |
89 | The script can be executed at the shell prompt with the standard Lua interpreter:
90 |
91 | ```shell
92 | $ lua hello.lua
93 | ```
94 |
95 | #### See also
96 |
97 | * [MoonLibs - Graphics and Audio Lua Libraries](https://github.com/stetre/moonlibs).
98 |
--------------------------------------------------------------------------------
/src/slide_joint.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freeslide_joint(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "slide_joint")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newslide_joint(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, SLIDE_JOINT_MT, "slide_joint");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freeslide_joint;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | double min, max;
50 | vec_t anchorA, anchorB;
51 | constraint_t *constraint;
52 | body_t *a = checkbody(L, 1, NULL);
53 | body_t *b = checkbody(L, 2, NULL);
54 | checkvec(L, 3, &anchorA);
55 | checkvec(L, 4, &anchorB);
56 | min = luaL_checknumber(L, 5);
57 | max = luaL_checknumber(L, 6);
58 | constraint = cpSlideJointNew(a, b, anchorA, anchorB, min, max);
59 | return newslide_joint(L, constraint);
60 | }
61 |
62 | SETVEC(SetAnchorA, cpSlideJointSetAnchorA, slide_joint)
63 | SETVEC(SetAnchorB, cpSlideJointSetAnchorB, slide_joint)
64 | GETVEC(GetAnchorA, cpSlideJointGetAnchorA, slide_joint)
65 | GETVEC(GetAnchorB, cpSlideJointGetAnchorB, slide_joint)
66 | SETDOUBLE(SetMin, cpSlideJointSetMin, slide_joint)
67 | SETDOUBLE(SetMax, cpSlideJointSetMax, slide_joint)
68 | GETDOUBLE(GetMin, cpSlideJointGetMin, slide_joint)
69 | GETDOUBLE(GetMax, cpSlideJointGetMax, slide_joint)
70 |
71 | DESTROY_FUNC(slide_joint)
72 |
73 | static const struct luaL_Reg Methods[] =
74 | {
75 | { "free", Destroy },
76 | { "set_anchor_a", SetAnchorA },
77 | { "set_anchor_b", SetAnchorB },
78 | { "get_anchor_a", GetAnchorA },
79 | { "get_anchor_b", GetAnchorB },
80 | { "set_min", SetMin },
81 | { "set_max", SetMax },
82 | { "get_min", GetMin },
83 | { "get_max", GetMax },
84 | { NULL, NULL } /* sentinel */
85 | };
86 |
87 | static const struct luaL_Reg MetaMethods[] =
88 | {
89 | { "__gc", Destroy },
90 | { NULL, NULL } /* sentinel */
91 | };
92 |
93 | static const struct luaL_Reg Functions[] =
94 | {
95 | { "slide_joint_new", Create },
96 | { NULL, NULL } /* sentinel */
97 | };
98 |
99 | void moonchipmunk_open_slide_joint(lua_State *L)
100 | {
101 | udata_define(L, SLIDE_JOINT_MT, Methods, MetaMethods);
102 | udata_inherit(L, SLIDE_JOINT_MT, CONSTRAINT_MT);
103 | luaL_setfuncs(L, Functions, 0);
104 | }
105 |
106 |
--------------------------------------------------------------------------------
/src/circle.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | static int freecircle(lua_State *L, ud_t *ud)
29 | {
30 | shape_t *shape = (shape_t*)ud->handle;
31 | if(!candestroyshape(shape, ud)) return 0;
32 | if(!freeuserdata(L, ud, "circle")) return 0;
33 | shapedestroy(L, (shape_t*)shape);
34 | return 0;
35 | }
36 |
37 | static int newcircle(lua_State *L, shape_t *circle)
38 | {
39 | ud_t *ud;
40 | ud = newuserdata(L, circle, CIRCLE_MT, "circle");
41 | ud->parent_ud = NULL;
42 | ud->destructor = freecircle;
43 | return 1;
44 | }
45 |
46 | static int Create(lua_State *L)
47 | {
48 | shape_t *circle;
49 | vec_t offset;
50 | body_t *body = checkbody(L, 1, NULL);
51 | double radius = luaL_checknumber(L, 2);
52 | offset.x = offset.y = 0.0;
53 | optvec(L, 3, &offset);
54 | circle = cpCircleShapeNew(body, radius, offset);
55 | return newcircle(L, circle);
56 | }
57 |
58 | static int GetOffset(lua_State *L)
59 | {
60 | shape_t *circle = checkcircle(L, 1, NULL);
61 | vec_t offset = cpCircleShapeGetOffset(circle);
62 | pushvec(L, &offset);
63 | return 1;
64 | }
65 |
66 | static int SetOffset(lua_State *L)
67 | {
68 | vec_t offset;
69 | shape_t *circle = checkcircle(L, 1, NULL);
70 | checkvec(L, 2, &offset);
71 | cpCircleShapeSetOffset(circle, offset);
72 | return 0;
73 | }
74 |
75 | static int GetRadius(lua_State *L)
76 | {
77 | shape_t *circle = checkcircle(L, 1, NULL);
78 | double radius = cpCircleShapeGetRadius(circle);
79 | lua_pushnumber(L, radius);
80 | return 1;
81 | }
82 |
83 | static int SetRadius(lua_State *L)
84 | {
85 | shape_t *circle = checkcircle(L, 1, NULL);
86 | double radius = luaL_checknumber(L, 2);
87 | cpCircleShapeSetRadius(circle, radius);
88 | return 0;
89 | }
90 |
91 |
92 | DESTROY_FUNC(circle)
93 |
94 | static const struct luaL_Reg Methods[] =
95 | {
96 | { "free", Destroy },
97 | { "get_offset", GetOffset },
98 | { "get_radius", GetRadius },
99 | { "set_offset", SetOffset }, /* chipmunk_unsafe.h */
100 | { "set_radius", SetRadius }, /* chipmunk_unsafe.h */
101 | { NULL, NULL } /* sentinel */
102 | };
103 |
104 | static const struct luaL_Reg MetaMethods[] =
105 | {
106 | { "__gc", Destroy },
107 | { NULL, NULL } /* sentinel */
108 | };
109 |
110 | static const struct luaL_Reg Functions[] =
111 | {
112 | { "circle_shape_new", Create },
113 | { NULL, NULL } /* sentinel */
114 | };
115 |
116 | void moonchipmunk_open_circle(lua_State *L)
117 | {
118 | udata_define(L, CIRCLE_MT, Methods, MetaMethods);
119 | udata_inherit(L, CIRCLE_MT, SHAPE_MT);
120 | luaL_setfuncs(L, Functions, 0);
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/doc/datatypes.adoc:
--------------------------------------------------------------------------------
1 |
2 | [[datatypes]]
3 | == Data types
4 |
5 | In this document, the _float_ and _integer_ types denote Lua numbers, while other types
6 | such as _boolean_, _string_, etc denote standard Lua types. Note that _float_
7 | here just means 'floating point' as opposed to 'integer', and does not imply
8 | single-precision (all numbers are actually represented internally using double-precision).
9 |
10 | Angles are always expressed in radians.
11 |
12 | Vectors, matrices, bounding boxes, and colors are by default represented as Lua arrays containing
13 | _float_ elements (or arrays of arrays in the case of matrices). The meaning of the elements
14 | thus depends on their position, as detailed below, and there is no syntactic sugar
15 | such as _v.x_ and _v.y_ to access them (unless one enables <>).
16 |
17 | A few other Chipmunk2D structs are represented as string-indexed Lua tables, also described below.
18 |
19 | * [[vec]]
20 | [small]#*vec* = {_x_, _y_} +
21 | All elements are floats. +
22 | (Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__cp_vect.html[cpVect])#
23 |
24 | * [[mat]]
25 | [small]#*mat* = {{_a_, _c_, _tx_}, {_b_, _d_, _ty_}} +
26 | All elements are floats. +
27 | (Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_transform.html[cpTransform])#
28 |
29 | * [[bb]]
30 | [small]#*bb* = {_l_, _r_, _b_, _t_} +
31 | All elements are floats. +
32 | Beware that the order is different than in _cpBB_ (where the order is _l_, _b_, _r_, _t_). +
33 | (Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_b_b.html[cpBB])#
34 |
35 | * [[color]]
36 | [small]#*color* = {_r_, _g_, _b_, _a_} +
37 | All elements are floats, representing normalized color components (i.e. in the range _[0, 1]_). +
38 | (Rfr: cpSpaceDebugColor)#
39 |
40 | * [[shapefilter]]
41 | [small]#*shapefilter* = { +
42 | _group_: integer, +
43 | _categories_: integer, +
44 | _mask_: integer, +
45 | } (Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_shape_filter.html[cpShapeFilter])#
46 |
47 | * [[pointqueryinfo]]
48 | [small]#*pointqueryinfo* = { +
49 | _shape_: <>, +
50 | _point_: <>, +
51 | _distance_: float, +
52 | _gradient_: <>, +
53 | } (Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_point_query_info.html[cpPointQueryInfo])#
54 |
55 | * [[segmentqueryinfo]]
56 | [small]#*segmentqueryinfo* = { +
57 | _shape_: <>, +
58 | _point_: <>, +
59 | _normal_: <>, +
60 | _alpha_: float, +
61 | } (Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_segment_query_info.html[cpSegmentQueryInfo])#
62 |
63 | * [[contactpoint]]
64 | [small]#*contactpoint* = { +
65 | _a_: <>, +
66 | _b_: <>, +
67 | _distance_: float, +
68 | } (Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_contact_point_set.html[cpContactPointSet])#
69 |
70 | [[glmath_compat]]
71 | == GLMATH compatibility
72 |
73 | As an option, it is possible to instruct MoonChipmunk to return vectors, matrices, boxes, and colors
74 | as https://github.com/stetre/moonglmath[MoonGLMATH] types, instead of returning them as plain tables
75 | (which is the default).
76 | footnote:[MoonGLMATH types are convenient because they support operators and synctatic sugar, but I
77 | chose not to impose their use because one may want to use an alternative math library, or none at all.]
78 |
79 | In particular, when this functionality is enabled, functions and methods will return values
80 | of the following MoonGLMATH types: *vec2* instead of <>, *mat2x3* instead of <>, *box2* instead of <>, and *vec4* instead of <>.
81 |
82 | (Notice that for function arguments nothing changes, since the above MoonGLMATH types are compatible
83 | with the corresponding plain tables used by default, thus they can be used as function arguments in
84 | any case).
85 |
86 | Use the following functions to control GLMATH compatibility:
87 |
88 | * *glmath_compat*(_boolean_) +
89 | [small]#Enables/disables GLMATH compatibility (which by default is disabled). +
90 | Enabling this functionality requires MoonGLMATH to be installed.#
91 |
92 | * _boolean_ = *is_glmath_compat*( ) +
93 | [small]#Returns _true_ if GLMATH compatibility is enabled.#
94 |
95 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | lua_State *moonchipmunk_L;
29 |
30 | static void AtExit(void)
31 | {
32 | if(moonchipmunk_L)
33 | {
34 | enums_free_all(moonchipmunk_L);
35 | moonchipmunk_L = NULL;
36 | }
37 | }
38 |
39 | static int AddVersions(lua_State *L)
40 | {
41 | lua_pushstring(L, "_VERSION");
42 | lua_pushstring(L, "MoonChipmunk "MOONCHIPMUNK_VERSION);
43 | lua_settable(L, -3);
44 |
45 |
46 | lua_pushstring(L, "_CHIPMUNK_VERSION");
47 | // lua_pushfstring(L, "Chipmunk %d.%d.%d",
48 | // CP_VERSION_MAJOR, CP_VERSION_MINOR, CP_VERSION_RELEASE);
49 | lua_pushfstring(L, "Chipmunk %s", cpVersionString);
50 | lua_settable(L, -3);
51 |
52 | return 0;
53 | }
54 |
55 | static int AddConstants(lua_State *L)
56 | {
57 | lua_pushinteger(L, CP_NO_GROUP);
58 | lua_setfield(L, -2, "NO_GROUP");
59 |
60 | lua_pushinteger(L, CP_ALL_CATEGORIES);
61 | lua_setfield(L, -2, "ALL_CATEGORIES");
62 |
63 | lua_pushinteger(L, CP_WILDCARD_COLLISION_TYPE);
64 | lua_setfield(L, -2, "WILDCARD_COLLISION_TYPE");
65 | return 0;
66 | }
67 |
68 |
69 |
70 | static int IsGlmathCompat(lua_State *L)
71 | {
72 | lua_pushboolean(L, isglmathcompat());
73 | return 1;
74 | }
75 |
76 | static int GlmathCompat(lua_State *L)
77 | {
78 | int on = checkboolean(L, 1);
79 | glmathcompat(L, on);
80 | return 0;
81 | }
82 |
83 | static const struct luaL_Reg Functions[] =
84 | {
85 | { "is_glmath_compat", IsGlmathCompat },
86 | { "glmath_compat", GlmathCompat },
87 | { NULL, NULL } /* sentinel */
88 | };
89 |
90 | int luaopen_moonchipmunk(lua_State *L)
91 | /* Lua calls this function to load the module */
92 | {
93 | moonchipmunk_L = L;
94 |
95 | moonchipmunk_utils_init(L);
96 | atexit(AtExit);
97 |
98 | lua_newtable(L); /* the module table */
99 | moonchipmunk_open_enums(L);
100 | moonchipmunk_open_flags(L);
101 | AddVersions(L);
102 | AddConstants(L);
103 | luaL_setfuncs(L, Functions, 0);
104 | moonchipmunk_open_tracing(L);
105 | moonchipmunk_open_misc(L);
106 | moonchipmunk_open_space(L);
107 | moonchipmunk_open_body(L);
108 | moonchipmunk_open_shape(L);
109 | moonchipmunk_open_circle(L);
110 | moonchipmunk_open_segment(L);
111 | moonchipmunk_open_poly(L);
112 | moonchipmunk_open_constraint(L);
113 | moonchipmunk_open_pin_joint(L);
114 | moonchipmunk_open_slide_joint(L);
115 | moonchipmunk_open_pivot_joint(L);
116 | moonchipmunk_open_groove_joint(L);
117 | moonchipmunk_open_damped_spring(L);
118 | moonchipmunk_open_damped_rotary_spring(L);
119 | moonchipmunk_open_rotary_limit_joint(L);
120 | moonchipmunk_open_ratchet_joint(L);
121 | moonchipmunk_open_gear_joint(L);
122 | moonchipmunk_open_simple_motor(L);
123 | moonchipmunk_open_arbiter(L);
124 | moonchipmunk_open_collision_handler(L);
125 |
126 | #if 0 //@@
127 | /* Add functions implemented in Lua */
128 | lua_pushvalue(L, -1); lua_setglobal(L, "moonchipmunk");
129 | if(luaL_dostring(L, "require('moonchipmunk.datastructs')") != 0) lua_error(L);
130 | lua_pushnil(L); lua_setglobal(L, "moonchipmunk");
131 | #endif
132 |
133 | return 1;
134 | }
135 |
136 |
--------------------------------------------------------------------------------
/src/constraint.h:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #ifndef constraintDEFINED
27 | #define constraintDEFINED
28 |
29 | /* Common functions for constraints */
30 |
31 | #define SETDOUBLE(Func, func, what) /* void func(what, double) */ \
32 | static int Func(lua_State *L) \
33 | { \
34 | constraint_t *constraint = check##what(L, 1, NULL); \
35 | double val = luaL_checknumber(L, 2); \
36 | func(constraint, val); \
37 | return 0; \
38 | }
39 |
40 | #define SETBOOLEAN(Func, func, what) /* void func(what, bool) */ \
41 | static int Func(lua_State *L) \
42 | { \
43 | constraint_t *constraint = check##what(L, 1, NULL); \
44 | int val = checkboolean(L, 2); \
45 | func(constraint, val); \
46 | return 0; \
47 | }
48 |
49 | #define SETVEC(Func, func, what) /* void func(what, vec_t) */ \
50 | static int Func(lua_State *L) \
51 | { \
52 | vec_t val; \
53 | constraint_t *constraint = check##what(L, 1, NULL); \
54 | checkvec(L, 2, &val); \
55 | func(constraint, val); \
56 | return 0; \
57 | }
58 |
59 | #define GETDOUBLE(Func, func, what) /* double func(what) */ \
60 | static int Func(lua_State *L) \
61 | { \
62 | constraint_t *constraint = check##what(L, 1, NULL); \
63 | double val = func(constraint); \
64 | lua_pushnumber(L, val); \
65 | return 1; \
66 | }
67 |
68 | #define GETBOOLEAN(Func, func, what) /* bool func(what) */ \
69 | static int Func(lua_State *L) \
70 | { \
71 | constraint_t *constraint = check##what(L, 1, NULL); \
72 | int val = func(constraint); \
73 | lua_pushboolean(L, val); \
74 | return 1; \
75 | }
76 |
77 | #define GETVEC(Func, func, what) /* vec_t func(what) */ \
78 | static int Func(lua_State *L) \
79 | { \
80 | constraint_t *constraint = check##what(L, 1, NULL); \
81 | vec_t val = func(constraint); \
82 | pushvec(L, &val); \
83 | return 1; \
84 | }
85 |
86 | #endif /* constraintDEFINED */
87 |
--------------------------------------------------------------------------------
/doc/shape.adoc:
--------------------------------------------------------------------------------
1 |
2 | [[shape]]
3 | === Shapes
4 |
5 | [small]#Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__cp_shape.html[cpShape].#
6 |
7 | [[shape_new]]
8 | Constructors and specialized methods are available for the following subtypes:
9 |
10 | * <>
11 | * <>
12 | * <>
13 |
14 | Common methods:
15 |
16 | [[shape_free]]
17 | * _shape_++:++*free*( ) +
18 | [small]#Delete _shape_.#
19 |
20 | [[shape_set_body]]
21 | * _shape_++:++*set_body*(<>) +
22 | <> = _shape_++:++*get_body*( ) +
23 | <> = _shape_++:++*get_space*( ) +
24 |
25 | [[shape_update]]
26 | * <> = _shape_++:++*update*(_transform_) +
27 | [small]#_transform_: <>.#
28 |
29 | [[shape_set_float]]
30 | * _shape_++:++*set_mass*(_value_) +
31 | _shape_++:++*set_density*(_value_) +
32 | _shape_++:++*set_elasticity*(_value_) +
33 | _shape_++:++*set_friction*(_value_) +
34 | _value_ = _shape_++:++*get_mass*( ) +
35 | _value_ = _shape_++:++*get_moment*( ) +
36 | _value_ = _shape_++:++*get_area*( ) +
37 | _value_ = _shape_++:++*get_density*( ) +
38 | _value_ = _shape_++:++*get_elasticity*( ) +
39 | _value_ = _shape_++:++*get_friction*( ) +
40 | [small]#_value_: float.#
41 |
42 | [[shape_set_vec]]
43 | * _shape_++:++*set_surface_velocity*(<>) +
44 | <> = _shape_++:++*get_surface_velocity*( ) +
45 | <> = _shape_++:++*get_center_of_gravity*( ) +
46 |
47 | [[shape_get_bb]]
48 | * <> = _shape_++:++*get_bb*( ) +
49 | <> = _shape_++:++*cache_bb*( ) +
50 |
51 | [[shape_set_sensor]]
52 | * _shape_++:++*set_sensor*(_boolean_) +
53 | _boolean_ = _shape_++:++*get_sensor*( ) +
54 |
55 | [[shape_set_filter]]
56 | * _shape_++:++*set_filter*(<>) +
57 | <> = _shape_++:++*get_filter*( ) +
58 |
59 | [[shape_filter_new]]
60 | * <> = *shape_filter_new*(_group_, _categories_, _bitmask_) +
61 | <> = *shape_filter_all*( ) +
62 | <> = *shape_filter_none*( ) +
63 | [small]#Shape filter constructor and built-in shape filters (_CP_SHAPE_FILTER_XXX_). +
64 | Note that a shape filter is a plain Lua table, and thus may also be manually constructed.#
65 |
66 | [[shape_set_collision_type]]
67 | * _shape_++:++*set_collision_type*(value) +
68 | value = _shape_++:++*get_collision_type*( ) +
69 | [small]#_value_: integer.#
70 |
71 | [[shape_collide]]
72 | * _normal_|_nil_, _{points}_ = *shapes_collide*(<>, <>) +
73 | _normal_|_nil_, _{points}_ = _shape_++:++*collide*(<>) +
74 | [small]#Return _nil_ if shape do not collide. +
75 | _normal_ = <>. +
76 | _{points}_ = {<>}.#
77 |
78 | [[shape_query]]
79 | * <> = _shape_++:++*point_query*(_point_) +
80 | <>|_nil_ = _shape_++:++*segment_query*(_a_, _b_, _radius_) +
81 | [small]#_point_, _a_, _b_: <>.
82 | _radius_: float.#
83 |
84 | [[circle]]
85 | ==== circle
86 |
87 | * <> = *circle_shape_new*(<>, _radius_, [_offset_]) +
88 | _shape_++:++*set_radius*(_radius_) _UNSAFE_ +
89 | _shape_++:++*set_offset*(_offset_) _UNSAFE_ +
90 | _radius_ = _shape_++:++*get_radius*( ) +
91 | _offset_ = _shape_++:++*get_offset*( ) +
92 | [small]#_radius_: float. +
93 | _offset_: <> (defaults to _{0, 0}_).#
94 |
95 |
96 | [[segment]]
97 | ==== segment
98 |
99 | * <> = *segment_shape_new*(<>, _a_, _b_, _radius_) +
100 | _shape_++:++*set_radius*(_radius_) _UNSAFE_ +
101 | _shape_++:++*set_endpoints*(_a_, _b_) _UNSAFE_ +
102 | _shape_++:++*set_neighbors*(_prev_, _next_) _UNSAFE_ +
103 | _radius_ = _shape_++:++*get_radius*( ) +
104 | _a_, _b_ = _shape_++:++*get_endpoints*( ) +
105 | _normal_ = _shape_++:++*get_normal*( ) +
106 | [small]#_a_, _b_, _prev_, _next_, _normal_: <>. +
107 | _radius_: float.#
108 |
109 | [[poly]]
110 | ==== poly
111 |
112 | * <> = *poly_shape_new*(<>, _{verts}_, _radius_, [_transform_]) +
113 | <> = *box_shape_new*(<>, _width_, _height_, _radius_) +
114 | <> = *box_shape_new*(<>, <>, _radius_) +
115 | _shape_++:++*set_radius*(_radius_) _UNSAFE_ +
116 | _shape_++:++*set_verts*(_{verts}_, [_transform_]) _UNSAFE_ +
117 | _radius_ = _shape_++:++*get_radius*( ) +
118 | _{verts}_ = _shape_++:++*get_verts*( ) +
119 | _nverts_ = _shape_++:++*get_count*( ) +
120 | [small]#_{verts}_: {<>}. +
121 | _radius_, _width_, _height_: float. +
122 | _transform_: <> (defaults to the identity transform).#
123 |
124 |
--------------------------------------------------------------------------------
/examples/demo/01-pyramid-stack.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local cp = require("moonchipmunk")
5 | local toolbox = require("moonchipmunk.toolbox")
6 |
7 | local infinity = math.huge
8 | local fmt = string.format
9 |
10 | -- Initializations ------------------------------------------------------------
11 |
12 | local TITLE = "Pyramid Stack"
13 | local FW, FH = 640, 480 -- width and height of the field
14 | local W, H = 1024, 768 -- width and height of the window
15 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
16 |
17 | glfw.version_hint(3, 3, 'core')
18 | glfw.window_hint('samples', 32)
19 | local window = glfw.create_window(W, H, TITLE)
20 | glfw.make_context_current(window)
21 | gl.init()
22 | toolbox.init(W, H)
23 | local camera = toolbox.camera()
24 |
25 | local function resize(window, width, height)
26 | W, H = width, height
27 | toolbox.resize(W, H)
28 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
29 | gl.viewport(0, 0, W, H)
30 | end
31 |
32 | glfw.set_window_size_callback(window, resize)
33 | resize(window, W, H)
34 |
35 | local space = cp.space_new()
36 | space:set_iterations(30)
37 | space:set_gravity({0, -100})
38 | space:set_sleep_time_threshold(0.5)
39 | space:set_collision_slop(0.5)
40 | local grabber = toolbox.grabber(window, space)
41 | local grabbable, not_grabbable = grabber:filters()
42 |
43 | local static_body = space:get_static_body()
44 | -- Create segments around the edge of the screen.
45 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,-240}, {-320,240}, 0.0))
46 | shape:set_elasticity(1.0)
47 | shape:set_friction(1.0)
48 | shape:set_filter(not_grabbable)
49 | local shape = space:add_shape(cp.segment_shape_new(static_body, {320,-240}, {320,240}, 0.0))
50 | shape:set_elasticity(1.0)
51 | shape:set_friction(1.0)
52 | shape:set_filter(not_grabbable)
53 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,-240}, {320,-240}, 0.0))
54 | shape:set_elasticity(1.0)
55 | shape:set_friction(1.0)
56 | shape:set_filter(not_grabbable)
57 | -- Add lots of boxes.
58 | for i=0, 13 do
59 | for j=0,i do
60 | local body = space:add_body(cp.body_new(1.0, cp.moment_for_box(1.0, 30.0, 30.0)))
61 | body:set_position({j*32 - i*16, 300 - i*32})
62 | shape = space:add_shape(cp.box_shape_new(body, 30.0, 30.0, 0.5))
63 | shape:set_elasticity(0.0)
64 | shape:set_friction(0.8)
65 | end
66 | end
67 | -- Add a ball to make things more interesting
68 | local radius = 15.0
69 | local body = space:add_body(cp.body_new(10.0, cp.moment_for_circle(10.0, 0.0, radius, {0, 0})))
70 | body:set_position({0, -240 + radius+5})
71 | local shape = space:add_shape(cp.circle_shape_new(body, radius, {0, 0}))
72 | shape:set_elasticity(0.0)
73 | shape:set_friction(0.9)
74 |
75 | -- Input handling -------------------------------------------------------------
76 |
77 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
78 | local keys = {} -- keys[k] = true if key k is pressed
79 |
80 | glfw.set_key_callback(window, function(window, key, scancode, action)
81 | if key == 'escape' and action == 'press' then
82 | glfw.set_window_should_close(window, true)
83 | elseif key == 'f11' and action == 'press' then
84 | toggle_fullscreen()
85 | else
86 | keys[key] = action ~= 'release'
87 | end
88 | end)
89 |
90 | glfw.set_cursor_pos_callback(window, function(window, x, y)
91 | grabber:cursor_pos_callback(x, y)
92 | end)
93 |
94 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
95 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
96 | end)
97 |
98 |
99 | -- Game loop ------------------------------------------------------------------
100 | local timer = toolbox.frame_timer()
101 | local spf = 1/60 -- 1 / desired fps
102 | local fdt = 1/180 -- fixed dt for physics updates
103 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
104 | local n, dt
105 |
106 | local renderer = toolbox.renderer(space)
107 |
108 | collectgarbage()
109 | collectgarbage('stop')
110 | while not glfw.window_should_close(window) do
111 | glfw.wait_events_timeout(spf)
112 | dt = timer:update() -- duration of the current frame
113 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
114 |
115 | space:step(fdt, n)
116 | grabber:step(fdt, n)
117 |
118 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
119 | gl.clear_color(BG_COLOR)
120 | gl.clear('color')
121 | renderer:begin()
122 | space:debug_draw()
123 | renderer:done()
124 |
125 | glfw.swap_buffers(window)
126 | collectgarbage()
127 | end
128 |
129 | toolbox.cleanup()
130 |
131 |
--------------------------------------------------------------------------------
/examples/demo/05-pyramid-topple.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 |
8 | cp.glmath_compat(true)
9 | local pi, infinity = math.pi, math.huge
10 | local sin, cos, abs = math.sin, math.cos, math.abs
11 | local fmt = string.format
12 | local vec2 = glmath.vec2
13 |
14 | -- Initializations ------------------------------------------------------------
15 |
16 | local TITLE = "Pyramid Topple"
17 | local FW, FH = 640, 480 -- width and height of the field
18 | local W, H = 1024, 768 -- window width and height
19 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
20 |
21 | glfw.version_hint(3, 3, 'core')
22 | glfw.window_hint('samples', 32)
23 | local window = glfw.create_window(W, H, TITLE)
24 | glfw.make_context_current(window)
25 | gl.init()
26 | toolbox.init(W, H)
27 | local camera = toolbox.camera()
28 |
29 | local function resize(window, width, height)
30 | W, H = width, height
31 | toolbox.resize(W, H)
32 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
33 | gl.viewport(0, 0, W, H)
34 | end
35 |
36 | glfw.set_window_size_callback(window, resize)
37 | resize(window, W, H)
38 |
39 | -- Demo inits -----------------------------------------------------------------
40 |
41 | local space = cp.space_new()
42 | local grabber = toolbox.grabber(window, space)
43 | local grabbable, not_grabbable = grabber:filters()
44 | space:set_iterations(30)
45 | space:set_gravity({0, -300})
46 | space:set_sleep_time_threshold(0.5)
47 | space:set_collision_slop(0.5)
48 | -- Add a floor.
49 | local shape = cp.segment_shape_new(space:get_static_body(),{-600,-240}, {600,-240}, 0.0)
50 | space:add_shape(shape)
51 | shape:set_elasticity(1.0)
52 | shape:set_friction(1.0)
53 | shape:set_filter(not_grabbable)
54 |
55 | -- Add the dominoes.
56 | local n, width, height = 12, 4.0, 30.0
57 | local n = 12
58 |
59 | local function add_domino(space, pos, flipped)
60 | local mass, radius = 1.0, 0.5
61 | local moment = cp.moment_for_box(mass, width, height)
62 | local body = space:add_body(cp.body_new(mass, moment))
63 | body:set_position(pos)
64 | local shape
65 | if flipped then
66 | shape = cp.box_shape_new(body, height, width, 0.0)
67 | else
68 | shape = cp.box_shape_new(body, width - radius*2.0, height, radius)
69 | end
70 | space:add_shape(shape)
71 | shape:set_elasticity(0.0)
72 | shape:set_friction(0.6)
73 | end
74 |
75 | for i=0, n-1 do
76 | for j=0, (n-i-1) do
77 | local offset = vec2((j-(n-1-i)*0.5)*1.5*height, (i+0.5)*(height+2*width)-width-240)
78 | add_domino(space, offset, false)
79 | add_domino(space, offset+vec2(0, (height + width)/2.0), true)
80 | if j == 0 then
81 | add_domino(space, offset + vec2(0.5*(width - height), height + width), false)
82 | end
83 | if j ~= (n-i-1) then
84 | add_domino(space, offset + vec2(height*0.75, (height + 3*width)/2.0), true)
85 | else
86 | add_domino(space, offset + vec2(0.5*(height - width), height + width), false)
87 | end
88 | end
89 | end
90 |
91 | -- Input handling -------------------------------------------------------------
92 |
93 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
94 | local keys = {} -- keys[k] = true if key k is pressed
95 |
96 | glfw.set_key_callback(window, function(window, key, scancode, action)
97 | if key == 'escape' and action == 'press' then
98 | glfw.set_window_should_close(window, true)
99 | elseif key == 'f11' and action == 'press' then
100 | toggle_fullscreen()
101 | else
102 | keys[key] = action ~= 'release'
103 | end
104 | end)
105 |
106 | glfw.set_cursor_pos_callback(window, function(window, x, y)
107 | grabber:cursor_pos_callback(x, y)
108 | end)
109 |
110 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
111 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
112 | end)
113 |
114 | -- Game loop ------------------------------------------------------------------
115 | local timer = toolbox.frame_timer()
116 | local spf = 1/60 -- 1 / desired fps
117 | local fdt = 1/180 -- fixed dt for physics updates
118 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
119 | local n, dt
120 |
121 | local renderer = toolbox.renderer(space)
122 |
123 | collectgarbage()
124 | collectgarbage('stop')
125 | while not glfw.window_should_close(window) do
126 | glfw.wait_events_timeout(spf)
127 | dt = timer:update() -- duration of the current frame
128 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
129 |
130 | space:step(fdt, n)
131 | grabber:step(fdt, n)
132 |
133 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
134 | gl.clear_color(BG_COLOR)
135 | gl.clear('color')
136 | renderer:begin()
137 | space:debug_draw()
138 | renderer:done()
139 |
140 | glfw.swap_buffers(window)
141 | collectgarbage()
142 | end
143 |
144 | toolbox.cleanup()
145 |
146 |
--------------------------------------------------------------------------------
/src/flags.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | #define ADD(c) do { lua_pushinteger(L, CP_##c); lua_setfield(L, -2, #c); } while(0)
29 |
30 | /* checkkkflags: accepts a list of strings starting from index=arg
31 | * pushxxxflags -> pushes a list of strings
32 | */
33 |
34 | /*----------------------------------------------------------------------*
35 | | cpSpaceDebugDrawFlags
36 | *----------------------------------------------------------------------*/
37 |
38 | static int checkdebugdrawflags(lua_State *L, int arg)
39 | {
40 | const char *s;
41 | int flags = 0;
42 |
43 | while(lua_isstring(L, arg))
44 | {
45 | s = lua_tostring(L, arg++);
46 | #define CASE(CODE,str) if((strcmp(s, str)==0)) do { flags |= CODE; goto done; } while(0)
47 | CASE(CP_SPACE_DEBUG_DRAW_SHAPES, "shapes");
48 | CASE(CP_SPACE_DEBUG_DRAW_CONSTRAINTS, "constraints");
49 | CASE(CP_SPACE_DEBUG_DRAW_COLLISION_POINTS, "points");
50 | #undef CASE
51 | return luaL_argerror(L, --arg, badvalue(L,s));
52 | done: ;
53 | }
54 |
55 | return flags;
56 | }
57 |
58 | static int pushdebugdrawflags(lua_State *L, int flags)
59 | {
60 | int n = 0;
61 |
62 | #define CASE(CODE,str) do { if( flags & CODE) { lua_pushstring(L, str); n++; } } while(0)
63 | CASE(CP_SPACE_DEBUG_DRAW_SHAPES, "shapes");
64 | CASE(CP_SPACE_DEBUG_DRAW_CONSTRAINTS, "constraints");
65 | CASE(CP_SPACE_DEBUG_DRAW_COLLISION_POINTS, "points");
66 | #undef CASE
67 |
68 | return n;
69 | }
70 |
71 | static int DebugDrawFlags(lua_State *L)
72 | {
73 | if(lua_type(L, 1) == LUA_TNUMBER)
74 | return pushdebugdrawflags(L, luaL_checkinteger(L, 1));
75 | lua_pushinteger(L, checkdebugdrawflags(L, 1));
76 | return 1;
77 | }
78 |
79 | #define Add_DebugDrawFlags(L) \
80 | ADD(SPACE_DEBUG_DRAW_SHAPES);\
81 | ADD(SPACE_DEBUG_DRAW_CONSTRAINTS);\
82 | ADD(SPACE_DEBUG_DRAW_COLLISION_POINTS);\
83 |
84 | /*----------------------------------------------------------------------*/
85 |
86 | static int AddConstants(lua_State *L) /* cp.XXX constants for CP_XXX values */
87 | {
88 | Add_DebugDrawFlags(L);
89 | return 0;
90 | }
91 |
92 | static const struct luaL_Reg Functions[] =
93 | {
94 | { "debugdrawflags", DebugDrawFlags },
95 | { NULL, NULL } /* sentinel */
96 | };
97 |
98 |
99 | void moonchipmunk_open_flags(lua_State *L)
100 | {
101 | AddConstants(L);
102 | luaL_setfuncs(L, Functions, 0);
103 | }
104 |
105 |
106 | #if 0 // scaffolding
107 |
108 | /*----------------------------------------------------------------------*
109 | |
110 | *----------------------------------------------------------------------*/
111 |
112 | static int checkzzz(lua_State *L, int arg)
113 | {
114 | const char *s;
115 | int flags = 0;
116 |
117 | while(lua_isstring(L, arg))
118 | {
119 | s = lua_tostring(L, arg++);
120 | #define CASE(CODE,str) if((strcmp(s, str)==0)) do { flags |= CODE; goto done; } while(0)
121 | CASE(ZZZ_, "");
122 | #undef CASE
123 | return luaL_argerror(L, --arg, badvalue(L,s));
124 | done: ;
125 | }
126 |
127 | return flags;
128 | }
129 |
130 | static int pushzzz(lua_State *L, int flags)
131 | {
132 | int n = 0;
133 |
134 | #define CASE(CODE,str) do { if( flags & CODE) { lua_pushstring(L, str); n++; } } while(0)
135 | CASE(ZZZ_, "");
136 | #undef CASE
137 |
138 | return n;
139 | }
140 |
141 | static int Zzz(lua_State *L)
142 | {
143 | if(lua_type(L, 1) == LUA_TNUMBER)
144 | return pushzzz(L, luaL_checkinteger(L, 1));
145 | lua_pushinteger(L, checkzzz(L, 1));
146 | return 1;
147 | }
148 |
149 | Add_Zzz(L);
150 | { "zzz", Zzz },
151 | #define Add_Zzz(L) \
152 | ADD(ZZZ_);\
153 |
154 | #endif
155 |
156 |
--------------------------------------------------------------------------------
/src/segment.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | static int freesegment(lua_State *L, ud_t *ud)
29 | {
30 | shape_t *shape = (shape_t*)ud->handle;
31 | if(!candestroyshape(shape, ud)) return 0;
32 | if(!freeuserdata(L, ud, "segment")) return 0;
33 | shapedestroy(L, (shape_t*)shape);
34 | return 0;
35 | }
36 |
37 | static int newsegment(lua_State *L, shape_t *segment)
38 | {
39 | ud_t *ud;
40 | ud = newuserdata(L, segment, SEGMENT_MT, "segment");
41 | ud->parent_ud = NULL;
42 | ud->destructor = freesegment;
43 | return 1;
44 | }
45 |
46 | static int Create(lua_State *L)
47 | {
48 | shape_t *segment;
49 | vec_t a, b;
50 | double radius;
51 | body_t *body = checkbody(L, 1, NULL);
52 | checkvec(L, 2, &a);
53 | checkvec(L, 3, &b);
54 | radius = luaL_checknumber(L, 4);
55 | segment = cpSegmentShapeNew(body, a, b, radius);
56 | return newsegment(L, segment);
57 | }
58 |
59 | static int SetNeighbors(lua_State *L)
60 | {
61 | vec_t prev, next;
62 | shape_t *segment = checksegment(L, 1, NULL);
63 | checkvec(L, 2, &prev);
64 | checkvec(L, 3, &next);
65 | cpSegmentShapeSetNeighbors(segment, prev, next);
66 | return 0;
67 | }
68 |
69 | #if 0
70 | static int GetA(lua_State *L)
71 | {
72 | shape_t *segment = checksegment(L, 1, NULL);
73 | vec_t a = cpSegmentShapeGetA(segment);
74 | pushvec(L, &a);
75 | return 1;
76 | }
77 |
78 | static int GetB(lua_State *L)
79 | {
80 | shape_t *segment = checksegment(L, 1, NULL);
81 | vec_t b = cpSegmentShapeGetB(segment);
82 | pushvec(L, &b);
83 | return 1;
84 | }
85 | #endif
86 |
87 | static int GetEndpoints(lua_State *L)
88 | {
89 | shape_t *segment = checksegment(L, 1, NULL);
90 | vec_t a = cpSegmentShapeGetA(segment);
91 | vec_t b = cpSegmentShapeGetB(segment);
92 | pushvec(L, &a);
93 | pushvec(L, &b);
94 | return 2;
95 | }
96 |
97 | static int SetEndpoints(lua_State *L)
98 | {
99 | vec_t a, b;
100 | shape_t *segment = checksegment(L, 1, NULL);
101 | checkvec(L, 2, &a);
102 | checkvec(L, 3, &b);
103 | cpSegmentShapeSetEndpoints(segment, a, b);
104 | return 0;
105 | }
106 |
107 | static int GetNormal(lua_State *L)
108 | {
109 | shape_t *segment = checksegment(L, 1, NULL);
110 | vec_t n = cpSegmentShapeGetNormal(segment);
111 | pushvec(L, &n);
112 | return 1;
113 | }
114 |
115 | static int GetRadius(lua_State *L)
116 | {
117 | shape_t *segment = checksegment(L, 1, NULL);
118 | double radius = cpSegmentShapeGetRadius(segment);
119 | lua_pushnumber(L, radius);
120 | return 1;
121 | }
122 |
123 | static int SetRadius(lua_State *L)
124 | {
125 | shape_t *segment = checksegment(L, 1, NULL);
126 | double radius = luaL_checknumber(L, 2);
127 | cpSegmentShapeSetRadius(segment, radius);
128 | return 0;
129 | }
130 |
131 | DESTROY_FUNC(segment)
132 |
133 | static const struct luaL_Reg Methods[] =
134 | {
135 | { "free", Destroy },
136 | { "set_neighbors", SetNeighbors },
137 | // { "get_a", GetA },
138 | // { "get_b", GetB },
139 | { "get_normal", GetNormal },
140 | { "get_endpoints", GetEndpoints },
141 | { "set_endpoints", SetEndpoints }, /* chipmunk_unsafe.h */
142 | { "get_radius", GetRadius },
143 | { "set_radius", SetRadius }, /* chipmunk_unsafe.h */
144 | { NULL, NULL } /* sentinel */
145 | };
146 |
147 | static const struct luaL_Reg MetaMethods[] =
148 | {
149 | { "__gc", Destroy },
150 | { NULL, NULL } /* sentinel */
151 | };
152 |
153 | static const struct luaL_Reg Functions[] =
154 | {
155 | { "segment_shape_new", Create },
156 | { NULL, NULL } /* sentinel */
157 | };
158 |
159 | void moonchipmunk_open_segment(lua_State *L)
160 | {
161 | udata_define(L, SEGMENT_MT, Methods, MetaMethods);
162 | udata_inherit(L, SEGMENT_MT, SHAPE_MT);
163 | luaL_setfuncs(L, Functions, 0);
164 | }
165 |
166 |
--------------------------------------------------------------------------------
/examples/toolboxtest.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 | --local game = require("game")
8 |
9 | local vec2, vec3, vec4 = glmath.vec2, glmath.vec3, glmath.vec4
10 | local fmt = string.format
11 |
12 | -- Initializations ------------------------------------------------------------
13 |
14 | local TITLE = "Prova!"
15 | local FW, FH = 640, 480 -- width and height of the field
16 | local W, H = 1024, 768 -- window width and height
17 |
18 | local WHITE = {1, 1, 1, 1}
19 | local RED = {1, 0, 0, 1}
20 | local GREEN = {0, 1, 0, 1}
21 | local BLUE = {0, 0, 1, 1}
22 |
23 | glfw.version_hint(3, 3, 'core')
24 | glfw.window_hint('samples', 32)
25 | local window = glfw.create_window(W, H, TITLE)
26 | glfw.make_context_current(window)
27 | gl.init()
28 | toolbox.init(W, H, true)
29 | local camera = toolbox.camera(vec3(0, 0, 0))
30 | --game.init(W, H)
31 |
32 | local view, projection
33 | local function set_matrices()
34 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
35 | toolbox.resize(W, H)
36 | end
37 |
38 | local function resize(window, w, h)
39 | W, H = w, h
40 | set_matrices()
41 | --game.resize(W, H)
42 | gl.viewport(0, 0, W, H)
43 | end
44 |
45 | glfw.set_window_size_callback(window, resize)
46 | resize(window, W, H)
47 |
48 | local space = cp.space_new()
49 | local renderer = toolbox.renderer(space)
50 |
51 | -- Fonts ----------------------------------------------------------------------
52 | local font = toolbox.font("ttf-bitstream-vera-1.10/VeraMoBd.ttf", .3)
53 |
54 | -- Sprites --------------------------------------------------------------------
55 | local face = toolbox.sprite("sprites/awesomeface.png", 'rgba')
56 | local block = toolbox.sprite("sprites/block.png", 'rgb')
57 |
58 | -- Sounds ---------------------------------------------------------------------
59 | local shoot = toolbox.sound_sample("sounds/Shoot_00.wav")
60 | local explosion = toolbox.sound_sample("sounds/Explosion_00.wav")
61 | local jinglewin = toolbox.sound_sample("sounds/Jingle_Win_00.wav")
62 |
63 | local function playsoundevery(sample, interval)
64 | local sample = sample
65 | local interval = interval
66 | local t = 0
67 | return function(dt)
68 | t = t+dt
69 | if t >= interval then sample:play() t = 0 end
70 | end
71 | end
72 |
73 | local playshoot = playsoundevery(shoot, 1)
74 | local playexplosion = playsoundevery(explosion, 2.3)
75 | local playjinglewin = playsoundevery(jinglewin, 2.7)
76 |
77 | -- Input handling -------------------------------------------------------------
78 |
79 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
80 | local keys = {} -- keys[k] = true if key k is pressed
81 |
82 | glfw.set_key_callback(window, function(window, key, scancode, action)
83 | if key == 'escape' and action == 'press' then
84 | glfw.set_window_should_close(window, true)
85 | elseif key == 'f11' and action == 'press' then
86 | toggle_fullscreen()
87 | else
88 | keys[key] = action ~= 'release'
89 | end
90 | end)
91 |
92 | -- Game loop ------------------------------------------------------------------
93 |
94 | local timer = toolbox.frame_timer()
95 |
96 | local rot = 0
97 | local fdt = 1/180 -- fixed dt for physics updates
98 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
99 | local dt = timer:update()
100 |
101 |
102 | local ang_speed = math.pi/10 -- rad/s
103 | collectgarbage()
104 | collectgarbage('stop')
105 | while not glfw.window_should_close(window) do
106 | glfw.wait_events_timeout(1/60)
107 | dt = timer:update()
108 | local n = n_physics_updates(dt)
109 | space:step(fdt, n) -- do n update steps with time interval = fdt
110 |
111 | glfw.set_window_title(window, tostring(timer))
112 |
113 | playshoot(dt)
114 | playexplosion(dt)
115 | playjinglewin(dt)
116 |
117 | if keys['up'] then camera:move('up', 200, dt) end
118 | if keys['down'] then camera:move('down', 200, dt) end
119 | if keys['left'] then camera:move('left', 200, dt) end
120 | if keys['right'] then camera:move('right', 200, dt) end
121 | if keys['w'] then camera:zoom('in', 1, dt) end
122 | if keys['s'] then camera:zoom('out', 1, dt) end
123 | if keys['a'] then camera:rotate('ccw', ang_speed, dt) end
124 | if keys['d'] then camera:rotate('cw', ang_speed, dt) end
125 | set_matrices()
126 |
127 | --game.input(keys)
128 | --game.update(dt, keys)
129 | --game.draw(dt, keys)
130 |
131 | gl.clear_color(0.3, 0.3, 0.3, 1.0)
132 | gl.clear('color')
133 | renderer:begin()
134 | renderer:draw_dot(40, {0, 0}, {1, 0, 0, 1})
135 | renderer:draw_dot(40, {FW/2, FH/2}, {0, 0, 1, 1})
136 |
137 | rot = rot + dt
138 | face:draw({0,100}, {100,100}, rot)
139 | block:draw({0, -200}, {100, 30}, 0, RED)
140 | block:draw({100, -200}, {100, 30}, 0, GREEN)
141 | block:draw({200, -200}, {100, 30}, math.pi/4, BLUE)
142 | block:draw({300, -200}, {100, 30}, 0, WHITE)
143 |
144 | font:draw(string.format("Physics intervals = %d", n), 0, 0, .05, WHITE)
145 |
146 | renderer:draw_box({-FW/4, 0, FH/8, FH/4}, {1, 0, 0, 1})
147 | renderer:draw_fat_segment({0, 0}, vec2(FW/4, FH/4)*math.cos(rot), 10, {0, 1, 0, 1}, {0, 0, 0, 0})
148 | renderer:done()
149 |
150 | glfw.swap_buffers(window)
151 | collectgarbage()
152 | end
153 |
154 | toolbox.cleanup()
155 |
156 |
--------------------------------------------------------------------------------
/src/damped_rotary_spring.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freedamped_rotary_spring(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "damped_rotary_spring")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newdamped_rotary_spring(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, DAMPED_ROTARY_SPRING_MT, "damped_rotary_spring");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freedamped_rotary_spring;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | body_t *a = checkbody(L, 1, NULL);
50 | body_t *b = checkbody(L, 2, NULL);
51 | double restAngle = luaL_checknumber(L, 3);
52 | double stiffness = luaL_checknumber(L, 4);
53 | double damping = luaL_checknumber(L, 5);
54 | constraint_t *constraint = cpDampedRotarySpringNew(a, b, restAngle, stiffness, damping);
55 | return newdamped_rotary_spring(L, constraint);
56 | }
57 |
58 | SETDOUBLE(SetRestAngle, cpDampedRotarySpringSetRestAngle, damped_rotary_spring)
59 | SETDOUBLE(SetStiffness, cpDampedRotarySpringSetStiffness, damped_rotary_spring)
60 | SETDOUBLE(SetDamping, cpDampedRotarySpringSetDamping, damped_rotary_spring)
61 | GETDOUBLE(GetRestAngle, cpDampedRotarySpringGetRestAngle, damped_rotary_spring)
62 | GETDOUBLE(GetStiffness, cpDampedRotarySpringGetStiffness, damped_rotary_spring)
63 | GETDOUBLE(GetDamping, cpDampedRotarySpringGetDamping, damped_rotary_spring)
64 |
65 | static double TorqueCallback(struct constraint_t *constraint, double relativeAngle) /* ud->ref3 */
66 | {
67 | #define L moonchipmunk_L
68 | double result;
69 | int top = lua_gettop(L);
70 | ud_t *ud = userdata(constraint);
71 | if(!ud) { unexpected(L); return 0.0f; }
72 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref3);
73 | pushconstraint(L, constraint);
74 | lua_pushnumber(L, relativeAngle);
75 | if(lua_pcall(L, 2, 1, 0) != LUA_OK)
76 | { lua_error(L); return 0.0f; }
77 | result = luaL_checknumber(L, -1);
78 | lua_settop(L, top);
79 | return result;
80 | #undef L
81 | }
82 |
83 | static int SetTorqueFunc(lua_State *L)
84 | {
85 | ud_t *ud;
86 | constraint_t *constraint = checkdamped_rotary_spring(L, 1, &ud);
87 | if(lua_isnoneornil(L, 2)) /* remove callback */
88 | {
89 | if(ud->ref3!=LUA_NOREF)
90 | { cpDampedRotarySpringSetSpringTorqueFunc(constraint, NULL); Unreference(L, ud->ref3); }
91 | return 0;
92 | }
93 | if(!lua_isfunction(L, 2))
94 | return argerror(L, 2, ERR_FUNCTION);
95 | Reference(L, 2, ud->ref3);
96 | cpDampedRotarySpringSetSpringTorqueFunc(constraint, TorqueCallback);
97 | return 0;
98 | }
99 |
100 | static int GetTorqueFunc(lua_State *L)
101 | {
102 | ud_t *ud;
103 | (void)checkdamped_rotary_spring(L, 1, &ud);
104 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref3);
105 | return 1;
106 | }
107 |
108 | DESTROY_FUNC(damped_rotary_spring)
109 |
110 | static const struct luaL_Reg Methods[] =
111 | {
112 | { "free", Destroy },
113 | { "set_rest_angle", SetRestAngle },
114 | { "set_stiffness", SetStiffness },
115 | { "set_damping", SetDamping },
116 | { "get_rest_angle", GetRestAngle },
117 | { "get_stiffness", GetStiffness },
118 | { "get_damping", GetDamping },
119 | { "set_spring_torque_func", SetTorqueFunc },
120 | { "get_spring_torque_func", GetTorqueFunc },
121 | { NULL, NULL } /* sentinel */
122 | };
123 |
124 | static const struct luaL_Reg MetaMethods[] =
125 | {
126 | { "__gc", Destroy },
127 | { NULL, NULL } /* sentinel */
128 | };
129 |
130 | static const struct luaL_Reg Functions[] =
131 | {
132 | { "damped_rotary_spring_new", Create },
133 | { NULL, NULL } /* sentinel */
134 | };
135 |
136 | void moonchipmunk_open_damped_rotary_spring(lua_State *L)
137 | {
138 | udata_define(L, DAMPED_ROTARY_SPRING_MT, Methods, MetaMethods);
139 | udata_inherit(L, DAMPED_ROTARY_SPRING_MT, CONSTRAINT_MT);
140 | luaL_setfuncs(L, Functions, 0);
141 | }
142 |
143 |
--------------------------------------------------------------------------------
/examples/demo/06-planet.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 |
8 | cp.glmath_compat(true)
9 | local pi, infinity = math.pi, math.huge
10 | local sin, cos, abs = math.sin, math.cos, math.abs
11 | local fmt = string.format
12 | local vec2 = glmath.vec2
13 | local identity = cp.transform_identity()
14 |
15 | -- Initializations ------------------------------------------------------------
16 |
17 | local TITLE = "Planet"
18 | local FW, FH = 640, 480 -- width and height of the field
19 | local W, H = 1024, 768 -- window width and height
20 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
21 |
22 | glfw.version_hint(3, 3, 'core')
23 | glfw.window_hint('samples', 32)
24 | local window = glfw.create_window(W, H, TITLE)
25 | glfw.make_context_current(window)
26 | gl.init()
27 | toolbox.init(W, H)
28 | local camera = toolbox.camera()
29 |
30 | local function resize(window, width, height)
31 | W, H = width, height
32 | toolbox.resize(W, H)
33 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
34 | gl.viewport(0, 0, W, H)
35 | end
36 |
37 | glfw.set_window_size_callback(window, resize)
38 | resize(window, W, H)
39 |
40 | -- Demo inits -----------------------------------------------------------------
41 |
42 | local gravity_strength = 5.0e6
43 |
44 | local function planet_gravity_velocity_func(body, gravity, damping, dt)
45 | -- Gravitational acceleration is proportional to the inverse square of
46 | -- distance, and directed toward the origin. The central planet is assumed
47 | -- to be massive enough that it affects the satellites but not vice versa.
48 | local pos = body:get_position()
49 | local r = pos:norm()
50 | local g = (-gravity_strength/(r^3))*pos
51 | body:update_velocity(g, damping, dt)
52 | end
53 |
54 | local function rand_pos(radius)
55 | while true do
56 | local v = vec2(math.random()*(FW-2*radius)-(FW/2-radius), math.random()*(FH-2*radius)-(FH/2-radius))
57 | if v:norm() >= 85.0 then return v end
58 | end
59 | end
60 |
61 | local function add_box(space)
62 | local size, mass = 10.0, 1.0
63 | local verts = {{-size,-size}, {-size, size}, { size, size}, { size,-size}}
64 | local radius = vec2(size, size):norm()
65 | local pos = rand_pos(radius)
66 | local body = cp.body_new(mass, cp.moment_for_poly(mass, verts, {0, 0}, 0.0))
67 | space:add_body(body)
68 | body:set_velocity_update_func(planet_gravity_velocity_func)
69 | body:set_position(pos)
70 | -- Set the box's velocity to put it into a circular orbit from its starting position.
71 | local r = pos:norm()
72 | local v = math.sqrt(gravity_strength/r)/r
73 | body:set_velocity(v*vec2(-pos.y, pos.x)) -- perp
74 | -- Set the box's angular velocity to match its orbital period and
75 | -- align its initial angle with its position.
76 | body:set_angular_velocity(v)
77 | body:set_angle(math.atan(pos.y, pos.x))
78 | local shape = cp.poly_shape_new(body, verts, 0.0, identity)
79 | space:add_shape(shape)
80 | shape:set_elasticity(0.0)
81 | shape:set_friction(0.7)
82 | end
83 |
84 | -- Create a rouge body to control the planet manually.
85 | local space = cp.space_new()
86 | local grabber = toolbox.grabber(window, space)
87 | local grabbable, not_grabbable = grabber:filters()
88 | space:set_iterations(20)
89 | local planetBody = space:add_body(cp.body_new_kinematic())
90 | planetBody:set_angular_velocity(0.2)
91 | for i=1, 30 do add_box(space) end
92 | local shape = space:add_shape(cp.circle_shape_new(planetBody, 70.0, {0, 0}))
93 | shape:set_elasticity(1.0)
94 | shape:set_friction(1.0)
95 | shape:set_filter(not_grabbable)
96 |
97 | -- Input handling -------------------------------------------------------------
98 |
99 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
100 | local keys = {} -- keys[k] = true if key k is pressed
101 |
102 | glfw.set_key_callback(window, function(window, key, scancode, action)
103 | if key == 'escape' and action == 'press' then
104 | glfw.set_window_should_close(window, true)
105 | elseif key == 'f11' and action == 'press' then
106 | toggle_fullscreen()
107 | else
108 | keys[key] = action ~= 'release'
109 | end
110 | end)
111 |
112 | glfw.set_cursor_pos_callback(window, function(window, x, y)
113 | grabber:cursor_pos_callback(x, y)
114 | end)
115 |
116 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
117 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
118 | end)
119 |
120 | -- Game loop ------------------------------------------------------------------
121 | local timer = toolbox.frame_timer()
122 | local spf = 1/60 -- 1 / desired fps
123 | local fdt = 1/180 -- fixed dt for physics updates
124 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
125 | local n, dt
126 |
127 | local renderer = toolbox.renderer(space)
128 |
129 | collectgarbage()
130 | collectgarbage('stop')
131 | while not glfw.window_should_close(window) do
132 | glfw.wait_events_timeout(spf)
133 | dt = timer:update() -- duration of the current frame
134 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
135 |
136 | space:step(fdt, n)
137 | grabber:step(fdt, n)
138 |
139 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
140 | gl.clear_color(BG_COLOR)
141 | gl.clear('color')
142 | renderer:begin()
143 | space:debug_draw()
144 | renderer:done()
145 |
146 | glfw.swap_buffers(window)
147 | collectgarbage()
148 | end
149 |
150 | toolbox.cleanup()
151 |
152 |
--------------------------------------------------------------------------------
/src/poly.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | static int freepoly(lua_State *L, ud_t *ud)
29 | {
30 | shape_t *shape = (shape_t*)ud->handle;
31 | if(!candestroyshape(shape, ud)) return 0;
32 | if(!freeuserdata(L, ud, "poly")) return 0;
33 | shapedestroy(L, (shape_t*)shape);
34 | return 0;
35 | }
36 |
37 | static int newpoly(lua_State *L, shape_t *poly)
38 | {
39 | ud_t *ud;
40 | ud = newuserdata(L, poly, POLY_MT, "poly");
41 | ud->parent_ud = NULL;
42 | ud->destructor = freepoly;
43 | return 1;
44 | }
45 |
46 | static int PolyShapeNew(lua_State *L)
47 | {
48 | int count, raw=0;
49 | double radius;
50 | mat_t transform;
51 | vec_t *verts;
52 | shape_t *poly;
53 | body_t *body = checkbody(L, 1, NULL);
54 | if(lua_isnoneornil(L, 4)) raw=1; else checkmat(L, 4, &transform);
55 | radius = luaL_checknumber(L, 3);
56 | verts = checkveclist(L, 2, &count, NULL);
57 | poly = raw ? cpPolyShapeNewRaw(body, count, verts, radius) :
58 | cpPolyShapeNew(body, count, verts, transform, radius);
59 | Free(L, verts);
60 | return newpoly(L, poly);
61 | }
62 |
63 | static int BoxShapeNew(lua_State *L)
64 | {
65 | shape_t *poly;
66 | bb_t box;
67 | double width, height, radius;
68 | body_t *body = checkbody(L, 1, NULL);
69 | if(lua_isnumber(L, 2))
70 | {
71 | width = luaL_checknumber(L, 2);
72 | height = luaL_checknumber(L, 3);
73 | radius = luaL_checknumber(L, 4);
74 | poly = cpBoxShapeNew(body, width, height, radius);
75 | }
76 | else
77 | {
78 | checkbb(L, 2, &box);
79 | radius = luaL_checknumber(L, 3);
80 | poly = cpBoxShapeNew2(body, box, radius);
81 | }
82 | return newpoly(L, poly);
83 | }
84 |
85 | static int GetCount(lua_State *L)
86 | {
87 | shape_t *poly = checkpoly(L, 1, NULL);
88 | int count = cpPolyShapeGetCount(poly);
89 | lua_pushnumber(L, count);
90 | return 1;
91 | }
92 |
93 | static int GetVerts(lua_State *L)
94 | {
95 | int i;
96 | vec_t vert;
97 | shape_t *poly = checkpoly(L, 1, NULL);
98 | int count = cpPolyShapeGetCount(poly);
99 | lua_newtable(L);
100 | for(i=0; i> (defaults to _{0, 0}_). +
34 | _damping_: float (defaults to _1.0_).#
35 |
36 | [[space_set_iterations]]
37 | * _space_++:++*set_iterations*(_n_) +
38 | _n_ = _space_++:++*get_iterations*( )
39 |
40 | [[space_set_thresholds]]
41 | * _space_++:++*set_idle_speed_threshold*(_ist_) +
42 | _space_++:++*set_sleep_time_threshold*(_stt_) +
43 | _ist_ = _space_++:++*get_idle_speed_threshold*( ) +
44 | _stt_ = _space_++:++*get_sleep_time_threshold*( ) +
45 | [small]#_ist_: float (defaults to _0_). +
46 | _stt_: float (defaults to _math.huge_).#
47 |
48 | [[space_set_collision_xxx]]
49 | * _space_++:++*set_collision_slop*(_cs_) +
50 | _space_++:++*set_collision_bias*(_cb_) +
51 | _space_++:++*set_collision_persistence*(_cp_) +
52 | _cs_ = _space_++:++*get_collision_slop*( ) +
53 | _cb_ = _space_++:++*get_collision_bias*( ) +
54 | _cp_ = _space_++:++*get_collision_persistence*( ) +
55 | [small]#_cs_: float (defaults to _0.1_). +
56 | _cb_: float (defaults to _(1 - 0.1)^60^_). +
57 | _cp_: number of frames (defaults to _3_).#
58 |
59 |
60 | [[space_get_static_body]]
61 | * <> = _space_++:++*get_static_body*( )
62 |
63 | [[space_add_xxx]]
64 | * <> = _space_++:++*add_body*(<>) +
65 | <> = _space_++:++*add_shape*(<>) +
66 | <> = _space_++:++*add_constraint*(<>) +
67 | _space_++:++*remove_body*(<>) +
68 | _space_++:++*remove_shape*(<>) +
69 | _space_++:++*remove_constraint*(<>) +
70 | _boolean_ = _space_++:++*contains_body*(<>) +
71 | _boolean_ = _space_++:++*contains_shape*(<>) +
72 | _boolean_ = _space_++:++*contains_constraint*(<>)
73 |
74 | [[space_reindex]]
75 | * _space_++:++*reindex_static*( ) +
76 | _space_++:++*reindex_shape*(<>) +
77 | _space_++:++*reindex_shapes_for_body*(<>) +
78 | _space_++:++*use_spatial_hash*(_dim_, _count_)
79 |
80 | [[space_each]]
81 | * _space_++:++*each_body*(_func_) +
82 | _space_++:++*each_shape*(_func_) +
83 | _space_++:++*each_constraint*(_func_) +
84 | [small]#Execute _func_ as *func(space, object)* for each object of the given type.#
85 |
86 | * _collision_handler_ = _space_++:++*add_default_collision_handler*( ) +
87 | _collision_handler_ = _space_++:++*add_collision_handler*(_type~a~_, _type~b~_) +
88 | _collision_handler_ = _space_++:++*add_wildcard_handler*(_type_) +
89 | [small]#See <>.#
90 |
91 | [[space_add_post_step_callback]]
92 | * _space_++:++*add_post_step_callback*(_func_) +
93 | [small]#The post-step callback is executed as *func(space)*.#
94 |
95 | [[space_queries]]
96 | * <>|_nil_ = _space_++:++*point_query_nearest*(_point_, _maxdist_, _shapefilter_) +
97 | <>|_nil_ = _space_++:++*segment_query_first*(_p~start~_, _p~end~_, _radius_, _shapefilter_) +
98 | _space_++:++*point_query*(_point_, _maxdist_, _shapefilter_, _func_) +
99 | _space_++:++*segment_query*(_p~start~_, _p~end~_, _radius_, _shapefilter_, _func_) +
100 | _space_++:++*bb_query*(<>, _shapefilter_, _func_) +
101 | _space_++:++*shape_query*(<>, _func_) +
102 | [small]#_point_, _p~start~_, _p~end~_: <>. +
103 | _maxdist_, _radius_: float. +
104 | _shapefilter_: <>. +
105 | The _func_ callbacks are executed for each hit shape, as follows: +
106 | pass:[-] point query: *func(space, shape, _point_, _distance_)* (_point_: <>, _distance_: float). +
107 | pass:[-] segment query: *func(space, shape, point, normal, alpha)* (_point_, _normal_: <>, _alpha_: float). +
108 | pass:[-] bb query: *func(space, shape)*. +
109 | pass:[-] shape query: *func(space, shape, _normal_, {points})* ( _normal_: <>, _{points}_: {<>}).#
110 |
111 | [[space_]]
112 | * _space_++:++*debug_draw*( ) +
113 | _space_++:++*set_debug_draw_options*(_draw_circle_, _draw_segment_, _..._) +
114 | [small]#Arguments for set_debug_draw_options( ): +
115 | arg1: _space_ (implicit argument). +
116 | arg2: _draw_circle_: a function, executed as *func(angle, radius, outlinecolor, fillcolor)*. +
117 | arg3: _draw_segment_: a function, executed as *func(a, b, color)* +
118 | arg4: _draw_fat_segment_: a function, executed as *func(a, b, radius, outlinecolor, fillcolor)*. +
119 | arg5: _draw_polygon_: a function, executed as *func({verts}, radius, outlinecolor, fillcolor)* +
120 | arg6: _draw_dot_: a function, executed as *func(size, pos, color)*. +
121 | arg7: _color_for_shape_: a function, executed as *color = func(shape)* +
122 | arg8: _flags_: integer (_cpSpaceDebugDrawFlags_) +
123 | arg9: _shape_outline_color_: <>, +
124 | arg10: _constraint_color_: <>, +
125 | arg11: _collision_point_color_: <>.#
126 |
127 |
--------------------------------------------------------------------------------
/examples/demo/20-convex.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 |
8 | cp.glmath_compat(true)
9 | local pi, infinity = math.pi, math.huge
10 | local sin, cos, abs, exp, sqrt = math.sin, math.cos, math.abs, math.exp, math.sqrt
11 | local fmt = string.format
12 | local vec2 = glmath.vec2
13 | local clamp, mix = glmath.clamp, glmath.mix
14 | local identity = cp.transform_identity()
15 |
16 | -- Initializations ------------------------------------------------------------
17 |
18 | local TITLE = "Convex"
19 | local FW, FH = 640, 480 -- width and height of the field
20 | local W, H = 1024, 768 -- window width and height
21 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
22 | local FONT_COLOR, FONT_SIZE = {0xfd/250, 0xf6/250, 0xe3/250, 1.0}, 12/H
23 |
24 | glfw.version_hint(3, 3, 'core')
25 | glfw.window_hint('samples', 32)
26 | local window = glfw.create_window(W, H, TITLE)
27 | glfw.make_context_current(window)
28 | gl.init()
29 | toolbox.init(W, H)
30 | local camera = toolbox.camera()
31 |
32 | local function resize(window, width, height)
33 | W, H = width, height
34 | toolbox.resize(W, H)
35 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
36 | gl.viewport(0, 0, W, H)
37 | end
38 |
39 | glfw.set_window_size_callback(window, resize)
40 | resize(window, W, H)
41 |
42 | -- Fonts ----------------------------------------------------------------------
43 | local font = toolbox.font("../ttf-bitstream-vera-1.10/VeraMoBd.ttf", 40/H)
44 |
45 | -- Demo inits -----------------------------------------------------------------
46 |
47 | local density = 1/10000
48 | local tolerance = 2.0
49 |
50 | local space = cp.space_new()
51 | local grabber = toolbox.grabber(window, space)
52 | local grabbable, not_grabbable = grabber:filters()
53 | space:set_iterations(30)
54 | space:set_gravity({0, -500})
55 | space:set_sleep_time_threshold(0.5)
56 | space:set_collision_slop(0.5)
57 | local static_body = space:get_static_body(space)
58 | -- Create segments around the edge of the screen.
59 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,-240}, {320,-240}, 0.0))
60 | shape:set_elasticity(1.0)
61 | shape:set_friction(1.0)
62 | shape:set_filter(not_grabbable)
63 | local width, height = 50.0, 70.0
64 | local mass = width*height*density
65 | local moment = cp.moment_for_box(mass, width, height)
66 | local body = space:add_body(cp.body_new(mass, moment))
67 | local shape = space:add_shape(cp.box_shape_new(body, width, height, 0.0))
68 | shape:set_friction(0.6)
69 |
70 | -- Input handling -------------------------------------------------------------
71 |
72 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
73 | local keys = {} -- keys[k] = true if key k is pressed
74 | local right_click, last_right_click_state = false, false
75 |
76 | glfw.set_key_callback(window, function(window, key, scancode, action)
77 | if key == 'escape' and action == 'press' then glfw.set_window_should_close(window, true)
78 | elseif key == 'f11' and action == 'press' then toggle_fullscreen()
79 | else
80 | keys[key] = action ~= 'release'
81 | end
82 | end)
83 |
84 | glfw.set_cursor_pos_callback(window, function(window, x, y)
85 | grabber:cursor_pos_callback(x, y)
86 | end)
87 |
88 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
89 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
90 | if button == 'right' then right_click = action ~= 'release' end
91 | end)
92 |
93 | -- Game loop ------------------------------------------------------------------
94 | local timer = toolbox.frame_timer()
95 | local spf = 1/60 -- 1 / desired fps
96 | local fdt = 1/60 -- fixed dt for physics updates
97 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
98 | local n, dt
99 |
100 | local renderer = toolbox.renderer(space)
101 |
102 | collectgarbage()
103 | collectgarbage('stop')
104 | while not glfw.window_should_close(window) do
105 | glfw.wait_events_timeout(spf)
106 | dt = timer:update() -- duration of the current frame
107 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
108 |
109 | if right_click then
110 | local mouse_pos = grabber:get_pos()
111 | local info = shape:point_query(mouse_pos)
112 | if info.distance > tolerance then
113 | local body = shape:get_body()
114 | local verts = shape:get_verts()
115 | verts[#verts+1] = body:world_to_local(mouse_pos)
116 | -- This function builds a convex hull for the vertexes.
117 | local verts = cp.convex_hull(verts, tolerance)
118 | -- Figure out how much to shift the body by.
119 | local centroid = cp.centroid_for_poly(verts)
120 | -- Recalculate the body properties to match the updated shape.
121 | local mass = cp.area_for_poly(verts, 0.0)*density
122 | body:set_mass(mass)
123 | body:set_moment(cp.moment_for_poly(mass, verts, -centroid, 0.0))
124 | body:set_position(body:local_to_world(centroid))
125 | -- Use the setter function from chipmunk_unsafe.h.
126 | -- You could also remove and recreate the shape if you wanted.
127 | shape:set_verts(verts, cp.transform_translate(-centroid))
128 | end
129 | end
130 | space:step(fdt, n)
131 | grabber:step(fdt, n)
132 |
133 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
134 | gl.clear_color(BG_COLOR)
135 | gl.clear('color')
136 |
137 | renderer:begin()
138 | space:debug_draw()
139 | renderer:done()
140 |
141 | font:draw("Right click and drag to change the blocks's shape.", .05, .9, FONT_SIZE, FONT_COLOR)
142 |
143 | glfw.swap_buffers(window)
144 | collectgarbage()
145 | end
146 |
147 | toolbox.cleanup()
148 |
149 |
--------------------------------------------------------------------------------
/doc/miscellanea.adoc:
--------------------------------------------------------------------------------
1 |
2 | [[miscellanea]]
3 | == Miscellanea
4 |
5 | [[float_utils]]
6 | === Float utilities
7 |
8 | [small]#Rfr: https://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__basic_types.html[cp basic types].#
9 |
10 | * _value_ = *fclamp*(_f_, _a_, _b_) +
11 | _value_ = *fclamp01*(_f_) +
12 | _value_ = *flerp*(_f~1~_, _f~2~_, _f_) +
13 | _value_ = *flerpconst*(_f~1~_, _f~2~_, _f_) +
14 | [small]#_value_, _f_, _f~1~_, _f~2~_, _a_, _b_: float.#
15 |
16 | [[vec_utils]]
17 | === Vector utilities
18 |
19 | [small]#Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__cp_vect.html[cpVect].#
20 |
21 | * _boolean_ = *veql*(_v~1~_, _v~2~_) +
22 | _v_ = *vadd*(_v~1~_, _v~2~_) +
23 | _v_ = *vsub*(_v~1~_, _v~2~_) +
24 | _v_ = *vneg*(_v~1~_) +
25 | _v_ = *vmult*(_v~1~_, _v~2~_) +
26 | _value_ = *vdot*(_v~1~_, _v~2~_) +
27 | _value_ = *vcross*(_v~1~_, _v~2~_) +
28 | _v_ = *vperp*(_v~1~_) +
29 | _v_ = *vrperp*(_v~1~_) +
30 | _v_ = *vproject*(_v~1~_, _v~2~_) +
31 | _v_ = *vforangle*(_angle_) +
32 | _angle_ = *vtoangle*(_v_) +
33 | _v_ = *vrotate*(_v~1~_, _v~2~_) +
34 | _v_ = *vunrotate*(_v~1~_, _v~2~_) +
35 | _value_ = *vlength*(_v~1~_) +
36 | _value_ = *vlengthsq*(_v~1~_) +
37 | _value_ = *vdist*(_v~1~_, _v~2~_) +
38 | _value_ = *vdistsq*(_v~1~_, _v~2~_) +
39 | _v_ = *vnormalize*(_v~1~_) +
40 | _v_ = *vclamp*(_v~1~_, _len_) +
41 | _boolean_ = *vnear*(_v~1~_, _v~2~_, _d_) +
42 | _v_ = *vlerp*(_v~1~_, _v~2~_, _d_) +
43 | _v_ = *vslerp*(_v~1~_, _v~2~_, _d_) +
44 | _v_ = *vlerpconst*(_v~1~_, _v~2~_, _d_) +
45 | _v_ = *vslerpconst*(_v~1~_, _v~2~_, _d_) +
46 | [small]#_v_, _v~1~_, _v~2~_: <>. +
47 | _value_, _angle_, _len_, _d_: float.#
48 |
49 |
50 | [[mat_utils]]
51 | === Transform utilities
52 |
53 | [small]#Rfr: http://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/structcp_transform.html[cpTransform].#
54 |
55 | * _m_ = *transform_identity*( ) +
56 | _m_ = *transform_new*(_a_, _b_, _c_, _d_, _t~x~_, _t~y~_) +
57 | _m_ = *transform_new_transpose*(_a_, _c_, _t~x~_, _b_, _d_, _t~y~_) +
58 | _m_ = *transform_inverse*(_m~1~_) +
59 | _m_ = *transform_mult*(_m~1~_, _m~2~_) +
60 | _p_ = *transform_point*(_m_, _p_) +
61 | _v_ = *transform_vect*(_m_, _v_) +
62 | _bb_ = *transform_bb*(_m_, _bb_) +
63 | _m_ = *transform_translate*(_v_) +
64 | _m_ = *transform_scale*(_s~x~_, _s~y~_) +
65 | _m_ = *transform_rotate*(_angle_) +
66 | _m_ = *transform_rigid*(_v_, _angle_) +
67 | _m_ = *transform_rigid_inverse*(_m~1~_) +
68 | _m_ = *transform_wrap*(_m~outer~_, _m~inner~_) +
69 | _m_ = *transform_wrap_inverse*(_m~outer~_, _m~inner~_) +
70 | _m_ = *transform_ortho*(_bb_) +
71 | _m_ = *transform_bone_scale*(_v~1~_, _v~2~_) +
72 | _m_ = *transform_axial_scale*(_axis_, _pivot_, _scale_) +
73 | [small]#_m_, _m~1~, _m~2~_, _m~outer~_, _m~inner~_: <>. +
74 | _p_, _v_, _v~1~_, _v~2~_, _axis_, _pivot_: <>. +
75 | _bb_: <>. +
76 | _a_, _b_, _c_, _d_, _t~x~_, _t~y~_, _s~x~_, _s~y~_, _angle_, _scale_: float.#
77 |
78 | [[bb_utils]]
79 | === Bounding box utilities
80 |
81 | [small]#Rfr: https://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__cp_b_b_b.html[cpBB].#
82 |
83 | * _bb_ = *bb_new_for_extents*(_center_, _halfwidth_, _halfheight_) +
84 | _bb_ = *bb_new_for_circle*(_center_, _radius_) +
85 | _boolean_ = *bb_intersects*(_bb~1~_, _bb~2~_) +
86 | _boolean_ = *bb_contains_bb*(_bb~1~_, _bb~2~_) +
87 | _boolean_ = *bb_contains_vect*(_bb_, _v_) +
88 | _bb_ = *bb_merge*(_bb~1~_, _bb~2~_) +
89 | _bb_ = *bb_expand*(_bb~1~_, _v_) +
90 | _center_ = *bb_center*(_bb_) +
91 | _area_ = *bb_area*(_bb_) +
92 | _area_ = *bb_merged_area*(_bb~1~_, _bb~2~_) +
93 | _f_ = *bb_segment_query*(_bb_, _a_, _b_) +
94 | _boolean_ = *bb_intersects_segment*(_bb_, _a_, _b_) +
95 | _v_ = *bb_clamp_vect*(_bb_, _v_) +
96 | _v_ = *bb_wrap_vect*(_bb_, _v_) +
97 | _bb_ = *bb_offset*(_bb_, _v_) +
98 | [small]#_bb_, _bb~1~_, _bb~2~_: <>. +
99 | _center_, _v_, _a_, _b_: <>. +
100 | _width_, _height_, _area_, _f_: float.#
101 |
102 | * *march_soft*(_bb_, _xsamples_, _ysamples_, _threshold_, _samplefunc_, _segmentfunc_ ) +
103 | *march_hard*(_bb_, _xsamples_, _ysamples_, _threshold_, _samplefunc_, _segmentfunc_ ) +
104 | [small]#_bb_: <>. +
105 | _xsamples_, _ysamples_: integer. +
106 | _threshold_: float. +
107 | The sample function is executed as *density = func(p)* (_density_: float, _p_: <>). +
108 | The segment function is executed as *func(_a_, _b_)* (_a_, _b_: <>).#
109 |
110 | [[moment]]
111 | === Moments, areas, etc
112 |
113 | [small]#Rfr:https://chipmunk-physics.net/release/ChipmunkLatest-API-Reference/group__misc.html[cp misc].#
114 |
115 | * _moment_ = *moment_for_circle*(_mass_, _r~inner~_, _r~outer~_, _offset_) +
116 | _moment_ = *moment_for_segment*(_mass_, _point~a~_, _point~b~_, _radius_) +
117 | _moment_ = *moment_for_poly*(_mass_, _{verts}_, _offset_, _radius_) +
118 | _moment_ = *moment_for_box*(_mass_, _width_, _height_) +
119 | _moment_ = *moment_for_box*(_mass_, <>) +
120 | _area_ = *area_for_circle*(_r~inner~_, _r~outer~_) +
121 | _area_ = *area_for_segment*(_point~a~_, _point~b~_, _radius_) +
122 | _area_ = *area_for_poly*(_{verts}_, _radius_) +
123 | _centroid_ = *centroid_for_poly*(_{verts}_) +
124 | _{verts}_ = *convex_hull*(_{verts}_, _tol_) +
125 | [small]#_moment_, _area_, _mass_, _r~inner~_, _r~outer~_, _radius_, _width_, _height_, _tol_: float. +
126 | _point~a~_, _point~b~_, _offset_, _centroid_: <>. +
127 | _{verts}_: {<>}.#
128 |
129 | * _p_ = *closest_point_on_segment*(_p_, _a_, _b_) +
130 | [small]#Returns the point on the segment (_a_, _b_) that is closest to the point _p_. +
131 | _p_, _a_, _b_: <>.#
132 |
133 | ////
134 | * _boolean_ = *check_point_greater*(_p_, _a_, _b_) +
135 | [small]#Returns _true_ if the point _p_ is to the left of the segment (_a_, _b_). +
136 | _p_, _a_, _b_: <>.#
137 |
138 | * _boolean_ = *check_axis*(_v~0~_, _v~1~_, _p_, _n_) +
139 | [small]#Returns _true_ if the point _p_ is behind one of _v~0~_ or _v~1~_ on axis _n_. + @@ UH?
140 | _v~0~_, _v~1~_, _p_, _n_: <>.#
141 | ////
142 |
143 |
144 |
--------------------------------------------------------------------------------
/src/damped_spring.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 | #include "constraint.h"
28 |
29 | static int freedamped_spring(lua_State *L, ud_t *ud)
30 | {
31 | constraint_t *constraint = (constraint_t*)ud->handle;
32 | if(!candestroyconstraint(constraint, ud)) return 0;
33 | if(!freeuserdata(L, ud, "damped_spring")) return 0;
34 | constraintdestroy(L, constraint);
35 | return 0;
36 | }
37 |
38 | static int newdamped_spring(lua_State *L, constraint_t *constraint)
39 | {
40 | ud_t *ud;
41 | ud = newuserdata(L, constraint, DAMPED_SPRING_MT, "damped_spring");
42 | ud->parent_ud = NULL;
43 | ud->destructor = freedamped_spring;
44 | return 1;
45 | }
46 |
47 | static int Create(lua_State *L)
48 | {
49 | vec_t anchorA, anchorB;
50 | double restLength, stiffness, damping;
51 | constraint_t *constraint;
52 | body_t *a = checkbody(L, 1, NULL);
53 | body_t *b = checkbody(L, 2, NULL);
54 | checkvec(L, 3, &anchorA);
55 | checkvec(L, 4, &anchorB);
56 | restLength = luaL_checknumber(L, 5);
57 | stiffness = luaL_checknumber(L, 6);
58 | damping = luaL_checknumber(L, 7);
59 | constraint = cpDampedSpringNew(a, b, anchorA, anchorB, restLength, stiffness, damping);
60 | return newdamped_spring(L, constraint);
61 | }
62 |
63 | SETVEC(SetAnchorA, cpDampedSpringSetAnchorA, damped_spring)
64 | SETVEC(SetAnchorB, cpDampedSpringSetAnchorB, damped_spring)
65 | GETVEC(GetAnchorA, cpDampedSpringGetAnchorA, damped_spring)
66 | GETVEC(GetAnchorB, cpDampedSpringGetAnchorB, damped_spring)
67 | SETDOUBLE(SetRestLength, cpDampedSpringSetRestLength, damped_spring)
68 | SETDOUBLE(SetStiffness, cpDampedSpringSetStiffness, damped_spring)
69 | SETDOUBLE(SetDamping, cpDampedSpringSetDamping, damped_spring)
70 | GETDOUBLE(GetRestLength, cpDampedSpringGetRestLength, damped_spring)
71 | GETDOUBLE(GetStiffness, cpDampedSpringGetStiffness, damped_spring)
72 | GETDOUBLE(GetDamping, cpDampedSpringGetDamping, damped_spring)
73 |
74 | static double ForceCallback(constraint_t *constraint, double dist) /* ud->ref3 */
75 | {
76 | #define L moonchipmunk_L
77 | double result;
78 | int top = lua_gettop(L);
79 | ud_t *ud = userdata(constraint);
80 | if(!ud) { unexpected(L); return 0.0f; }
81 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref3);
82 | pushconstraint(L, constraint);
83 | lua_pushnumber(L, dist);
84 | if(lua_pcall(L, 2, 1, 0) != LUA_OK)
85 | { lua_error(L); return 0.0f; }
86 | result = luaL_checknumber(L, -1);
87 | lua_settop(L, top);
88 | return result;
89 | #undef L
90 | }
91 |
92 | static int SetSpringForceFunc(lua_State *L)
93 | {
94 | ud_t *ud;
95 | constraint_t *constraint = checkdamped_spring(L, 1, &ud);
96 | if(lua_isnoneornil(L, 2)) /* remove callback */
97 | {
98 | if(ud->ref3!=LUA_NOREF)
99 | { cpDampedSpringSetSpringForceFunc(constraint, NULL); Unreference(L, ud->ref3); }
100 | return 0;
101 | }
102 | if(!lua_isfunction(L, 2))
103 | return argerror(L, 2, ERR_FUNCTION);
104 | Reference(L, 2, ud->ref3);
105 | cpDampedSpringSetSpringForceFunc(constraint, ForceCallback);
106 | return 0;
107 | }
108 |
109 | static int GetSpringForceFunc(lua_State *L)
110 | {
111 | ud_t *ud;
112 | (void)checkdamped_spring(L, 1, &ud);
113 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref3);
114 | return 1;
115 | }
116 |
117 | DESTROY_FUNC(damped_spring)
118 |
119 | static const struct luaL_Reg Methods[] =
120 | {
121 | { "free", Destroy },
122 | { "set_anchor_a", SetAnchorA },
123 | { "set_anchor_b", SetAnchorB },
124 | { "get_anchor_a", GetAnchorA },
125 | { "get_anchor_b", GetAnchorB },
126 | { "set_rest_length", SetRestLength },
127 | { "set_stiffness", SetStiffness },
128 | { "set_damping", SetDamping },
129 | { "get_rest_length", GetRestLength },
130 | { "get_stiffness", GetStiffness },
131 | { "get_damping", GetDamping },
132 | { "set_spring_force_func", SetSpringForceFunc },
133 | { "get_spring_force_func", GetSpringForceFunc },
134 | { NULL, NULL } /* sentinel */
135 | };
136 |
137 | static const struct luaL_Reg MetaMethods[] =
138 | {
139 | { "__gc", Destroy },
140 | { NULL, NULL } /* sentinel */
141 | };
142 |
143 | static const struct luaL_Reg Functions[] =
144 | {
145 | { "damped_spring_new", Create },
146 | { NULL, NULL } /* sentinel */
147 | };
148 |
149 | void moonchipmunk_open_damped_spring(lua_State *L)
150 | {
151 | udata_define(L, DAMPED_SPRING_MT, Methods, MetaMethods);
152 | udata_inherit(L, DAMPED_SPRING_MT, CONSTRAINT_MT);
153 | luaL_setfuncs(L, Functions, 0);
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/examples/demo/11-one-way.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 |
8 | cp.glmath_compat(true)
9 | local pi, infinity = math.pi, math.huge
10 | local sin, cos, abs = math.sin, math.cos, math.abs
11 | local fmt = string.format
12 | local vec2 = glmath.vec2
13 | local clamp, mix = glmath.clamp, glmath.mix
14 | local identity = cp.transform_identity()
15 |
16 | -- Initializations ------------------------------------------------------------
17 |
18 | local TITLE = "One Way Platforms"
19 | local FW, FH = 640, 480 -- width and height of the field
20 | local W, H = 1024, 768 -- window width and height
21 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
22 | local FONT_COLOR, FONT_SIZE = {0xfd/250, 0xf6/250, 0xe3/250, 1.0}, 12/H
23 |
24 | glfw.version_hint(3, 3, 'core')
25 | glfw.window_hint('samples', 32)
26 | local window = glfw.create_window(W, H, TITLE)
27 | glfw.make_context_current(window)
28 | gl.init()
29 | toolbox.init(W, H)
30 | local camera = toolbox.camera()
31 |
32 | local function resize(window, width, height)
33 | W, H = width, height
34 | toolbox.resize(W, H)
35 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
36 | gl.viewport(0, 0, W, H)
37 | end
38 |
39 | glfw.set_window_size_callback(window, resize)
40 | resize(window, W, H)
41 |
42 | -- Fonts ----------------------------------------------------------------------
43 | local font = toolbox.font("../ttf-bitstream-vera-1.10/VeraMoBd.ttf", 40/H)
44 |
45 | -- Demo inits -----------------------------------------------------------------
46 |
47 | local collision_type = { ONE_WAY=1, STANDARD=2 }
48 |
49 | local platforms = {} -- indexed by shape
50 | local function new_platform(normal, shape)
51 | local platform = {
52 | normal=normal, -- direction objects may pass through
53 | shape=shape, -- the platform's shape
54 | }
55 | platforms[shape] = platform
56 | return platform
57 | end
58 |
59 | local function pre_solve(arbiter, space)
60 | local a, b = arbiter:get_shapes()
61 | local platform = platforms[a]
62 | if arbiter:get_normal()*platform.normal < 0 then return arbiter:ignore() end
63 | return true
64 | end
65 |
66 | local space = cp.space_new()
67 | local grabber = toolbox.grabber(window, space)
68 | local grabbable, not_grabbable = grabber:filters()
69 | space:set_iterations(10)
70 | space:set_gravity({0, -100})
71 | local static_body = space:get_static_body()
72 | -- Create segments around the edge of the screen.
73 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,-240}, {-320,240}, 0.0))
74 | shape:set_elasticity(1.0)
75 | shape:set_friction(1.0)
76 | shape:set_filter(not_grabbable)
77 | local shape = space:add_shape(cp.segment_shape_new(static_body, {320,-240}, {320,240}, 0.0))
78 | shape:set_elasticity(1.0)
79 | shape:set_friction(1.0)
80 | shape:set_filter(not_grabbable)
81 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,-240}, {320,-240}, 0.0))
82 | shape:set_elasticity(1.0)
83 | shape:set_friction(1.0)
84 | shape:set_filter(not_grabbable)
85 | -- Add our one way segment
86 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-160,-100}, {160,-100}, 10.0))
87 | shape:set_elasticity(1.0)
88 | shape:set_friction(1.0)
89 | shape:set_collision_type(collision_type.ONE_WAY)
90 | shape:set_filter(not_grabbable)
91 | local platform = new_platform(vec2(0,1), shape)
92 | -- Add a ball to test it out
93 | local radius = 15.0
94 | local body = space:add_body(cp.body_new(10.0, cp.moment_for_circle(10.0, 0.0, radius, {0, 0})))
95 | body:set_position({0, -200})
96 | body:set_velocity({0, 170})
97 | local shape = space:add_shape(cp.circle_shape_new(body, radius, {0, 0}))
98 | shape:set_elasticity(0.0)
99 | shape:set_friction(0.9)
100 | shape:set_collision_type(collision_type.STANDARD)
101 | local handler = space:add_wildcard_handler(collision_type.ONE_WAY)
102 | handler:set_pre_solve_func(pre_solve)
103 |
104 | -- Input handling -------------------------------------------------------------
105 |
106 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
107 | local keys = {} -- keys[k] = true if key k is pressed
108 |
109 | glfw.set_key_callback(window, function(window, key, scancode, action)
110 | if key == 'escape' and action == 'press' then
111 | glfw.set_window_should_close(window, true)
112 | elseif key == 'f11' and action == 'press' then
113 | toggle_fullscreen()
114 | else
115 | keys[key] = action ~= 'release'
116 | end
117 | end)
118 |
119 | glfw.set_cursor_pos_callback(window, function(window, x, y)
120 | grabber:cursor_pos_callback(x, y)
121 | end)
122 |
123 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
124 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
125 | end)
126 |
127 | -- Game loop ------------------------------------------------------------------
128 | local timer = toolbox.frame_timer()
129 | local spf = 1/60 -- 1 / desired fps
130 | local fdt = 1/60 -- fixed dt for physics updates
131 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
132 | local n, dt
133 |
134 | local message = "One way platforms are trivial in Chipmunk using a very simple collision callback."
135 | local renderer = toolbox.renderer(space)
136 |
137 | collectgarbage()
138 | collectgarbage('stop')
139 | while not glfw.window_should_close(window) do
140 | glfw.wait_events_timeout(spf)
141 | dt = timer:update() -- duration of the current frame
142 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
143 | space:step(fdt, n)
144 | grabber:step(fdt, n)
145 |
146 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
147 | gl.clear_color(BG_COLOR)
148 | gl.clear('color')
149 |
150 | renderer:begin()
151 | space:debug_draw()
152 | renderer:done()
153 |
154 | font:draw(message, .05, .9, FONT_SIZE, FONT_COLOR)
155 |
156 | glfw.swap_buffers(window)
157 | collectgarbage()
158 | end
159 |
160 | toolbox.cleanup()
161 |
162 |
--------------------------------------------------------------------------------
/examples/demo/02-plink.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local cp = require("moonchipmunk")
5 | local toolbox = require("moonchipmunk.toolbox")
6 |
7 | local pi, infinity = math.pi, math.huge
8 | local sin, cos, abs = math.sin, math.cos, math.abs
9 | local fmt = string.format
10 |
11 | -- Initializations ------------------------------------------------------------
12 |
13 | local TITLE = "Pyramid Stack"
14 | local FW, FH = 640, 480 -- width and height of the field
15 | local W, H = 1024, 768 -- width and height of the window
16 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
17 | local FONT_COLOR, FONT_SIZE = {0xfd/250, 0xf6/250, 0xe3/250, 1.0}, 12/H
18 |
19 | glfw.version_hint(3, 3, 'core')
20 | glfw.window_hint('samples', 32)
21 | local window = glfw.create_window(W, H, TITLE)
22 | glfw.make_context_current(window)
23 | gl.init()
24 | toolbox.init(W, H)
25 | local camera = toolbox.camera()
26 |
27 | local function resize(window, width, height)
28 | W, H = width, height
29 | toolbox.resize(W, H)
30 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
31 | gl.viewport(0, 0, W, H)
32 | end
33 |
34 | glfw.set_window_size_callback(window, resize)
35 | resize(window, W, H)
36 |
37 | -- Fonts ----------------------------------------------------------------------
38 | local font = toolbox.font("../ttf-bitstream-vera-1.10/VeraMoBd.ttf", 40/H)
39 |
40 | -- Demo inits -----------------------------------------------------------------
41 | local space = cp.space_new()
42 | local grabber = toolbox.grabber(window, space)
43 | local grabbable, not_grabbable = grabber:filters()
44 | space:set_iterations(5)
45 | space:set_gravity({0, -100})
46 | local static_body = space:get_static_body()
47 | local tris = {{-15,-15}, { 0, 10}, { 15,-15}} -- Vertexes for a triangle shape.
48 | -- Create the static triangles.
49 | for i=0, 8 do
50 | for j=0, 5 do
51 | local stagger = (j%2)*40
52 | local offset = {i*80 - 320 + stagger, j*70 - 240}
53 | local transform = cp.transform_translate(offset)
54 | local shape = cp.poly_shape_new(static_body, tris, 0.0, transform)
55 | space:add_shape(shape)
56 | shape:set_elasticity(1.0)
57 | shape:set_friction(1.0)
58 | shape:set_filter(not_grabbable)
59 | end
60 | end
61 |
62 | -- Add lots of pentagons.
63 | local num_pentagon_verts= 5
64 | local pentagon_mass = 1.0
65 | local pentagon_verts = {} -- vertices for a pentagon shape.
66 | for i=0, num_pentagon_verts-1 do
67 | local angle = -2.0*pi*i/num_pentagon_verts
68 | table.insert(pentagon_verts, {10*cos(angle), 10*sin(angle)})
69 | end
70 | local pentagon_moment = cp.moment_for_poly(pentagon_mass, pentagon_verts, {0, 0}, 0.0)
71 | local identity = cp.transform_identity()
72 |
73 | math.randomseed(os.time())
74 | for i=0,299 do
75 | local body = cp.body_new(pentagon_mass, pentagon_moment)
76 | space:add_body(body)
77 | body:set_position({math.random()*640-320, 350})
78 | local shape = cp.poly_shape_new(body, pentagon_verts, 0.0, identity)
79 | space:add_shape(shape)
80 | shape:set_elasticity(0.0)
81 | shape:set_friction(0.4)
82 | end
83 |
84 | -- Input handling -------------------------------------------------------------
85 |
86 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
87 | local keys = {} -- keys[k] = true if key k is pressed
88 |
89 | glfw.set_key_callback(window, function(window, key, scancode, action)
90 | if key == 'escape' and action == 'press' then
91 | glfw.set_window_should_close(window, true)
92 | elseif key == 'f11' and action == 'press' then
93 | toggle_fullscreen()
94 | else
95 | keys[key] = action ~= 'release'
96 | end
97 | end)
98 |
99 | glfw.set_cursor_pos_callback(window, function(window, x, y)
100 | grabber:cursor_pos_callback(x, y)
101 | end)
102 |
103 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
104 | if button=='right' and action=='press' then
105 | -- toggle the nearest body (if any) from static to dynamic and viceversa
106 | local nearest = space:point_query_nearest(grabber:get_pos(), 0.0, grabbable)
107 | if nearest then
108 | local body = nearest.shape:get_body()
109 | if body:get_type() == 'static' then
110 | body:set_type('dynamic')
111 | body:set_mass(pentagon_mass)
112 | body:set_moment(pentagon_moment)
113 | elseif body:get_type()=='dynamic' then
114 | body:set_type('static')
115 | end
116 | end
117 | end
118 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
119 | end)
120 |
121 | -- Game loop ------------------------------------------------------------------
122 | local timer = toolbox.frame_timer()
123 | local spf = 1/60 -- 1 / desired fps
124 | local fdt = 1/60 -- fixed dt for physics updates
125 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
126 | local n, dt
127 |
128 | local renderer = toolbox.renderer(space)
129 |
130 | collectgarbage()
131 | collectgarbage('stop')
132 | while not glfw.window_should_close(window) do
133 | glfw.wait_events_timeout(spf)
134 | dt = timer:update() -- duration of the current frame
135 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
136 |
137 | for i = 1, n do
138 | -- Iterate over all of the bodies and reset the ones that have fallen offscreen.
139 | space:each_body(function(space, body)
140 | local x, y = table.unpack(body:get_position())
141 | if y < -260 or abs(x) > 340 then
142 | body:set_position({math.random()*640-320, 260})
143 | end
144 | end)
145 | space:step(fdt)
146 | grabber:step(fdt)
147 | end
148 |
149 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
150 | gl.clear_color(BG_COLOR)
151 | gl.clear('color')
152 | renderer:begin()
153 | space:debug_draw()
154 | renderer:done()
155 |
156 | font:draw("Right click to make pentagons static/dynamic.", .05, .9, FONT_SIZE, FONT_COLOR)
157 |
158 | glfw.swap_buffers(window)
159 | collectgarbage()
160 | end
161 |
162 | toolbox.cleanup()
163 |
164 |
165 |
--------------------------------------------------------------------------------
/examples/demo/04-tumble.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 |
8 | cp.glmath_compat(true)
9 | local pi, infinity = math.pi, math.huge
10 | local sin, cos, abs = math.sin, math.cos, math.abs
11 | local fmt = string.format
12 | local vec2 = glmath.vec2
13 |
14 | -- Initializations ------------------------------------------------------------
15 |
16 | local TITLE = "Tumble"
17 | local FW, FH = 640, 480 -- width and height of the field
18 | local W, H = 1024, 768 -- window width and height
19 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
20 |
21 | glfw.version_hint(3, 3, 'core')
22 | glfw.window_hint('samples', 32)
23 | local window = glfw.create_window(W, H, TITLE)
24 | glfw.make_context_current(window)
25 | gl.init()
26 | toolbox.init(W, H)
27 | local camera = toolbox.camera()
28 |
29 | local function resize(window, width, height)
30 | W, H = width, height
31 | toolbox.resize(W, H)
32 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
33 | gl.viewport(0, 0, W, H)
34 | end
35 |
36 | glfw.set_window_size_callback(window, resize)
37 | resize(window, W, H)
38 |
39 | -- Demo inits -----------------------------------------------------------------
40 |
41 | local space = cp.space_new()
42 | local grabber = toolbox.grabber(window, space)
43 | local grabbable, not_grabbable = grabber:filters()
44 | space:set_gravity({0, -600})
45 | -- We create an infinite mass rogue body to attach the line segments too
46 | -- This way we can control the rotation however we want.
47 | local kinematic_box_body = cp.body_new_kinematic()
48 | space:add_body(kinematic_box_body)
49 | kinematic_box_body:set_angular_velocity(0.4)
50 | -- Set up the static box.
51 | local a, b, c, d = {-200, -200}, {-200, 200}, { 200, 200}, { 200, -200}
52 | local shape = space:add_shape(cp.segment_shape_new(kinematic_box_body, a, b, 0.0))
53 | shape:set_elasticity(1.0)
54 | shape:set_friction(1.0)
55 | shape:set_filter(not_grabbable)
56 | local shape = space:add_shape(cp.segment_shape_new(kinematic_box_body, b, c, 0.0))
57 | shape:set_elasticity(1.0)
58 | shape:set_friction(1.0)
59 | shape:set_filter(not_grabbable)
60 | local shape = space:add_shape(cp.segment_shape_new(kinematic_box_body, c, d, 0.0))
61 | shape:set_elasticity(1.0)
62 | shape:set_friction(1.0)
63 | shape:set_filter(not_grabbable)
64 | local shape = space:add_shape(cp.segment_shape_new(kinematic_box_body, d, a, 0.0))
65 | shape:set_elasticity(1.0)
66 | shape:set_friction(1.0)
67 | shape:set_filter(not_grabbable)
68 |
69 | -- Add the bricks.
70 |
71 | local function add_box(space, pos, mass, width, height)
72 | local body = space:add_body(cp.body_new(mass, cp.moment_for_box(mass, width, height)))
73 | body:set_position(pos)
74 | local shape = space:add_shape(cp.box_shape_new(body, width, height, 0.0))
75 | shape:set_elasticity(0.0)
76 | shape:set_friction(0.7)
77 | end
78 |
79 | local function add_segment(space, pos, mass, width, height)
80 | local body = space:add_body(cp.body_new(mass, cp.moment_for_box(mass, width, height)))
81 | body:set_position(pos)
82 | local a, b = {0.0, (height-width)/2.0}, {0.0, (width-height)/2.0}
83 | local shape = space:add_shape(cp.segment_shape_new(body, a, b, width/2.0))
84 | shape:set_elasticity(0.0)
85 | shape:set_friction(0.7)
86 | end
87 |
88 | local function add_circle(space, pos, mass, radius)
89 | local body = space:add_body(cp.body_new(mass, cp.moment_for_circle(mass, 0.0, radius, {0, 0})))
90 | body:set_position(pos)
91 | local shape = space:add_shape(cp.circle_shape_new(body, radius, {0, 0}))
92 | shape:set_elasticity(0.0)
93 | shape:set_friction(0.7)
94 | end
95 |
96 | local mass, width, height = 1, 30, 60
97 | math.randomseed(os.time())
98 | for i=0, 6 do
99 | for j=0, 2 do
100 | local pos = vec2(i*width - 150, j*height - 150)
101 | local dice = math.random(0,2) -- 3-faces dice (0, 1, 2)
102 | if dice==0 then
103 | add_box(space, pos, mass, width, height)
104 | elseif dice == 1 then
105 | add_segment(space, pos, mass, width, height)
106 | else -- dice == 2
107 | add_circle(space, pos + vec2(0.0, (height - width)/2.0), mass, width/2.0)
108 | add_circle(space, pos + vec2(0.0, (width - height)/2.0), mass, width/2.0)
109 | end
110 | end
111 | end
112 |
113 | -- Input handling -------------------------------------------------------------
114 |
115 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
116 | local keys = {} -- keys[k] = true if key k is pressed
117 |
118 | glfw.set_key_callback(window, function(window, key, scancode, action)
119 | if key == 'escape' and action == 'press' then
120 | glfw.set_window_should_close(window, true)
121 | elseif key == 'f11' and action == 'press' then
122 | toggle_fullscreen()
123 | else
124 | keys[key] = action ~= 'release'
125 | end
126 | end)
127 |
128 | glfw.set_cursor_pos_callback(window, function(window, x, y)
129 | grabber:cursor_pos_callback(x, y)
130 | end)
131 |
132 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
133 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
134 | end)
135 |
136 | -- Game loop ------------------------------------------------------------------
137 | local timer = toolbox.frame_timer()
138 | local spf = 1/60 -- 1 / desired fps
139 | local fdt = 1/180 -- fixed dt for physics updates
140 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
141 | local n, dt
142 |
143 | local renderer = toolbox.renderer(space)
144 |
145 | collectgarbage()
146 | collectgarbage('stop')
147 | while not glfw.window_should_close(window) do
148 | glfw.wait_events_timeout(spf)
149 | dt = timer:update() -- duration of the current frame
150 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
151 |
152 | space:step(fdt, n)
153 | grabber:step(fdt, n)
154 |
155 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
156 | gl.clear_color(BG_COLOR)
157 | gl.clear('color')
158 | renderer:begin()
159 | space:debug_draw()
160 | renderer:done()
161 |
162 | glfw.swap_buffers(window)
163 | collectgarbage()
164 | end
165 |
166 | toolbox.cleanup()
167 |
168 |
--------------------------------------------------------------------------------
/examples/ttf-bitstream-vera-1.10/COPYRIGHT.TXT:
--------------------------------------------------------------------------------
1 | Bitstream Vera Fonts Copyright
2 |
3 | The fonts have a generous copyright, allowing derivative works (as
4 | long as "Bitstream" or "Vera" are not in the names), and full
5 | redistribution (so long as they are not *sold* by themselves). They
6 | can be be bundled, redistributed and sold with any software.
7 |
8 | The fonts are distributed under the following copyright:
9 |
10 | Copyright
11 | =========
12 |
13 | Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
14 | Vera is a trademark of Bitstream, Inc.
15 |
16 | Permission is hereby granted, free of charge, to any person obtaining
17 | a copy of the fonts accompanying this license ("Fonts") and associated
18 | documentation files (the "Font Software"), to reproduce and distribute
19 | the Font Software, including without limitation the rights to use,
20 | copy, merge, publish, distribute, and/or sell copies of the Font
21 | Software, and to permit persons to whom the Font Software is furnished
22 | to do so, subject to the following conditions:
23 |
24 | The above copyright and trademark notices and this permission notice
25 | shall be included in all copies of one or more of the Font Software
26 | typefaces.
27 |
28 | The Font Software may be modified, altered, or added to, and in
29 | particular the designs of glyphs or characters in the Fonts may be
30 | modified and additional glyphs or characters may be added to the
31 | Fonts, only if the fonts are renamed to names not containing either
32 | the words "Bitstream" or the word "Vera".
33 |
34 | This License becomes null and void to the extent applicable to Fonts
35 | or Font Software that has been modified and is distributed under the
36 | "Bitstream Vera" names.
37 |
38 | The Font Software may be sold as part of a larger software package but
39 | no copy of one or more of the Font Software typefaces may be sold by
40 | itself.
41 |
42 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
44 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
45 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
46 | BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
47 | OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
48 | OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
49 | OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
50 | SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
51 |
52 | Except as contained in this notice, the names of Gnome, the Gnome
53 | Foundation, and Bitstream Inc., shall not be used in advertising or
54 | otherwise to promote the sale, use or other dealings in this Font
55 | Software without prior written authorization from the Gnome Foundation
56 | or Bitstream Inc., respectively. For further information, contact:
57 | fonts at gnome dot org.
58 |
59 | Copyright FAQ
60 | =============
61 |
62 | 1. I don't understand the resale restriction... What gives?
63 |
64 | Bitstream is giving away these fonts, but wishes to ensure its
65 | competitors can't just drop the fonts as is into a font sale system
66 | and sell them as is. It seems fair that if Bitstream can't make money
67 | from the Bitstream Vera fonts, their competitors should not be able to
68 | do so either. You can sell the fonts as part of any software package,
69 | however.
70 |
71 | 2. I want to package these fonts separately for distribution and
72 | sale as part of a larger software package or system. Can I do so?
73 |
74 | Yes. A RPM or Debian package is a "larger software package" to begin
75 | with, and you aren't selling them independently by themselves.
76 | See 1. above.
77 |
78 | 3. Are derivative works allowed?
79 | Yes!
80 |
81 | 4. Can I change or add to the font(s)?
82 | Yes, but you must change the name(s) of the font(s).
83 |
84 | 5. Under what terms are derivative works allowed?
85 |
86 | You must change the name(s) of the fonts. This is to ensure the
87 | quality of the fonts, both to protect Bitstream and Gnome. We want to
88 | ensure that if an application has opened a font specifically of these
89 | names, it gets what it expects (though of course, using fontconfig,
90 | substitutions could still could have occurred during font
91 | opening). You must include the Bitstream copyright. Additional
92 | copyrights can be added, as per copyright law. Happy Font Hacking!
93 |
94 | 6. If I have improvements for Bitstream Vera, is it possible they might get
95 | adopted in future versions?
96 |
97 | Yes. The contract between the Gnome Foundation and Bitstream has
98 | provisions for working with Bitstream to ensure quality additions to
99 | the Bitstream Vera font family. Please contact us if you have such
100 | additions. Note, that in general, we will want such additions for the
101 | entire family, not just a single font, and that you'll have to keep
102 | both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
103 | glyphs to the font, they must be stylistically in keeping with Vera's
104 | design. Vera cannot become a "ransom note" font. Jim Lyles will be
105 | providing a document describing the design elements used in Vera, as a
106 | guide and aid for people interested in contributing to Vera.
107 |
108 | 7. I want to sell a software package that uses these fonts: Can I do so?
109 |
110 | Sure. Bundle the fonts with your software and sell your software
111 | with the fonts. That is the intent of the copyright.
112 |
113 | 8. If applications have built the names "Bitstream Vera" into them,
114 | can I override this somehow to use fonts of my choosing?
115 |
116 | This depends on exact details of the software. Most open source
117 | systems and software (e.g., Gnome, KDE, etc.) are now converting to
118 | use fontconfig (see www.fontconfig.org) to handle font configuration,
119 | selection and substitution; it has provisions for overriding font
120 | names and subsituting alternatives. An example is provided by the
121 | supplied local.conf file, which chooses the family Bitstream Vera for
122 | "sans", "serif" and "monospace". Other software (e.g., the XFree86
123 | core server) has other mechanisms for font substitution.
124 |
125 |
--------------------------------------------------------------------------------
/src/objects.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | ud_t *newuserdata(lua_State *L, void *handle, const char *mt, const char *tracename)
29 | {
30 | ud_t *ud;
31 | /* we use handle as search key */
32 | ud = (ud_t*)udata_new(L, sizeof(ud_t), (uint64_t)(uintptr_t)handle, mt);
33 | memset(ud, 0, sizeof(ud_t));
34 | ud->handle = handle;
35 | MarkValid(ud);
36 | if(trace_objects)
37 | printf("create %s %p (%p)\n", tracename, (void*)ud, handle);
38 | return ud;
39 | }
40 |
41 | int freeuserdata(lua_State *L, ud_t *ud, const char *tracename)
42 | {
43 | /* The 'Valid' mark prevents double calls when an object is explicitly destroyed,
44 | * and subsequently deleted also by the GC (the ud sticks around until the GC
45 | * collects it, so we mark it as invalid when the object is explicitly destroyed
46 | * by the script, or implicitly destroyed because child of a destroyed object). */
47 | if(!IsValid(ud)) return 0;
48 | CancelValid(ud);
49 | if(ud->info)
50 | Free(L, ud->info);
51 | if(ud->ref1!=LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, ud->ref1);
52 | if(ud->ref2!=LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, ud->ref2);
53 | if(ud->ref3!=LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, ud->ref3);
54 | if(trace_objects)
55 | printf("delete %s %p (%p)\n", tracename, (void*)ud, ud->handle);
56 | udata_free(L, (uint64_t)(uintptr_t)ud->handle);
57 | return 1;
58 | }
59 |
60 | static int freeifchild(lua_State *L, const void *mem, const char *mt, const void *parent_ud)
61 | /* callback for udata_scan */
62 | {
63 | ud_t *ud = (ud_t*)mem;
64 | (void)mt;
65 | if(IsValid(ud) && (ud->parent_ud == parent_ud))
66 | ud->destructor(L, ud);
67 | return 0;
68 | }
69 |
70 | int freechildren(lua_State *L, const char *mt, ud_t *parent_ud)
71 | /* calls the self destructor for all 'mt' objects that are children of the given parent_ud */
72 | {
73 | return udata_scan(L, mt, parent_ud, freeifchild);
74 | }
75 |
76 | int pushuserdata(lua_State *L, ud_t *ud)
77 | {
78 | if(!IsValid(ud)) return unexpected(L);
79 | return udata_push(L, (uint64_t)(uintptr_t)ud->handle);
80 | }
81 |
82 | ud_t *userdata(const void *handle)
83 | {
84 | ud_t *ud = (ud_t*)udata_mem((uint64_t)(uintptr_t)handle);
85 | if(ud && IsValid(ud)) return ud;
86 | return NULL;
87 | }
88 |
89 | void *testxxx(lua_State *L, int arg, ud_t **udp, const char *mt)
90 | {
91 | ud_t *ud = (ud_t*)udata_test(L, arg, mt);
92 | if(ud && IsValid(ud)) { if(udp) *udp=ud; return ud->handle; }
93 | if(udp) *udp = NULL;
94 | return 0;
95 | }
96 |
97 | #if 0
98 | void *testoneofxxx(lua_State *L, int arg, ud_t **udp, char **mtp)
99 | {
100 | void *handle = NULL;
101 | int i = 0;
102 | char *mt = NULL;
103 | while((mt = mtp[i++]) != NULL)
104 | {
105 | handle = testxxx(L, arg, udp, mt);
106 | if(handle) return handle;
107 | }
108 | if(udp) *udp = NULL;
109 | return 0;
110 | }
111 | #endif
112 |
113 |
114 | void *checkxxx(lua_State *L, int arg, ud_t **udp, const char *mt)
115 | {
116 | ud_t *ud = (ud_t*)udata_test(L, arg, mt);
117 | if(ud && IsValid(ud))
118 | { if(udp) *udp = ud; return ud->handle; }
119 | lua_pushfstring(L, "not a %s", mt);
120 | luaL_argerror(L, arg, lua_tostring(L, -1));
121 | return 0;
122 | }
123 |
124 | void *optxxx(lua_State *L, int arg, ud_t **udp, const char *mt)
125 | /* This differs from testxxx in that it fails in case the argument is
126 | * something different than either none/nil or the expected userdata type
127 | */
128 | {
129 | if(lua_isnoneornil(L, arg))
130 | { if(udp) *udp = NULL; return 0; }
131 | return checkxxx(L, arg, udp, mt);
132 | }
133 |
134 | int pushxxx(lua_State *L, void *handle)
135 | { return udata_push(L, (uint64_t)(uintptr_t)handle); }
136 |
137 |
138 | void** checkxxxlist(lua_State *L, int arg, int *count, int *err, const char *mt)
139 | /* xxx* checkxxxlist(lua_State *L, int arg, int *count, int *err)
140 | * Checks if the variable at arg on the Lua stack is a list of xxx objects.
141 | * On success, returns an array of xxx handles and sets its length in *count.
142 | * The array s Malloc'd and must be released by the caller using Free(L, ...).
143 | * On error, sets *err to ERR_XXX, *count to 0, and returns NULL.
144 | */
145 | {
146 | void** list;
147 | int i;
148 |
149 | *count = 0;
150 | *err = 0;
151 | if(lua_isnoneornil(L, arg))
152 | { *err = ERR_NOTPRESENT; return NULL; }
153 | if(lua_type(L, arg) != LUA_TTABLE)
154 | { *err = ERR_TABLE; return NULL; }
155 | *count = luaL_len(L, arg);
156 | if(*count == 0)
157 | { *err = ERR_EMPTY; return NULL; }
158 | list = (void**)MallocNoErr(L, sizeof(void*) * (*count));
159 |
160 | if(!list)
161 | { *count = 0; *err = ERR_MEMORY; return NULL; }
162 |
163 | for(i=0; i<*count; i++)
164 | {
165 | lua_rawgeti(L, arg, i+1);
166 | list[i] = (void*)(uintptr_t)testxxx(L, -1, NULL, mt);
167 | if(!list[i])
168 | { Free(L, list); *count = 0; *err = ERR_TYPE; return NULL; }
169 | lua_pop(L, 1);
170 | }
171 | return list;
172 | }
173 |
174 |
175 | int setmetatable(lua_State *L, const char *mt)
176 | /* Sets the metatable of the table on top of the stack */
177 | {
178 | luaL_getmetatable(L, mt);
179 | lua_setmetatable(L, -2);
180 | return 0;
181 | }
182 |
183 |
--------------------------------------------------------------------------------
/examples/demo/14-chains.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 |
8 | cp.glmath_compat(true)
9 | local pi, infinity = math.pi, math.huge
10 | local sin, cos, abs = math.sin, math.cos, math.abs
11 | local fmt = string.format
12 | local vec2 = glmath.vec2
13 | local clamp, mix = glmath.clamp, glmath.mix
14 | local identity = cp.transform_identity()
15 |
16 | -- Initializations ------------------------------------------------------------
17 |
18 | local TITLE = "Breakable Chains"
19 | local FW, FH = 640, 480 -- width and height of the field
20 | local W, H = 1024, 768 -- window width and height
21 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
22 | local FONT_COLOR, FONT_SIZE = {0xfd/250, 0xf6/250, 0xe3/250, 1.0}, 12/H
23 |
24 | glfw.version_hint(3, 3, 'core')
25 | glfw.window_hint('samples', 32)
26 | local window = glfw.create_window(W, H, TITLE)
27 | glfw.make_context_current(window)
28 | gl.init()
29 | toolbox.init(W, H)
30 | local camera = toolbox.camera()
31 |
32 | local function resize(window, width, height)
33 | W, H = width, height
34 | toolbox.resize(W, H)
35 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
36 | gl.viewport(0, 0, W, H)
37 | end
38 |
39 | glfw.set_window_size_callback(window, resize)
40 | resize(window, W, H)
41 |
42 | -- Fonts ----------------------------------------------------------------------
43 | local font = toolbox.font("../ttf-bitstream-vera-1.10/VeraMoBd.ttf", 40/H)
44 |
45 | -- Demo inits -----------------------------------------------------------------
46 |
47 | local chain_count, link_count = 8, 10
48 | local breaking_force = 80000
49 |
50 | local function breakable_joint_post_solve(joint, space)
51 | local joint = joint
52 | local dt = space:get_current_time_step()
53 | -- Convert the impulse to a force by dividing it by the timestep.
54 | local force = joint:get_impulse()/dt
55 | local maxForce = joint:get_max_force()
56 | -- If the force is almost as big as the joint's max force, break it.
57 | if force > 0.9*maxForce then
58 | space:add_post_step_callback(function(space)
59 | space:remove_constraint(joint)
60 | joint:free()
61 | end)
62 | end
63 | end
64 |
65 | local space = cp.space_new()
66 | local grabber = toolbox.grabber(window, space)
67 | local grabbable, not_grabbable = grabber:filters()
68 | space:set_iterations(30)
69 | space:set_gravity({0, -100})
70 | space:set_sleep_time_threshold(0.5)
71 | local static_body = space:get_static_body()
72 | -- Create segments around the edge of the screen.
73 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,-240}, {-320,240}, 0.0))
74 | shape:set_elasticity(1.0)
75 | shape:set_friction(1.0)
76 | shape:set_filter(not_grabbable)
77 | local shape = space:add_shape(cp.segment_shape_new(static_body, {320,-240}, {320,240}, 0.0))
78 | shape:set_elasticity(1.0)
79 | shape:set_friction(1.0)
80 | shape:set_filter(not_grabbable)
81 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,-240}, {320,-240}, 0.0))
82 | shape:set_elasticity(1.0)
83 | shape:set_friction(1.0)
84 | shape:set_filter(not_grabbable)
85 | local shape = space:add_shape(cp.segment_shape_new(static_body, {-320,240}, {320,240}, 0.0))
86 | shape:set_elasticity(1.0)
87 | shape:set_friction(1.0)
88 | shape:set_filter(not_grabbable)
89 | local mass, width, height = 1, 20, 30
90 | local spacing = width*0.3
91 | -- Add lots of boxes.
92 | for i=0, chain_count-1 do
93 | local prev = nil
94 | for j= 0, link_count-1 do
95 | local pos = vec2(40*(i-(chain_count-1)/2.0), 240-(j+0.5)*height-(j+1)*spacing)
96 | local body = space:add_body(cp.body_new(mass, cp.moment_for_box(mass, width, height)))
97 | body:set_position(pos)
98 | local shape = cp.segment_shape_new(body,
99 | {0, (height-width)/2.0}, {0, (width-height)/2.0}, width/2.0)
100 | space:add_shape(shape)
101 | shape:set_friction(0.8)
102 | local constraint
103 | if not prev then
104 | constraint = cp.slide_joint_new(body, static_body, {0, height/2}, {pos.x, 240}, 0, spacing)
105 | else
106 | constraint = cp.slide_joint_new(body, prev, {0, height/2}, {0, -height/2}, 0, spacing)
107 | end
108 | space:add_constraint(constraint)
109 | constraint:set_max_force(breaking_force)
110 | constraint:set_post_solve_func(breakable_joint_post_solve)
111 | constraint:set_collide_bodies(false)
112 | prev = body
113 | end
114 | end
115 | local radius = 15.0
116 | local body = space:add_body(cp.body_new(10.0, cp.moment_for_circle(10.0, 0.0, radius, {0, 0})))
117 | body:set_position({0, -240 + radius+5})
118 | body:set_velocity({0, 300})
119 | local shape = space:add_shape(cp.circle_shape_new(body, radius, {0, 0}))
120 | shape:set_elasticity(0.0)
121 | shape:set_friction(0.9)
122 |
123 | -- Input handling -------------------------------------------------------------
124 |
125 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
126 | local keys = {} -- keys[k] = true if key k is pressed
127 |
128 | glfw.set_key_callback(window, function(window, key, scancode, action)
129 | if key == 'escape' and action == 'press' then
130 | glfw.set_window_should_close(window, true)
131 | elseif key == 'f11' and action == 'press' then
132 | toggle_fullscreen()
133 | else
134 | keys[key] = action ~= 'release'
135 | end
136 | end)
137 |
138 | glfw.set_cursor_pos_callback(window, function(window, x, y)
139 | grabber:cursor_pos_callback(x, y)
140 | end)
141 |
142 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
143 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
144 | end)
145 |
146 | -- Game loop ------------------------------------------------------------------
147 | local timer = toolbox.frame_timer()
148 | local spf = 1/60 -- 1 / desired fps
149 | local fdt = 1/180 -- fixed dt for physics updates
150 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
151 | local n, dt
152 |
153 | local renderer = toolbox.renderer(space)
154 |
155 | collectgarbage()
156 | collectgarbage('stop')
157 | while not glfw.window_should_close(window) do
158 | glfw.wait_events_timeout(spf)
159 | dt = timer:update() -- duration of the current frame
160 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
161 | space:step(fdt, n)
162 | grabber:step(fdt, n)
163 |
164 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
165 | gl.clear_color(BG_COLOR)
166 | gl.clear('color')
167 |
168 | renderer:begin()
169 | space:debug_draw()
170 | renderer:done()
171 |
172 | -- font:draw(message, .05, .9, FONT_SIZE, FONT_COLOR)
173 |
174 | glfw.swap_buffers(window)
175 | collectgarbage()
176 | end
177 |
178 | toolbox.cleanup()
179 |
180 |
--------------------------------------------------------------------------------
/src/collision_handler.c:
--------------------------------------------------------------------------------
1 | /* The MIT License (MIT)
2 | *
3 | * Copyright (c) 2020 Stefano Trettel
4 | *
5 | * Software repository: MoonChipmunk, https://github.com/stetre/moonchipmunk
6 | *
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy
8 | * of this software and associated documentation files (the "Software"), to deal
9 | * in the Software without restriction, including without limitation the rights
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | * copies of the Software, and to permit persons to whom the Software is
12 | * furnished to do so, subject to the following conditions:
13 | *
14 | * The above copyright notice and this permission notice shall be included in all
15 | * copies or substantial portions of the Software.
16 | *
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | * SOFTWARE.
24 | */
25 |
26 | #include "internal.h"
27 |
28 | static int freecollision_handler(lua_State *L, ud_t *ud)
29 | {
30 | //collision_handler_t *handler = (collision_handler_t*)ud->handle;
31 | if(!freeuserdata(L, ud, "collision_handler")) return 0;
32 | return 0;
33 | }
34 |
35 | int newcollision_handler(lua_State *L, collision_handler_t *handler, space_t *space)
36 | {
37 | ud_t *ud;
38 | if(userdata(handler)) /* already in */
39 | return pushcollision_handler(L, handler);
40 | ud = newuserdata(L, handler, COLLISION_HANDLER_MT, "collision_handler");
41 | ud->parent_ud = userdata(space);
42 | ud->destructor = freecollision_handler;
43 | handler->userData = ud;
44 | return 1;
45 | }
46 |
47 | static int GetTypes(lua_State *L)
48 | {
49 | collision_handler_t *handler = checkcollision_handler(L, 1, NULL);
50 | lua_pushinteger(L, handler->typeA);
51 | lua_pushinteger(L, handler->typeB);
52 | return 2;
53 | }
54 |
55 | static cpBool BeginFunc(cpArbiter *arbiter, space_t *space, cpDataPointer userData)
56 | {
57 | int rc;
58 | cpBool res;
59 | lua_State *L = moonchipmunk_L;
60 | ud_t *ud = (ud_t*)userData;
61 | int top = lua_gettop(L);
62 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref1);
63 | pusharbiter(L, arbiter);
64 | pushspace(L, space);
65 | rc = lua_pcall(L, 2, 1, 0);
66 | invalidatearbiter(L, arbiter);
67 | if(rc != LUA_OK) { lua_error(L); return 0; }
68 | res = lua_toboolean(L, -1);
69 | lua_settop(L, top);
70 | return res;
71 | }
72 |
73 | static cpBool PreSolveFunc(cpArbiter *arbiter, space_t *space, cpDataPointer userData)
74 | {
75 | int rc;
76 | cpBool res;
77 | lua_State *L = moonchipmunk_L;
78 | ud_t *ud = (ud_t*)userData;
79 | int top = lua_gettop(L);
80 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref2);
81 | pusharbiter(L, arbiter);
82 | pushspace(L, space);
83 | rc = lua_pcall(L, 2, 1, 0);
84 | invalidatearbiter(L, arbiter);
85 | if(rc != LUA_OK) { lua_error(L); return 0; }
86 | res = lua_toboolean(L, -1);
87 | lua_settop(L, top);
88 | return res;
89 | }
90 |
91 | static void PostSolveFunc(cpArbiter *arbiter, space_t *space, cpDataPointer userData)
92 | {
93 | int rc;
94 | lua_State *L = moonchipmunk_L;
95 | ud_t *ud = (ud_t*)userData;
96 | int top = lua_gettop(L);
97 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref3);
98 | pusharbiter(L, arbiter);
99 | pushspace(L, space);
100 | rc = lua_pcall(L, 2, 0, 0);
101 | invalidatearbiter(L, arbiter);
102 | if(rc != LUA_OK) { lua_error(L); return; }
103 | lua_settop(L, top);
104 | return;
105 | }
106 |
107 | static void SeparateFunc(cpArbiter *arbiter, space_t *space, cpDataPointer userData)
108 | {
109 | int rc;
110 | lua_State *L = moonchipmunk_L;
111 | ud_t *ud = (ud_t*)userData;
112 | int top = lua_gettop(L);
113 | lua_rawgeti(L, LUA_REGISTRYINDEX, ud->ref4);
114 | pusharbiter(L, arbiter);
115 | pushspace(L, space);
116 | rc = lua_pcall(L, 2, 0, 0);
117 | invalidatearbiter(L, arbiter);
118 | if(rc != LUA_OK)
119 | { lua_error(L); return; }
120 | lua_settop(L, top);
121 | return;
122 | }
123 |
124 | static int SetBeginFunc(lua_State *L)
125 | {
126 | ud_t *ud;
127 | collision_handler_t *handler = checkcollision_handler(L, 1, &ud);
128 | if(!lua_isfunction(L, 2)) return argerror(L, 2, ERR_FUNCTION);
129 | Reference(L, 2, ud->ref1);
130 | handler->beginFunc = BeginFunc;
131 | return 0;
132 | }
133 |
134 | static int SetPreSolveFunc(lua_State *L)
135 | {
136 | ud_t *ud;
137 | collision_handler_t *handler = checkcollision_handler(L, 1, &ud);
138 | if(!lua_isfunction(L, 2)) return argerror(L, 2, ERR_FUNCTION);
139 | Reference(L, 2, ud->ref2);
140 | handler->preSolveFunc = PreSolveFunc;
141 | return 0;
142 | }
143 |
144 | static int SetPostSolveFunc(lua_State *L)
145 | {
146 | ud_t *ud;
147 | collision_handler_t *handler = checkcollision_handler(L, 1, &ud);
148 | if(!lua_isfunction(L, 2)) return argerror(L, 2, ERR_FUNCTION);
149 | Reference(L, 2, ud->ref3);
150 | handler->postSolveFunc = PostSolveFunc;
151 | return 0;
152 | }
153 |
154 | static int SetSeparateFunc(lua_State *L)
155 | {
156 | ud_t *ud;
157 | collision_handler_t *handler = checkcollision_handler(L, 1, &ud);
158 | if(!lua_isfunction(L, 2)) return argerror(L, 2, ERR_FUNCTION);
159 | Reference(L, 2, ud->ref4);
160 | handler->separateFunc = SeparateFunc;
161 | return 0;
162 | }
163 |
164 |
165 | RAW_FUNC(collision_handler)
166 | PARENT_FUNC(collision_handler)
167 | DESTROY_FUNC(collision_handler)
168 |
169 | static const struct luaL_Reg Methods[] =
170 | {
171 | { "raw", Raw },
172 | { "parent", Parent },
173 | { "free", Destroy },
174 | { "get_types", GetTypes },
175 | { "set_begin_func", SetBeginFunc },
176 | { "set_pre_solve_func", SetPreSolveFunc },
177 | { "set_post_solve_func", SetPostSolveFunc },
178 | { "set_separate_func", SetSeparateFunc },
179 | { NULL, NULL } /* sentinel */
180 | };
181 |
182 | static const struct luaL_Reg MetaMethods[] =
183 | {
184 | { "__gc", Destroy },
185 | { NULL, NULL } /* sentinel */
186 | };
187 |
188 | static const struct luaL_Reg Functions[] =
189 | {
190 | { NULL, NULL } /* sentinel */
191 | };
192 |
193 |
194 | void moonchipmunk_open_collision_handler(lua_State *L)
195 | {
196 | udata_define(L, COLLISION_HANDLER_MT, Methods, MetaMethods);
197 | luaL_setfuncs(L, Functions, 0);
198 | }
199 |
200 |
--------------------------------------------------------------------------------
/examples/demo/10-query.lua:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | local glfw = require("moonglfw")
3 | local gl = require("moongl")
4 | local glmath = require("moonglmath")
5 | local cp = require("moonchipmunk")
6 | local toolbox = require("moonchipmunk.toolbox")
7 |
8 | cp.glmath_compat(true)
9 | local pi, infinity = math.pi, math.huge
10 | local sin, cos, abs = math.sin, math.cos, math.abs
11 | local fmt = string.format
12 | local vec2 = glmath.vec2
13 | local clamp, mix = glmath.clamp, glmath.mix
14 | local identity = cp.transform_identity()
15 |
16 | -- Initializations ------------------------------------------------------------
17 |
18 | local TITLE = "Segment Query"
19 | local FW, FH = 640, 480 -- width and height of the field
20 | local W, H = 1024, 768 -- window width and height
21 | local BG_COLOR = {0x07/255, 0x36/255, 0x42/255, 1.0}
22 | local FONT_COLOR, FONT_SIZE = {0xfd/250, 0xf6/250, 0xe3/250, 1.0}, 12/H
23 |
24 | local NO_COLOR = {0, 0, 0, 0}
25 | local RED = {1, 0, 0, 1}
26 | local GREEN = {0, 1, 0, 1}
27 | local BLUE = {0, 0, 1, 1}
28 | local GREY = {.5, .5, .5, 1}
29 |
30 | glfw.version_hint(3, 3, 'core')
31 | glfw.window_hint('samples', 32)
32 | local window = glfw.create_window(W, H, TITLE)
33 | glfw.make_context_current(window)
34 | gl.init()
35 | toolbox.init(W, H)
36 | local camera = toolbox.camera()
37 |
38 | local function resize(window, width, height)
39 | W, H = width, height
40 | toolbox.resize(W, H)
41 | toolbox.set_matrices(camera:view(), camera:projection(-FW/2, FW/2, -FH/2, FH/2))
42 | gl.viewport(0, 0, W, H)
43 | end
44 |
45 | glfw.set_window_size_callback(window, resize)
46 | resize(window, W, H)
47 |
48 | -- Fonts ----------------------------------------------------------------------
49 | local font = toolbox.font("../ttf-bitstream-vera-1.10/VeraMoBd.ttf", 40/H)
50 |
51 | -- Demo inits -----------------------------------------------------------------
52 | local space = cp.space_new()
53 | local grabber = toolbox.grabber(window, space)
54 | local grabbable, not_grabbable = grabber:filters()
55 | local filter_all = {group=0, categories=-1, mask=-1 }
56 | local filter_none = {group=0, categories=0, mask=0 }
57 | space:set_iterations(5)
58 |
59 | -- add a fat segment
60 | local mass, length = 1.0, 100.0
61 | local a, b = {-length/2.0, 0.0}, {length/2.0, 0.0}
62 | local body = space:add_body(cp.body_new(mass, cp.moment_for_segment(mass, a, b, 0.0)))
63 | body:set_position({0.0, 100.0})
64 | space:add_shape(cp.segment_shape_new(body, a, b, 20.0))
65 | -- add a static segment
66 | space:add_shape(cp.segment_shape_new(space:get_static_body(), {0, 300}, {300, 0}, 0.0))
67 | -- add a pentagon
68 | local mass, verts = 1.0, {}
69 | for i=0, 5 do
70 | local angle = -2.0*pi*i/5
71 | table.insert(verts, {30*cos(angle), 30*sin(angle)})
72 | end
73 | local body = space:add_body(cp.body_new(mass, cp.moment_for_poly(mass, verts, {0, 0}, 0.0)))
74 | body:set_position({50.0, 30.0})
75 | space:add_shape(cp.poly_shape_new(body, verts, 10.0, identity))
76 | -- add a circle
77 | local mass, r = 1.0, 20.0
78 | local body = space:add_body(cp.body_new(mass, cp.moment_for_circle(mass, 0.0, r, {0, 0})))
79 | body:set_position({100.0, 100.0})
80 | space:add_shape(cp.circle_shape_new(body, r, {0, 0}))
81 |
82 | -- Input handling -------------------------------------------------------------
83 |
84 | local toggle_fullscreen = toolbox.toggle_fullscreen(window)
85 | local keys = {} -- keys[k] = true if key k is pressed
86 |
87 | local right_click = false
88 | local query_start = vec2()
89 |
90 | glfw.set_key_callback(window, function(window, key, scancode, action)
91 | if key == 'escape' and action == 'press' then
92 | glfw.set_window_should_close(window, true)
93 | elseif key == 'f11' and action == 'press' then
94 | toggle_fullscreen()
95 | elseif key == 'right' then right_click = action~='release'
96 | else
97 | keys[key] = action ~= 'release'
98 | end
99 | end)
100 |
101 | glfw.set_cursor_pos_callback(window, function(window, x, y)
102 | grabber:cursor_pos_callback(x, y)
103 | end)
104 |
105 | glfw.set_mouse_button_callback(window, function(window, button, action, shift, control, alt, super)
106 | grabber:mouse_button_callback(button, action, shift, control, alt, super)
107 | end)
108 |
109 | -- Game loop ------------------------------------------------------------------
110 | local timer = toolbox.frame_timer()
111 | local spf = 1/60 -- 1 / desired fps
112 | local fdt = 1/60 -- fixed dt for physics updates
113 | local n_physics_updates = toolbox.fixed_dt_counter(fdt)
114 | local n, dt
115 |
116 | local renderer = toolbox.renderer(space)
117 | local message1, message2
118 |
119 | collectgarbage()
120 | collectgarbage('stop')
121 | while not glfw.window_should_close(window) do
122 | glfw.wait_events_timeout(spf)
123 | dt = timer:update() -- duration of the current frame
124 | n = n_physics_updates(dt) -- no. of physics updates to do in this frame
125 | space:step(fdt, n)
126 | grabber:step(fdt, n)
127 |
128 | glfw.set_window_title(window, fmt("%s - fps=%.0f, n=%d", TITLE, timer:fps(), n))
129 | gl.clear_color(BG_COLOR)
130 | gl.clear('color')
131 |
132 | renderer:begin()
133 | space:debug_draw()
134 |
135 | local mouse_pos = grabber:get_pos()
136 | if right_click then query_start = mouse_pos end
137 | local p_start = query_start
138 | local p_end = mouse_pos
139 | local dist = (p_end - p_start):norm()
140 | local radius = 10.0
141 |
142 | renderer:draw_segment(p_start, p_end, GREEN)
143 | message1 = fmt("Query: Dist(%f) Point(%5.2f, %5.2f), ", dist, p_end.x, p_end.y)
144 | local info = space:segment_query_first(p_start, p_end, radius, filter_all)
145 | local alpha = info and info.alpha or 0
146 | if info then
147 | local point, normal = info.point, info.normal
148 | -- Draw blue over the occluded part of the query
149 | renderer:draw_segment(mix(p_start, p_end, alpha), p_end, BLUE)
150 | -- Draw a little red surface normal
151 | renderer:draw_segment(point, point + 16*normal, RED)
152 | -- Draw a little red dot on the hit point.
153 | renderer:draw_dot(3, point, RED)
154 | message2 = fmt("Segment Query: Dist(%f) Normal(%5.2f, %5.2f)", alpha*dist, normal.x, normal.y)
155 | else
156 | message2 = "Segment Query (None)"
157 | end
158 | -- Draw a fat green line over the unoccluded part of the query
159 | renderer:draw_fat_segment(p_start, mix(p_start,p_end, alpha), radius, GREEN, NO_COLOR)
160 | local nearest_info = space:point_query_nearest(mouse_pos, 100.0, filter_all)
161 | if nearest_info then
162 | -- Draw a grey line to the closest shape.
163 | renderer:draw_dot(3, mouse_pos, GREY)
164 | renderer:draw_segment(mouse_pos, nearest_info.point, GREY)
165 | -- Draw a red bounding box around the shape under the mouse.
166 | if nearest_info.distance < 0 then
167 | renderer:draw_box(nearest_info.shape:get_bb(), RED)
168 | end
169 | end
170 |
171 | renderer:done()
172 |
173 | font:draw(message1..message2, .05, .9, FONT_SIZE, FONT_COLOR)
174 |
175 | glfw.swap_buffers(window)
176 | collectgarbage()
177 | end
178 |
179 | toolbox.cleanup()
180 |
181 |
--------------------------------------------------------------------------------