Chipmunk-6.1.5/000755 000765 000000 00000000000 12152211306 014215 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/.gitignore000644 000765 000000 00000000460 12151675775 016234 0ustar00slembckewheel000000 000000 .DS_Store doc/index.html xcode/Chipmunk6.xcodeproj/*.pbxuser xcode/Chipmunk6.xcodeproj/*.perspectivev3 xcode/Chipmunk6.xcodeproj/xcuserdata xcode/Chipmunk6.xcodeproj/project.xcworkspace xcode/DerivedData build *.opensdf *.sdf *.suo msvc/vc10/chipmunk/Win32/ msvc/vc10/demo/ipch/ msvc/vc10/demo/Win32/ Chipmunk-6.1.5/CMakeLists.txt000644 000765 000000 00000003005 12151675775 017002 0ustar00slembckewheel000000 000000 cmake_minimum_required(VERSION 2.6) cmake_policy(SET CMP0001 NEW) # don't use MAKE_BACKWARDS_COMPATIBILITY but policies instead project(chipmunk) # to change the prefix, run cmake with the parameter: # -D CMAKE_INSTALL_PREFIX=/my/prefix # to change the build type, run cmake with the parameter: # -D CMAKE_BUILD_TYPE= # run "cmake --help-variable CMAKE_BUILD_TYPE" for details if(NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) endif() # other options for the build, you can i.e. activate the shared library by passing # -D BUILD_SHARED=ON # to cmake. Other options analog option(BUILD_DEMOS "Build the demo applications" ON) option(INSTALL_DEMOS "Install the demo applications" OFF) option(BUILD_SHARED "Build and install the shared library" ON) option(BUILD_STATIC "Build as static library" ON) option(INSTALL_STATIC "Install the static library" ON) # sanity checks... if(INSTALL_DEMOS) set(BUILD_DEMOS ON FORCE) endif() # these need the static lib too if(BUILD_DEMOS OR INSTALL_STATIC) set(BUILD_STATIC ON FORCE) endif() if(NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") # always use gnu99 set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ffast-math") # extend release-profile with fast-math set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall") # extend debug-profile with -Wall endif() add_subdirectory(src) if(BUILD_DEMOS) add_subdirectory(Demo) endif() Chipmunk-6.1.5/Demo/000755 000765 000000 00000000000 12151675775 015130 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/doc/000755 000765 000000 00000000000 12152211306 014762 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/extract_protos.rb000644 000765 000000 00000001256 12151675775 017655 0ustar00slembckewheel000000 000000 # match 0 is the whole function proto # match 1 is either "static inline " or nil # match 2 is the return type # match 3 is the function symbol name # match 4 is the arguments PATTERN = /.*?((static inline )?(\w*\*?)\s(cp\w*)\((.*?)\))/ IO.readlines("|gcc -DNDEBUG -E include/chipmunk/chipmunk.h").each do|line| str = line while match = PATTERN.match(str) str = match.post_match proto, inline, ret, name, args = match.captures.values_at(0, 1, 2, 3, 4) next if ret == "return" || ret == "" inline = !!inline p({:inline => inline, :return => ret, :name => name, :args => args}) # puts "#{name} - #{inline ? "static inline " : ""}#{ret} #{name}(#{args})" end end Chipmunk-6.1.5/include/000755 000765 000000 00000000000 12151675775 015667 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/LICENSE.txt000644 000765 000000 00000002073 12151675775 016071 0ustar00slembckewheel000000 000000 Copyright (c) 2007 Scott Lembcke and Howling Moon Software Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chipmunk-6.1.5/msvc/000755 000765 000000 00000000000 12151675775 015214 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/README.textile000644 000765 000000 00000011671 12151675775 016607 0ustar00slembckewheel000000 000000 !http://files.slembcke.net/chipmunk/logo/logo1_med.png! h2. ABOUT: Chipmunk is a simple, lightweight, fast and portable 2D rigid body physics library written in C. It's licensed under the unrestrictive, OSI approved MIT license. My aim is to give 2D developers access to the same quality of physics you find in newer 3D games. I hope you enjoy using Chipmunk, and please consider donating to help make it worth our time to continue to support Chipmunk with great new features. h2. FEATURES: * Designed specifically for 2D video games. * Circle, convex polygon, and beveled line segment collision primitives. * Multiple collision primitives can be attached to a single rigid body. * Fast broad phase collision detection by using a bounding box tree with great temporal coherence or a spatial hash. * Extremely fast impulse solving by utilizing Erin Catto's contact persistence algorithm. * Supports sleeping objects that have come to rest to reduce the CPU load. * Support for collision event callbacks based on user definable object types types. * Flexible collision filtering system with layers, exclusion groups and callbacks. ** Can be used to create all sorts of effects like one way platforms or buoyancy areas. (Examples included) * Supports nearest point, segment (raycasting), shape and bounding box queries to the collision detection system. * Collision impulses amounts can be retrieved for gameplay effects, sound effects, etc. * Large variety of joints - easily make vehicles, ragdolls, and more. * Joint callbacks. ** Can be used to easily implement breakable or animated joints. (Examples included) * Maintains a contact graph of all colliding objects. * Lightweight C99 implementation with no external dependencies outside of the Std. C library. * "Many language bindings available":http://chipmunk-physics.net/bindingsAndPorts.php. * Simple, read the "documentation":http://chipmunk-physics.net/documentation.php and see! * Unrestrictive MIT license h2. CONTRACTING: Howling Moon Software (my company) is available for contracting if you want to make the physics in your game really stand out. Given our unique experience with the library, we can help you use Chipmunk to it's fullest potential. Feel free to contact us through our webpage: http://howlingmoonsoftware.com/contracting.php h2. CHIPMUNK PRO: We also make a bunch of extra for Chipmunk called "Chipmunk Pro":http://chipmunk-physics.net/chipmunkPro.php. Currently we have a nice Objective-C wrapper that should be of particular interest to Mac and iPhone developers. It also offers auto-geometry features and multithreading/SIMD optimizations as well. Check out the link above for more information! h2. BUILDING: Mac OS X: There is an included XCode project file for building the static library and demo application. Alternatively you could use the CMake files or the macstatic.command script to build a static lib and package up the headers for you. iPhone: If you want a native Objective-C API, check out Chipmunk Pro on the Chipmunk website. It is inexpensive to license and will save you a lot of time. Otherwise, the XCode project can build a static library with all the proper compiler settings. Alternatively, you can just run iphonestatic.command in the macosx/ directory. It will build you a fat library compiled as release for the device and debug for the simulator. After running it, you can simply drop the Chipmunk-iPhone directory into your iPhone project! UNIXes: A forum user was kind enough to make a set of CMake files for Chipmunk. This will require you to have CMake installed. To build run 'cmake .' then 'make'. This should build a dynamic library, a static library, and the demo application. A number of people have had build errors on Ubuntu due to not having GLUT or libxmu installed. Windows: Visual Studio projects are included in the msvc/ directory. While I try to make sure the MSVC 10 project is up to date, I don't have MSVC 9 to keep that project updated regularly. It may not work. I'd appreciate a hand fixing it if that's the case. h2. GETTING STARTED: First of all, you can find the C API documentation in the doc/ directory. A good starting point is to take a look at the included Demo application. The demos all just set up a Chipmunk simulation space and the demo app draws the graphics directly out of that. This makes it easy to see how the Chipmunk API works without worrying about the graphics code. You are free to use the demo drawing routines in your own projects, though it is certainly not the recommended way of drawing Chipmunk objects as it pokes around at the undocumented/private APIs of Chipmunk. h2. SUPPORT: The best way to get support is to visit the "Chipmunk Forums":http://chipmunk-physics.net/forum/. There are plenty of people around using Chipmunk on the just about every platform I've ever heard of. If you are working on a commercial project and want some more direct help, Howling Moon Software is also available for "contracting":http://howlingmoonsoftware.com/contracting.php. Chipmunk-6.1.5/src/000755 000765 000000 00000000000 12151675775 015033 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/VERSION.txt000644 000765 000000 00000043007 12151675775 016136 0ustar00slembckewheel000000 000000 CHANGES SINCE 6.1.3: * MISC: Fixed a build script issue that was preventing the documentation from being generated. CHANGES SINCE 6.1.2: * BUG: Fixed a couple of very specific but fatal bugs that occur when sleeping is enabled and filtering collisions. * BUG: Fixed an issue with cpvslerp() between very similar vectors. * BUG: Fixed an issue with grab friction in ChipmunkMultiGrab. (Pro only) * MISC: Implemented the cpConstraintGetImpulse() functionality for spring joints. * MISC: Added more functions to chipmunk_ffi.h CHANGES SINCE 6.1.1: * API: Added a cpArbiter.data pointer. Now you can tag collisions with custom persistent data. * API: Added segment to segment collisions (thanks to LegoCylon) * API: cpSpaceAddPostStepCallback() now returns false if the callback was a duplicate. * API: Added the ChipmunkAbstractSampler.marchThreshold property instead of hardcoding it to 0.5. * API: Added ChipmunkGrooveJoint properties for the groove and joint anchors. * API: ChipmunkMultiGrab now returns information about grabbed shapes. * BUG: Fixed a minor (non-crashing, non-leaking) memory pooling issue with reindexing lots of static shapes. * BUG: Fixed an issue with the slerp functions that would cause them to return incorrect results when given non-unit length input. * BUG: Fixed a precision bug with the ChipmunkImage sampler classes that could cause artifacts or miss small features. * BUG: Fixed a number of properties in Objective-Chipmunk that should have been nonatomic. * BUG: Fixed a number of types in Objective-Chipmunk that were incorrectly id that should have been cpGroup, cpCollisionType etc. It's now possible to redefine them at compile time if you wish. * MISC: Dropped armv6 support in favor of armv7s on iOS. (You can switch it back easily if you need.) * MISC: Updated iOS build scripts to guess the latest SDK. * MISC: Added the "Sticky Surfaces" demo as a cpArbiter.data example. * MISC: Updated Objective-Chipmunk build scripts to always use the latest iOS SDK. CHANGES SINCE 6.1.0: * API: Renamed the new block based iterators as soon as possible to match the Apple convention ("_b" suffix). CHANGES SINCE 6.0.3: * API: Added a pthread based, multi-threaded solver to accelerate the game on multi-core systems. (Pro only) * API: Added cpConvexHull() and CP_CONVEX_HULL() for generating convex hulls. * API: Added cpPolylineConvexDecomposition_BETA() to generate an approximate concave decomposition of a polyline. (Pro only) * API: Added [ChipmunkPolyline toConvexHull:] to generate approximate convex hulls. (Pro only). * API: Added [ChipmunkPolylineSet toConvexHulls_BETA:]. (Pro only) * API: Added nearest point queries. * API: Added a push mode to ChipmunkMultiGrab so touches can interact with the scene even if they didn't initially touch a shape. (Pro only) * API: Added optional block based iterators. * API: Added a space property to cpBody, cpShape and cpConstraint types. * BUG: Fixed an issue with changing the floating point and vector type on OS X. * BUG: Fixed a pixel offset in ChipmunkImageSampler that could cause minor sampling artifacts. (Pro only) * BUG: Fixed an issue where cpShape and cpConstraint structs could have garbage space pointers if cpcalloc() was redefined. * BUG: Fixed assertions in cpArbiter getters to correctly reflect a contact count of 0 from separate() callbacks. * BUG: Fixed a regression relating to registering post-step() callbacks from other post-step() callbacks. * BUG: Fixed a minor memory leak for sleeping bodies when destroying a space. * MISC: Point queries are now deprecated in preference to point queries. * MISC: cpSpatialIndexPointQuery() was redundant and has been removed. Use cpSpatialIndexQuery() instead. * MISC: cpShape*Query() functions now accept a NULL info pointer if you don't want detailed query info. * MISC: The enableContactGraph property of cpSpace is deprecated and always be true. * MISC: Added a new demos of the convex hull functions and a self balancing Unicycle. CHANGES SINCE 6.0.2: * API: Added a cpBBForCircle() convenience function. * API: Added cpBBSegmentQuery() to check where a segment hits a cpBB. * API: Added cpBodyGetVelAtWorldPoint() and cpBodyGetVelAtLocalPoint() to get point velocities on a body. * API: Added cpArbiterTotalKE() to calculate the energy lost due to a collision. Great for calculating damage accurately. * API: Added methods to get an ObjC pointer from a C chipmunk struct. * API: Added a CHIPMUNK_ARBITER_GET_BODIES() macro for Objective-Chipmunk. * API: The Objective-Chipmunk headers are now ARC compatible. * API: Added a [ChipmunkSpace contains:] method to check if a ChipmunkObject has been added to the space or not. * API: Added a cpBBNewForCircle() function. * API: Added a cpBBSegmentQuery() function for raycasting againsts AABBs. * BUG: Fixed a regression with ChipmunkSpace.bodies and ChipmunkSpace.shapes that caused crashes. * BUG: Fixed a rare bug with postStep() callbacks and iterators. * BUG: Fixed a border case in cpBBIntersectsSegment() that could cause missed segment queries. * MISC: Added some new assertions for error conditions that were previously uncaught. * MISC: Accelerated segment queries in cpBBTree by sorting the nodes. * MISC: Added a new "Slice" demo that lets you cut up a polygon. * MISC: Added NEON optimizations for Chipmunk Pro. Expect running on most ARM platforms to be 25-35% faster for contact heavy simulations. * MISC: All ChipmunkObject instances added to a space are now retained, even composite ones. CHANGES SINCE 6.0.1: * API: Added cpSpaceIsLocked() to check if you are in a callback or not. * API: Removed the long deprecated [ChipmunkSpace addShapeAHandler:] and [ChipmunkSpace addShapeBHandler:] methods. * API: The ChipmunkObject protocol now can return any id object instead of just an NSSet. * API: The largely useless [ChipmunkSpace addBaseObjects:] and [ChipmunkSpace removeBaseObjects:] methods were removed. * API: Added [ChipmunkSpace smartAdd:] and [ChipmunkSpace smartRemove:] methods for a consistent API to remove objects inside and out of callbacks. * API: Added [ChipmunkSpace addPostStepBlock:key:] to complement [ChipmunkSpace addPostStepCallback:selector:key:]. * API: Added [ChipmunkSpace addPostStepAddition:]. * API: Objective-Chipmunk collision handlers no longer retain their target to avoid reference cycles. * API: Added callbacks to joints. * BUG: Soft errors (only checked when debug mode is enabled) and warnings were disabled. Whoops. * BUG: cpShapeIsSensor() was incorrectly named in chipmunk_ffi.h. * BUG: It should be safe to call cpActivateBody() from an space iterator callback now. * MISC: Very nice bouyancy demo added based on callbacks. * MISC: Breakable Joints demo showing how to use the new joint callbacks. * MISC: Player demo updated and greatly enhanced by Chipmunk 6 features. * MISC: Changed adding a static body to a space from a warning to a hard error. * MISC: cpGroup and cpCollisionType now default to uintptr_t so you can safely use pointers instead of ints for these types. * MISC: Updated the MSVC10 project file. * MISC: Updated the FFI defs. CHANGES SINCE 6.0.0: * BUG: Calling cpBodySetPos() on a sleeping body was delaying the Separate() handler callback if one existed. * BUG: Fixed a bug where Separate() handler callbacks were not occuring when removing shapes. * BUG: Calling cpBodyApplyForce() or cpBodyResetForces() was not activating sleeping bodies. * API: Added cpSpaceEachConstraint(). * API: Added a "CurrentTimeStep" property to cpSpace to retrieve the current (or most recent) timestep. * MISC: Got rid of anonymous unions so that it is C99 clean again. CHANGES SINCE 5.x: Chipmunk 6.x's API is not quite 100% compatible with 5.x. Make sure you read the list of changes carefully. Keep in mind that this is a x.0.0 release and that it's likely there are still some bugs I don't know about yet. I've spent a lot of effort rewritting the collision detection, sleeping, and contact graph algorithms that have required large changes and cleanup to the 5.x codebase. I've ironed out all the bugs that I know of, and the beta test went well. So it's finally time for 6! * API: Chipmunk now has hard runtime assertions that aren't disabled in release mode for many error conditions. Most people have been using release builds of Chipmunk during development and were missing out on very important error checking. * API: Access to the private API has been disabled by default now and much of the private API has changed. I've added official APIs for all the uses of the private API I knew of. * API: Added accessor functions for every property on every type. As Chipmunk's complexity has grown, it's become more difficult to ignore accessors. You are encouraged to use them, but are not required to. * API: Added cpSpaceEachBody() and cpSpaceEachShape() to iterate bodies/shapes in a space. * API: Added cpSpaceReindexShapesForBody() to reindex all the shapes attached to a particular body. * API: Added a 'data' pointer to spaces now too. * API: cpSpace.staticBody is a pointer to the static body instead of a static reference. * API: The globals cp_bias_coef, cp_collision_slop, cp_contact_persistence have been moved to properties of a space. (collisionBias, collisionSlop, collisionPersistence respectively) * API: Added cpBodyActivateStatic() to wake up bodies touching a static body with an optional shape filter parameter. * API: Added cpBodyEachShape() and cpBodyEachConstraint() iterators to iterate the active shapes/constraints attached to a body. * API: Added cpBodyEeachArbiter() to iterate the collision pairs a body is involved in. This makes it easy to perform grounding checks or find how much collision force is being applied to an object. * API: The error correction applied by the collision bias and joint bias is now timestep independent and the units have completely changed. * FIX: Units of damping for springs are correct regardless of the number of iterations. Previously they were only correct if you had 1 or 2 iterations. * MISC: Numerous changes to help make Chipmunk work better with variable timesteps. Use of constant timesteps is still highly recommended, but it is now easier to change the time scale without introducing artifacts. * MISC: Performance! Chipmunk 6 should be way faster than Chipmunk 5 for almost any game. * MISC: Chipmunk supports multiple spatial indexes and uses a bounding box tree similar to the one found in the Bullet physics library by default. This should provide much better performance for scenes with objects of differening size and works without any tuning for any scale. CHANGES SINCE 5.3.4 * FIX: Fixed spelling of cpArbiterGetDepth(). Was cpArbiteGetDepth() before. Apparently nobody ever used this function. * FIX: Added defines for M_PI and M_E. Apparently these values were never part of the C standard math library. Who knew!? * FIX: Added a guard to cpBodyActivate() so that it's a noop for rouge bodies. * FIX: Shape queries now work with (and against) sensor shapes. * FIX: Fixed an issue where removing a collision handler while a separate() callback was waiting to fire the next step would cause crashes. * FIX: Fixed an issue where the default callback would not be called for sensor shapes. * FIX: Resetting or applying forces or impulses on a body causes it to wake up now. * MISC: Added a check that a space was not locked when adding or removing a callback. * MISC: Removed cpmalloc from the API and replaced all occurences with cpcalloc * MISC: Added a benchmarking mode to the demo app. -trial runs it in time trial mode and -bench makes it run some benchmarking demos. CHANGES SINCE 5.3.3: * FIX: cpBodyActivate() can now be called from collision and query callbacks. This way you can use the setter functions to change properties without indirectly calling cpBodyActivate() and causing an assertion. * FIX: cpArbiterGetContactPointSet() was returning the collision points for the normals. * FIX: cpSpaceEachBody() now includes sleeping bodies. * FIX: Shapes attached to static rogue bodies created with cpBodyNewStatic() are added as static shapes. * MISC: Applied a user patch to update the MSVC project and add a .def file. CHANGES SINCE 5.3.2: * API: Added cpArbiteGetCount() to return the number of contact points. * API: Added helper functions for calculating areas of Chipmunk shapes as well as calculating polygon centroids and centering polygons on their centroid. * API: Shape queries. Query a shape to test for collisions if it were to be inserted into a space. * API: cpBodyInitStatic() and cpBodyNewStatic() for creating additional static (rogue) bodies. * API: cpBodySleepWithGroup() to allow you to create groups of sleeping objects that are woken up together. * API: Added overloaded *, +, - and == operators for C++ users. * API: Added cpSpaceActivateShapesTouchingShape() to query for and activate any shapes touching a given shape. Useful if you ever need to move a static body. * FIX: Fixed an extremely rare memory bug in the collision cache. * FIX: Fixed a memory leak in Objective-Chipmunk that could cause ChipmunkSpace objects to be leaked. * MISC: C struct fields and function that are considered private have been explicitly marked as such. Defining CP_ALLOW_PRIVATE_ACCESS to 0 in Chipmunk.h will let you test which parts of the private API that you are using and give me feedback about how to build proper APIs in Chipmunk 6 for what you are trying to do. * MISC: Allow CGPoints to be used as cpVect on Mac OS X as well as iOS. CHANGES SINCE 5.3.1: * FIX: Collision begin callbacks were being called continuously for sensors or collisions rejected from the pre-solve callback. * FIX: Plugged a nasty memory leak when adding post-step callbacks. * FIX: Shapes were being added to the spatial hash using an uninitialized bounding box in some cases. * FIX: Perfectly aligned circle shapes now push each other apart. * FIX: cpBody setter functions now call cpBodyActivate(). * FIX: Collision handler targets are released in Objective-Chipmunk when they are no longer needed instead of waiting for the space to be deallocated. * API: cpSpaceSegmentQuery() no longer returns a boolean. Use cpSpaceSegmentQueryFirst() instead as it's more efficient. * NEW: cpSpaceRehashShape() Rehash an individual shape, active or static. * NEW: cpBodySleep() Force a body to fall asleep immediately. * NEW: cpConstraintGetImpulse() Return the most recent impulse applied by a constraint. * NEW: Added setter functions for the groove joint endpoints. * MISC: A number of other minor optimizations and fixes. CHANGES SINCE 5.3.0: * NEW: Added a brand new tutorial for Objective-Chipmunk: SimpleObjectiveChipmunk that can be found in the Objective-Chipmunk folder. * NEW: Proper API docs for Objective-Chipmunk. * NEW: Updated the included Objective-Chipmunk library. * FIX: Fixed a rare memory crash in the sensor demo. * FIX: Fixed some warnings that users submitted. CHANGES SINCE 5.2.0: * FIX: Fixed the source so it can compile as C, C++, Objective-C, and Objective-C++. * FIX: Fixed cp_contact_persistence. It was broken so that it would forget collision solutions after 1 frame instead of respecting the value set. * OPTIMIZATION: Several minor optimizations have been added. Though performance should only differ by a few percent. * OPTIMIZATION: Chipmunk now supports putting bodies to sleep when they become inactive. * API: Elastic iterations are now deprecated as they should no longer be necessary. * API: Added API elements to support body sleeping. * API: Added a statically allocated static body to each space for attaching static shapes to. * API: Static shapes attached to the space's static body can simply be added to the space using cpSpaceAddShape(). * NEW: New MSVC projects. * NEW: Added boolean and time stamp types for clarity. CHANGES SINCE 5.1.0: * OPTIMIZATION: Chipmunk structs used within the solver are now allocated linearly in large blocks. This is much more CPU cache friendly. Programs have seen up to 50% performance improvements though 15-20% should be expected. * API: Shape references in cpArbiter structs changed to private_a and private_b to discourage accessing the fields directly and getting them out of order. You should be using cpArbiterGetShapes() or CP_ARBITER_GET_SHAPES() to access the shapes in the correct order. * API: Added assertion error messages as well as warnings and covered many new assertion cases. * FIX: separate() callbacks are called before shapes are removed from the space to prevent dangling pointers. * NEW: Added convenience functions for creating box shapes and calculating moments. CHANGES SINCE 5.0.0: * FIX: fixed a NaN issue that was causing raycasts for horizontal or vertical lines to end up in an infinite loop * FIX: fixed a number of memory leaks * FIX: fixed warnings for various compiler/OS combinations * API: Rejecting a collision from a begin() callback permanently rejects the collision until separation * API: Erroneous collision type parameterns removed from cpSpaceDefaulteCollisionHandler() * MOVE: FFI declarations of inlined functions into their own header * MOVE: Rearranged the project structure to separate out the header files into a separate include/ directory. * NEW: Added a static library target for the iPhone. * NEW: Type changes when building on the iPhone to make it friendlier to other iPhone APIs * NEW: Added an AABB query to complement point and segment queries * NEW: CP_NO_GROUP and CP_ALL_LAYERS constants CHANGES SINCE 4.x: * Brand new Joint/Constraint API: New constraints can be added easily and are much more flexible than the old joint system * Efficient Segment Queries - Like raycasting, but with line segments. * Brand new collision callback API: Collision begin/separate events, API for removal of objects within callbacks, more programable control over collision handling.Chipmunk-6.1.5/xcode/000755 000765 000000 00000000000 12151675775 015346 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/xcode/Chipmunk6.xcodeproj/000755 000765 000000 00000000000 12151675775 021206 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/xcode/iphonestatic.command000755 000765 000000 00000003423 12151675775 021405 0ustar00slembckewheel000000 000000 #! /usr/bin/ruby Dir.chdir(File.dirname($0)) require 'Tempfile' BUILD_LOG = Tempfile.new("Chipmunk-") BUILD_LOG_PATH = BUILD_LOG.path def log(string) puts string open(BUILD_LOG_PATH, 'a'){|f| f.puts string} end def latest_sdk() sdks = `xcodebuild -showsdks`.split("\n") versions = sdks.map do|elt| # Match only lines with "iphoneos" in them. m = elt.match(/iphoneos(\d\.\d)/) (m ? m.captures[0] : "0.0") end return versions.max end # Or you can pick a specific version string (ex: "5.1") IOS_SDK_VERSION = latest_sdk() log("Building using iOS SDK #{IOS_SDK_VERSION}") VERBOSE = (not ARGV.include?("--quiet")) def system(command) log "> #{command}" result = Kernel.system(VERBOSE ? "#{command} | tee -a #{BUILD_LOG_PATH}; exit ${PIPESTATUS[0]}" : "#{command} >> #{BUILD_LOG_PATH}") unless $? == 0 log "===========================================" log "Command failed with status #{$?}: #{command}" log "Build errors encountered. Aborting build script" log "Check the build log for more information: #{BUILD_LOG_PATH}" raise end end OUTPUT_DIR_NAME = "Chipmunk-iPhone" system "rm -rf #{OUTPUT_DIR_NAME}" system "mkdir #{OUTPUT_DIR_NAME}" system "xcodebuild -project Chipmunk6.xcodeproj -sdk iphoneos#{IOS_SDK_VERSION} -configuration Release -target ChipmunkStatic-iPhone" system "xcodebuild -project Chipmunk6.xcodeproj -sdk iphonesimulator#{IOS_SDK_VERSION} -arch i386 -configuration Debug -target ChipmunkStatic-iPhone" system "lipo build/Debug-iphonesimulator/libChipmunk-iPhone.a build/Release-iphoneos/libChipmunk-iPhone.a -create -output #{OUTPUT_DIR_NAME}/libChipmunk-iPhone.a" system "rsync -r --exclude='.*' ../include/chipmunk/ #{OUTPUT_DIR_NAME}" system "open #{OUTPUT_DIR_NAME}" puts "Copy #{OUTPUT_DIR_NAME} into your project and enjoy." BUILD_LOG.delete Chipmunk-6.1.5/xcode/macstatic.command000755 000765 000000 00000002456 12151675775 020670 0ustar00slembckewheel000000 000000 #! /usr/bin/ruby Dir.chdir(File.dirname($0)) require 'Tempfile' BUILD_LOG = Tempfile.new("Chipmunk-") BUILD_LOG_PATH = BUILD_LOG.path def log(string) puts string open(BUILD_LOG_PATH, 'a'){|f| f.puts string} end VERBOSE = (not ARGV.include?("--quiet")) def system(command) log "> #{command}" result = Kernel.system(VERBOSE ? "#{command} | tee -a #{BUILD_LOG_PATH}; exit ${PIPESTATUS[0]}" : "#{command} >> #{BUILD_LOG_PATH}") unless $? == 0 log "===========================================" log "Command failed with status #{$?}: #{command}" log "Build errors encountered. Aborting build script" log "Check the build log for more information: #{BUILD_LOG_PATH}" raise end end OUTPUT_DIR_NAME = "Chipmunk-Mac" system "rm -rf #{OUTPUT_DIR_NAME}" system "mkdir #{OUTPUT_DIR_NAME}" system "xcodebuild -project Chipmunk6.xcodeproj -configuration Release -target ChipmunkStatic" system "xcodebuild -project Chipmunk6.xcodeproj -configuration Debug -target ChipmunkStatic" system "cp build/Debug/libChipmunk.a #{OUTPUT_DIR_NAME}/libChipmunk-Debug.a" system "cp build/Release/libChipmunk.a #{OUTPUT_DIR_NAME}/libChipmunk.a" system "rsync -r --exclude='.*' ../include/chipmunk/ #{OUTPUT_DIR_NAME}" system "open #{OUTPUT_DIR_NAME}" puts "Copy #{OUTPUT_DIR_NAME} into your project and enjoy." BUILD_LOG.delete Chipmunk-6.1.5/xcode/main-Info.plist000644 000765 000000 00000001337 12151675775 020244 0ustar00slembckewheel000000 000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier com.yourcompany.main CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion 1.0 NSMainNibFile MainMenu NSPrincipalClass NSApplication Chipmunk-6.1.5/xcode/Chipmunk6.xcodeproj/project.pbxproj000644 000765 000000 00000156122 12151675775 024271 0ustar00slembckewheel000000 000000 // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ D3102B171119FD3000E77771 /* Tank.c in Sources */ = {isa = PBXBuildFile; fileRef = D3102B161119FD3000E77771 /* Tank.c */; }; D31402950E9DD07E00EF79DB /* Springies.c in Sources */ = {isa = PBXBuildFile; fileRef = D31402940E9DD07E00EF79DB /* Springies.c */; }; D317246613280FC900752CBE /* cpSweep1D.c in Sources */ = {isa = PBXBuildFile; fileRef = D317246513280FC900752CBE /* cpSweep1D.c */; }; D317246713280FC900752CBE /* cpSweep1D.c in Sources */ = {isa = PBXBuildFile; fileRef = D317246513280FC900752CBE /* cpSweep1D.c */; }; D31847750FC458FD00E30B0D /* Query.c in Sources */ = {isa = PBXBuildFile; fileRef = D31847740FC458FD00E30B0D /* Query.c */; }; D3185D200EC5610A00E6BFCB /* TheoJansen.c in Sources */ = {isa = PBXBuildFile; fileRef = D3185D1F0EC5610A00E6BFCB /* TheoJansen.c */; }; D3238F8210C1B5ED00C4BDC2 /* Joints.c in Sources */ = {isa = PBXBuildFile; fileRef = D3238F8110C1B5ED00C4BDC2 /* Joints.c */; }; D34963C10B56CBA900CAD239 /* chipmunk.h in Headers */ = {isa = PBXBuildFile; fileRef = D3E5F0C40AA75CC3004E361B /* chipmunk.h */; }; D34963C20B56CBA900CAD239 /* cpVect.h in Headers */ = {isa = PBXBuildFile; fileRef = D3E5F0270AA32F16004E361B /* cpVect.h */; }; D34963C30B56CBA900CAD239 /* cpBB.h in Headers */ = {isa = PBXBuildFile; fileRef = D3E5F2D90AAA5622004E361B /* cpBB.h */; }; D34963C50B56CBA900CAD239 /* prime.h in Headers */ = {isa = PBXBuildFile; fileRef = D353B6480B059C5F0038D274 /* prime.h */; }; D34963C70B56CBA900CAD239 /* cpBody.h in Headers */ = {isa = PBXBuildFile; fileRef = D3E5F0DD0AAA2273004E361B /* cpBody.h */; }; D34963C90B56CBA900CAD239 /* cpArbiter.h in Headers */ = {isa = PBXBuildFile; fileRef = D3E5F0C10AA75CA9004E361B /* cpArbiter.h */; }; D34963CA0B56CBA900CAD239 /* cpPolyShape.h in Headers */ = {isa = PBXBuildFile; fileRef = D3BC99AC0AB381AF0025A2C0 /* cpPolyShape.h */; }; D34963CB0B56CBA900CAD239 /* cpShape.h in Headers */ = {isa = PBXBuildFile; fileRef = D37E22FC0AAA63B800BB4C50 /* cpShape.h */; }; D34963CD0B56CBA900CAD239 /* cpSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = D3E5F2CE0AAA5589004E361B /* cpSpace.h */; }; D34963CE0B56CBBF00CAD239 /* chipmunk.c in Sources */ = {isa = PBXBuildFile; fileRef = D3B718E00AB2BC8900B500C9 /* chipmunk.c */; }; D34963CF0B56CBBF00CAD239 /* cpVect.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F0260AA32F15004E361B /* cpVect.c */; }; D34963D00B56CBBF00CAD239 /* cpBB.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2DA0AAA5622004E361B /* cpBB.c */; }; D34963D10B56CBBF00CAD239 /* cpArray.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2DD0AAA562B004E361B /* cpArray.c */; }; D34963D20B56CBBF00CAD239 /* cpHashSet.c in Sources */ = {isa = PBXBuildFile; fileRef = D30CE25D0B52535500427129 /* cpHashSet.c */; }; D34963D30B56CBBF00CAD239 /* cpBody.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F0DE0AAA2273004E361B /* cpBody.c */; }; D34963D40B56CBBF00CAD239 /* cpSpaceHash.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2DF0AAA562B004E361B /* cpSpaceHash.c */; }; D34963D50B56CBBF00CAD239 /* cpArbiter.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F0C20AA75CA9004E361B /* cpArbiter.c */; }; D34963D60B56CBBF00CAD239 /* cpPolyShape.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BC99AB0AB381AF0025A2C0 /* cpPolyShape.c */; }; D34963D70B56CBBF00CAD239 /* cpShape.c in Sources */ = {isa = PBXBuildFile; fileRef = D37E22FD0AAA63B800BB4C50 /* cpShape.c */; }; D34963D80B56CBBF00CAD239 /* cpCollision.c in Sources */ = {isa = PBXBuildFile; fileRef = D37E231F0AAA728A00BB4C50 /* cpCollision.c */; }; D34963D90B56CBBF00CAD239 /* cpSpace.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2CF0AAA5589004E361B /* cpSpace.c */; }; D34E9E6712558100002C0FE5 /* cpSpaceQuery.c in Sources */ = {isa = PBXBuildFile; fileRef = D34E9E6412558081002C0FE5 /* cpSpaceQuery.c */; }; D34E9E681255810F002C0FE5 /* cpSpaceQuery.c in Sources */ = {isa = PBXBuildFile; fileRef = D34E9E6412558081002C0FE5 /* cpSpaceQuery.c */; }; D34E9E97125581DD002C0FE5 /* cpSpaceComponent.c in Sources */ = {isa = PBXBuildFile; fileRef = D34E9E96125581DD002C0FE5 /* cpSpaceComponent.c */; }; D34E9E98125581DD002C0FE5 /* cpSpaceComponent.c in Sources */ = {isa = PBXBuildFile; fileRef = D34E9E96125581DD002C0FE5 /* cpSpaceComponent.c */; }; D34E9EA312558A7C002C0FE5 /* cpSpaceStep.c in Sources */ = {isa = PBXBuildFile; fileRef = D34E9EA212558A7C002C0FE5 /* cpSpaceStep.c */; }; D34E9EA412558A7C002C0FE5 /* cpSpaceStep.c in Sources */ = {isa = PBXBuildFile; fileRef = D34E9EA212558A7C002C0FE5 /* cpSpaceStep.c */; }; D35420C00F4E1FD70017F4F7 /* chipmunk_unsafe.h in Headers */ = {isa = PBXBuildFile; fileRef = D35420BF0F4E1FD70017F4F7 /* chipmunk_unsafe.h */; }; D36B19510EA13B6D0028A362 /* cpDampedRotarySpring.c in Sources */ = {isa = PBXBuildFile; fileRef = D36B192D0EA1364E0028A362 /* cpDampedRotarySpring.c */; }; D36D87831012D63600DB5078 /* cpRatchetJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D36D87811012D63600DB5078 /* cpRatchetJoint.c */; }; D36D87841012D63600DB5078 /* cpRatchetJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = D36D87821012D63600DB5078 /* cpRatchetJoint.h */; }; D37282AD13C6432F00FFFA3F /* Crane.c in Sources */ = {isa = PBXBuildFile; fileRef = D37282AC13C6432F00FFFA3F /* Crane.c */; }; D37282D413C76C1B00FFFA3F /* Buoyancy.c in Sources */ = {isa = PBXBuildFile; fileRef = D37282D313C76C1B00FFFA3F /* Buoyancy.c */; }; D373FF1013D0D66E000EDB87 /* ContactGraph.c in Sources */ = {isa = PBXBuildFile; fileRef = D373FF0F13D0D66E000EDB87 /* ContactGraph.c */; }; D37697200B50C53900BB33CC /* LogoSmash.c in Sources */ = {isa = PBXBuildFile; fileRef = D3CCDF460AE35D920080442F /* LogoSmash.c */; }; D37BB76E0EAADA6300C70958 /* cpRotaryLimitJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D37BB76C0EAADA6300C70958 /* cpRotaryLimitJoint.c */; }; D37BB76F0EAADA6300C70958 /* cpRotaryLimitJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = D37BB76D0EAADA6300C70958 /* cpRotaryLimitJoint.h */; }; D37BB8B30EAB01E400C70958 /* cpGearJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D37BB8B10EAB01E400C70958 /* cpGearJoint.c */; }; D37BB8B40EAB01E400C70958 /* cpGearJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = D37BB8B20EAB01E400C70958 /* cpGearJoint.h */; }; D37BB8F10EAB06B600C70958 /* cpSimpleMotor.h in Headers */ = {isa = PBXBuildFile; fileRef = D37BB8EF0EAB06B600C70958 /* cpSimpleMotor.h */; }; D37BB8F20EAB06B600C70958 /* cpSimpleMotor.c in Sources */ = {isa = PBXBuildFile; fileRef = D37BB8F00EAB06B600C70958 /* cpSimpleMotor.c */; }; D3800E120E9815FC00A3D7FA /* cpConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = D3800E0F0E9815FC00A3D7FA /* cpConstraint.h */; }; D3800E130E9815FC00A3D7FA /* cpConstraint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800E100E9815FC00A3D7FA /* cpConstraint.c */; }; D3800E1E0E98176F00A3D7FA /* cpPinJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800E1B0E98176F00A3D7FA /* cpPinJoint.c */; }; D3800E1F0E98176F00A3D7FA /* cpPinJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = D3800E1C0E98176F00A3D7FA /* cpPinJoint.h */; }; D38011620E984FA400A3D7FA /* cpDampedSpring.c in Sources */ = {isa = PBXBuildFile; fileRef = D380115F0E984FA400A3D7FA /* cpDampedSpring.c */; }; D38011630E984FA400A3D7FA /* cpDampedSpring.h in Headers */ = {isa = PBXBuildFile; fileRef = D38011600E984FA400A3D7FA /* cpDampedSpring.h */; }; D38687D30BAFC695008B7008 /* libChipmunk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D34963BB0B56CAA300CAD239 /* libChipmunk.a */; }; D38996A6148B1E72006CFE0B /* Slice.c in Sources */ = {isa = PBXBuildFile; fileRef = D38996A5148B1E72006CFE0B /* Slice.c */; }; D38C029916840ED3009F612B /* Shatter.c in Sources */ = {isa = PBXBuildFile; fileRef = D38C029816840ED2009F612B /* Shatter.c */; }; D393275C0EA02C710026F6A2 /* Pump.c in Sources */ = {isa = PBXBuildFile; fileRef = D393275B0EA02C710026F6A2 /* Pump.c */; }; D3AA477512AF0F8900E27AAB /* cpBBTree.c in Sources */ = {isa = PBXBuildFile; fileRef = D3AA477312AF0F8900E27AAB /* cpBBTree.c */; }; D3AA477612AF0F8900E27AAB /* cpSpatialIndex.c in Sources */ = {isa = PBXBuildFile; fileRef = D3AA477412AF0F8900E27AAB /* cpSpatialIndex.c */; }; D3AA477712AF0F8900E27AAB /* cpBBTree.c in Sources */ = {isa = PBXBuildFile; fileRef = D3AA477312AF0F8900E27AAB /* cpBBTree.c */; }; D3AA477812AF0F8900E27AAB /* cpSpatialIndex.c in Sources */ = {isa = PBXBuildFile; fileRef = D3AA477412AF0F8900E27AAB /* cpSpatialIndex.c */; }; D3AA477C12AF0F9B00E27AAB /* cpSpatialIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = D3AA477A12AF0F9B00E27AAB /* cpSpatialIndex.h */; }; D3AA477E12AF0F9B00E27AAB /* cpSpatialIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = D3AA477A12AF0F9B00E27AAB /* cpSpatialIndex.h */; }; D3BACF8310B5DF8900376394 /* OneWay.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BACF8210B5DF8900376394 /* OneWay.c */; }; D3BAD65810B8B52900376394 /* Player.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BAD0C710B61AAD00376394 /* Player.c */; }; D3BAF9C50E9C4F250039DD5C /* PyramidStack.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BAF9C40E9C4F250039DD5C /* PyramidStack.c */; }; D3BAFA040E9C52810039DD5C /* Plink.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BAFA030E9C52810039DD5C /* Plink.c */; }; D3BAFA360E9C53E50039DD5C /* Tumble.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BAFA350E9C53E50039DD5C /* Tumble.c */; }; D3BAFA510E9C549C0039DD5C /* PyramidTopple.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BAFA500E9C549C0039DD5C /* PyramidTopple.c */; }; D3BAFB8B0E9C7C150039DD5C /* Planet.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BAFB8A0E9C7C150039DD5C /* Planet.c */; }; D3BC99C10AB381EE0025A2C0 /* ChipmunkDemo.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BC99C00AB381EE0025A2C0 /* ChipmunkDemo.c */; }; D3C378F511063C57003EF1D9 /* cpConstraint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800E100E9815FC00A3D7FA /* cpConstraint.c */; }; D3C378F611063C57003EF1D9 /* cpPinJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800E1B0E98176F00A3D7FA /* cpPinJoint.c */; }; D3C378F711063C57003EF1D9 /* cpSlideJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800EA60E98260200A3D7FA /* cpSlideJoint.c */; }; D3C378F811063C57003EF1D9 /* cpPivotJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800EA40E98260200A3D7FA /* cpPivotJoint.c */; }; D3C378F911063C57003EF1D9 /* cpGrooveJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800EA00E98260200A3D7FA /* cpGrooveJoint.c */; }; D3C378FA11063C57003EF1D9 /* cpDampedSpring.c in Sources */ = {isa = PBXBuildFile; fileRef = D380115F0E984FA400A3D7FA /* cpDampedSpring.c */; }; D3C378FB11063C57003EF1D9 /* chipmunk.c in Sources */ = {isa = PBXBuildFile; fileRef = D3B718E00AB2BC8900B500C9 /* chipmunk.c */; }; D3C378FC11063C57003EF1D9 /* cpVect.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F0260AA32F15004E361B /* cpVect.c */; }; D3C378FD11063C57003EF1D9 /* cpBB.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2DA0AAA5622004E361B /* cpBB.c */; }; D3C378FE11063C57003EF1D9 /* cpArray.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2DD0AAA562B004E361B /* cpArray.c */; }; D3C378FF11063C57003EF1D9 /* cpHashSet.c in Sources */ = {isa = PBXBuildFile; fileRef = D30CE25D0B52535500427129 /* cpHashSet.c */; }; D3C3790011063C57003EF1D9 /* cpBody.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F0DE0AAA2273004E361B /* cpBody.c */; }; D3C3790111063C57003EF1D9 /* cpSpaceHash.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2DF0AAA562B004E361B /* cpSpaceHash.c */; }; D3C3790211063C57003EF1D9 /* cpArbiter.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F0C20AA75CA9004E361B /* cpArbiter.c */; }; D3C3790311063C57003EF1D9 /* cpPolyShape.c in Sources */ = {isa = PBXBuildFile; fileRef = D3BC99AB0AB381AF0025A2C0 /* cpPolyShape.c */; }; D3C3790411063C57003EF1D9 /* cpShape.c in Sources */ = {isa = PBXBuildFile; fileRef = D37E22FD0AAA63B800BB4C50 /* cpShape.c */; }; D3C3790511063C57003EF1D9 /* cpCollision.c in Sources */ = {isa = PBXBuildFile; fileRef = D37E231F0AAA728A00BB4C50 /* cpCollision.c */; }; D3C3790611063C57003EF1D9 /* cpSpace.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E5F2CF0AAA5589004E361B /* cpSpace.c */; }; D3C3790711063C57003EF1D9 /* cpDampedRotarySpring.c in Sources */ = {isa = PBXBuildFile; fileRef = D36B192D0EA1364E0028A362 /* cpDampedRotarySpring.c */; }; D3C3790811063C57003EF1D9 /* cpRotaryLimitJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D37BB76C0EAADA6300C70958 /* cpRotaryLimitJoint.c */; }; D3C3790911063C57003EF1D9 /* cpGearJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D37BB8B10EAB01E400C70958 /* cpGearJoint.c */; }; D3C3790A11063C57003EF1D9 /* cpSimpleMotor.c in Sources */ = {isa = PBXBuildFile; fileRef = D37BB8F00EAB06B600C70958 /* cpSimpleMotor.c */; }; D3C3790B11063C57003EF1D9 /* cpRatchetJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D36D87811012D63600DB5078 /* cpRatchetJoint.c */; }; D3DFB55D1613765700162F19 /* Sticky.c in Sources */ = {isa = PBXBuildFile; fileRef = D3DFB55C1613765700162F19 /* Sticky.c */; }; D3E4867613175AE000A00840 /* Bench.c in Sources */ = {isa = PBXBuildFile; fileRef = D3E4867513175AE000A00840 /* Bench.c */; }; D3E4A9C80E99683200EE08BA /* cpSlideJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800EA60E98260200A3D7FA /* cpSlideJoint.c */; }; D3E4A9CA0E99683200EE08BA /* cpPivotJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800EA40E98260200A3D7FA /* cpPivotJoint.c */; }; D3E4A9CC0E99683200EE08BA /* cpGrooveJoint.c in Sources */ = {isa = PBXBuildFile; fileRef = D3800EA00E98260200A3D7FA /* cpGrooveJoint.c */; }; D3E5F0550AA3303F004E361B /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3E5F0530AA3303F004E361B /* GLUT.framework */; }; D3E5F0560AA3303F004E361B /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3E5F0540AA3303F004E361B /* OpenGL.framework */; }; D3F2EE2F14F898E9005FD439 /* Unicycle.c in Sources */ = {isa = PBXBuildFile; fileRef = D3F2EE2E14F898E9005FD439 /* Unicycle.c */; }; D3F52BD313C509DC00EB67D9 /* Chains.c in Sources */ = {isa = PBXBuildFile; fileRef = D3F52BD213C509DC00EB67D9 /* Chains.c */; }; D3F6EEDF156D581300A158A8 /* Convex.c in Sources */ = {isa = PBXBuildFile; fileRef = D3F6EEDE156D581300A158A8 /* Convex.c */; }; D3FBA1A70E9B1E0400950BCC /* ChipmunkDebugDraw.c in Sources */ = {isa = PBXBuildFile; fileRef = D3FBA1A60E9B1E0400950BCC /* ChipmunkDebugDraw.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ D38687D10BAFC688008B7008 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D3E5F0190AA32EAC004E361B /* Project object */; proxyType = 1; remoteGlobalIDString = D34963BA0B56CAA300CAD239; remoteInfo = ChipmunkStatic; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ D30CE25D0B52535500427129 /* cpHashSet.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cpHashSet.c; sourceTree = ""; }; D3102B161119FD3000E77771 /* Tank.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Tank.c; sourceTree = ""; }; D31402940E9DD07E00EF79DB /* Springies.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Springies.c; sourceTree = ""; }; D317246513280FC900752CBE /* cpSweep1D.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpSweep1D.c; sourceTree = ""; }; D31847740FC458FD00E30B0D /* Query.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Query.c; sourceTree = ""; }; D3185D1F0EC5610A00E6BFCB /* TheoJansen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = TheoJansen.c; sourceTree = ""; }; D3238F8110C1B5ED00C4BDC2 /* Joints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Joints.c; sourceTree = ""; }; D34963BB0B56CAA300CAD239 /* libChipmunk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libChipmunk.a; sourceTree = BUILT_PRODUCTS_DIR; }; D34E9E6412558081002C0FE5 /* cpSpaceQuery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpSpaceQuery.c; path = ../src/cpSpaceQuery.c; sourceTree = ""; }; D34E9E96125581DD002C0FE5 /* cpSpaceComponent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpSpaceComponent.c; path = ../src/cpSpaceComponent.c; sourceTree = ""; }; D34E9EA212558A7C002C0FE5 /* cpSpaceStep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpSpaceStep.c; path = ../src/cpSpaceStep.c; sourceTree = ""; }; D353B6480B059C5F0038D274 /* prime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = prime.h; sourceTree = ""; }; D35420BF0F4E1FD70017F4F7 /* chipmunk_unsafe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = chipmunk_unsafe.h; path = ../include/chipmunk/chipmunk_unsafe.h; sourceTree = SOURCE_ROOT; }; D36B192D0EA1364E0028A362 /* cpDampedRotarySpring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpDampedRotarySpring.c; sourceTree = ""; }; D36B192E0EA1364E0028A362 /* cpDampedRotarySpring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpDampedRotarySpring.h; path = ../../include/chipmunk/constraints/cpDampedRotarySpring.h; sourceTree = ""; }; D36C44DD10F53DEB003D48B5 /* chipmunk_ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = chipmunk_ffi.h; path = ../include/chipmunk/chipmunk_ffi.h; sourceTree = SOURCE_ROOT; }; D36D87811012D63600DB5078 /* cpRatchetJoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpRatchetJoint.c; sourceTree = ""; }; D36D87821012D63600DB5078 /* cpRatchetJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpRatchetJoint.h; path = ../../include/chipmunk/constraints/cpRatchetJoint.h; sourceTree = ""; }; D37282AC13C6432F00FFFA3F /* Crane.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Crane.c; sourceTree = ""; }; D37282D313C76C1B00FFFA3F /* Buoyancy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Buoyancy.c; sourceTree = ""; }; D373FF0F13D0D66E000EDB87 /* ContactGraph.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ContactGraph.c; sourceTree = ""; }; D37BB76C0EAADA6300C70958 /* cpRotaryLimitJoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpRotaryLimitJoint.c; sourceTree = ""; }; D37BB76D0EAADA6300C70958 /* cpRotaryLimitJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpRotaryLimitJoint.h; path = ../../include/chipmunk/constraints/cpRotaryLimitJoint.h; sourceTree = ""; }; D37BB8B10EAB01E400C70958 /* cpGearJoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpGearJoint.c; sourceTree = ""; }; D37BB8B20EAB01E400C70958 /* cpGearJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpGearJoint.h; path = ../../include/chipmunk/constraints/cpGearJoint.h; sourceTree = ""; }; D37BB8EF0EAB06B600C70958 /* cpSimpleMotor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpSimpleMotor.h; path = ../../include/chipmunk/constraints/cpSimpleMotor.h; sourceTree = ""; }; D37BB8F00EAB06B600C70958 /* cpSimpleMotor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpSimpleMotor.c; sourceTree = ""; }; D37E22FC0AAA63B800BB4C50 /* cpShape.h */ = {isa = PBXFileReference; fileEncoding = 4; languageSpecificationIdentifier = c; lastKnownFileType = sourcecode.c.h; name = cpShape.h; path = ../include/chipmunk/cpShape.h; sourceTree = ""; }; D37E22FD0AAA63B800BB4C50 /* cpShape.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpShape.c; sourceTree = ""; }; D37E231F0AAA728A00BB4C50 /* cpCollision.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpCollision.c; sourceTree = ""; }; D3800E0F0E9815FC00A3D7FA /* cpConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpConstraint.h; path = ../../include/chipmunk/constraints/cpConstraint.h; sourceTree = ""; }; D3800E100E9815FC00A3D7FA /* cpConstraint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpConstraint.c; sourceTree = ""; }; D3800E1B0E98176F00A3D7FA /* cpPinJoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpPinJoint.c; sourceTree = ""; }; D3800E1C0E98176F00A3D7FA /* cpPinJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpPinJoint.h; path = ../../include/chipmunk/constraints/cpPinJoint.h; sourceTree = ""; }; D3800E3A0E9820B900A3D7FA /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = ../../include/chipmunk/constraints/util.h; sourceTree = ""; }; D3800EA00E98260200A3D7FA /* cpGrooveJoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpGrooveJoint.c; sourceTree = ""; }; D3800EA10E98260200A3D7FA /* cpGrooveJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpGrooveJoint.h; path = ../../include/chipmunk/constraints/cpGrooveJoint.h; sourceTree = ""; }; D3800EA40E98260200A3D7FA /* cpPivotJoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpPivotJoint.c; sourceTree = ""; }; D3800EA50E98260200A3D7FA /* cpPivotJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpPivotJoint.h; path = ../../include/chipmunk/constraints/cpPivotJoint.h; sourceTree = ""; }; D3800EA60E98260200A3D7FA /* cpSlideJoint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpSlideJoint.c; sourceTree = ""; }; D3800EA70E98260200A3D7FA /* cpSlideJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpSlideJoint.h; path = ../../include/chipmunk/constraints/cpSlideJoint.h; sourceTree = ""; }; D380115F0E984FA400A3D7FA /* cpDampedSpring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpDampedSpring.c; sourceTree = ""; }; D38011600E984FA400A3D7FA /* cpDampedSpring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpDampedSpring.h; path = ../../include/chipmunk/constraints/cpDampedSpring.h; sourceTree = ""; }; D38996A5148B1E72006CFE0B /* Slice.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Slice.c; sourceTree = ""; }; D38BB1D1149933F20000EC41 /* chipmunk-docs.textile */ = {isa = PBXFileReference; lastKnownFileType = text; name = "chipmunk-docs.textile"; path = "../doc-src/chipmunk-docs.textile"; sourceTree = ""; }; D38C029816840ED2009F612B /* Shatter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Shatter.c; sourceTree = ""; }; D390FDAD146EF0F8005D1E06 /* VERSION.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = VERSION.txt; path = ../VERSION.txt; sourceTree = ""; }; D393275B0EA02C710026F6A2 /* Pump.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Pump.c; sourceTree = ""; }; D39F478A0FD4AB4E00B244CA /* chipmunk_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = chipmunk_types.h; path = ../include/chipmunk/chipmunk_types.h; sourceTree = SOURCE_ROOT; }; D3AA477312AF0F8900E27AAB /* cpBBTree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpBBTree.c; sourceTree = ""; }; D3AA477412AF0F8900E27AAB /* cpSpatialIndex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpSpatialIndex.c; sourceTree = ""; }; D3AA477A12AF0F9B00E27AAB /* cpSpatialIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpSpatialIndex.h; path = ../include/chipmunk/cpSpatialIndex.h; sourceTree = SOURCE_ROOT; }; D3B718E00AB2BC8900B500C9 /* chipmunk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = chipmunk.c; path = ../src/chipmunk.c; sourceTree = ""; }; D3BACF8210B5DF8900376394 /* OneWay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = OneWay.c; sourceTree = ""; }; D3BAD0C710B61AAD00376394 /* Player.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Player.c; sourceTree = ""; }; D3BAF9C40E9C4F250039DD5C /* PyramidStack.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PyramidStack.c; sourceTree = ""; }; D3BAFA030E9C52810039DD5C /* Plink.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Plink.c; sourceTree = ""; }; D3BAFA350E9C53E50039DD5C /* Tumble.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Tumble.c; sourceTree = ""; }; D3BAFA500E9C549C0039DD5C /* PyramidTopple.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = PyramidTopple.c; sourceTree = ""; }; D3BAFB8A0E9C7C150039DD5C /* Planet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Planet.c; sourceTree = ""; }; D3BC99AB0AB381AF0025A2C0 /* cpPolyShape.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cpPolyShape.c; sourceTree = ""; }; D3BC99AC0AB381AF0025A2C0 /* cpPolyShape.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cpPolyShape.h; path = ../include/chipmunk/cpPolyShape.h; sourceTree = ""; }; D3BC99C00AB381EE0025A2C0 /* ChipmunkDemo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ChipmunkDemo.c; sourceTree = ""; }; D3C2B4581282178B0080A718 /* chipmunk_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = chipmunk_private.h; path = ../include/chipmunk/chipmunk_private.h; sourceTree = ""; }; D3C3787A11063B1B003EF1D9 /* libChipmunk-iPhone.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libChipmunk-iPhone.a"; sourceTree = BUILT_PRODUCTS_DIR; }; D3C517841279B38300C2AFEB /* TODO.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TODO.txt; path = ../TODO.txt; sourceTree = SOURCE_ROOT; }; D3CCDF460AE35D920080442F /* LogoSmash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LogoSmash.c; sourceTree = ""; }; D3CCEAE60E9B346100161D40 /* ChipmunkDemo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChipmunkDemo.h; sourceTree = ""; }; D3DFB55C1613765700162F19 /* Sticky.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Sticky.c; sourceTree = ""; }; D3E4867513175AE000A00840 /* Bench.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Bench.c; sourceTree = ""; }; D3E5F0260AA32F15004E361B /* cpVect.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cpVect.c; sourceTree = ""; }; D3E5F0270AA32F16004E361B /* cpVect.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cpVect.h; path = ../include/chipmunk/cpVect.h; sourceTree = ""; }; D3E5F0490AA32FDE004E361B /* ChipmunkDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ChipmunkDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; D3E5F04C0AA32FDE004E361B /* main-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "main-Info.plist"; sourceTree = ""; }; D3E5F0530AA3303F004E361B /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = /System/Library/Frameworks/GLUT.framework; sourceTree = ""; }; D3E5F0540AA3303F004E361B /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; D3E5F0C10AA75CA9004E361B /* cpArbiter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpArbiter.h; path = ../include/chipmunk/cpArbiter.h; sourceTree = ""; }; D3E5F0C20AA75CA9004E361B /* cpArbiter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpArbiter.c; sourceTree = ""; }; D3E5F0C40AA75CC3004E361B /* chipmunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = chipmunk.h; path = ../include/chipmunk/chipmunk.h; sourceTree = ""; }; D3E5F0DD0AAA2273004E361B /* cpBody.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpBody.h; path = ../include/chipmunk/cpBody.h; sourceTree = ""; }; D3E5F0DE0AAA2273004E361B /* cpBody.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpBody.c; path = ../src/cpBody.c; sourceTree = ""; }; D3E5F2CE0AAA5589004E361B /* cpSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpSpace.h; path = ../include/chipmunk/cpSpace.h; sourceTree = ""; }; D3E5F2CF0AAA5589004E361B /* cpSpace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpSpace.c; path = ../src/cpSpace.c; sourceTree = ""; }; D3E5F2D90AAA5622004E361B /* cpBB.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = cpBB.h; path = ../include/chipmunk/cpBB.h; sourceTree = ""; }; D3E5F2DA0AAA5622004E361B /* cpBB.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cpBB.c; sourceTree = ""; }; D3E5F2DD0AAA562B004E361B /* cpArray.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cpArray.c; sourceTree = ""; }; D3E5F2DF0AAA562B004E361B /* cpSpaceHash.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = cpSpaceHash.c; sourceTree = ""; }; D3F2EE2E14F898E9005FD439 /* Unicycle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Unicycle.c; sourceTree = ""; }; D3F52BD213C509DC00EB67D9 /* Chains.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Chains.c; sourceTree = ""; }; D3F6EEDE156D581300A158A8 /* Convex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Convex.c; sourceTree = ""; }; D3FBA1A60E9B1E0400950BCC /* ChipmunkDebugDraw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ChipmunkDebugDraw.c; sourceTree = ""; }; D3FBA1B80E9B1F6300950BCC /* ChipmunkDebugDraw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChipmunkDebugDraw.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ D34963B90B56CAA300CAD239 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D3C3787811063B1B003EF1D9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D3E5F0470AA32FDE004E361B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D38687D30BAFC695008B7008 /* libChipmunk.a in Frameworks */, D3E5F0550AA3303F004E361B /* GLUT.framework in Frameworks */, D3E5F0560AA3303F004E361B /* OpenGL.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ D34E9E5A12557FBF002C0FE5 /* Space */ = { isa = PBXGroup; children = ( D3E5F2CE0AAA5589004E361B /* cpSpace.h */, D3E5F2CF0AAA5589004E361B /* cpSpace.c */, D34E9E6412558081002C0FE5 /* cpSpaceQuery.c */, D34E9E96125581DD002C0FE5 /* cpSpaceComponent.c */, D34E9EA212558A7C002C0FE5 /* cpSpaceStep.c */, ); name = Space; sourceTree = ""; }; D37E24570AAAA48800BB4C50 /* Collision */ = { isa = PBXGroup; children = ( D3AA477A12AF0F9B00E27AAB /* cpSpatialIndex.h */, D3AA477412AF0F8900E27AAB /* cpSpatialIndex.c */, D3E5F2DF0AAA562B004E361B /* cpSpaceHash.c */, D3AA477312AF0F8900E27AAB /* cpBBTree.c */, D317246513280FC900752CBE /* cpSweep1D.c */, D3E5F0C10AA75CA9004E361B /* cpArbiter.h */, D3E5F0C20AA75CA9004E361B /* cpArbiter.c */, D37E22FC0AAA63B800BB4C50 /* cpShape.h */, D37E22FD0AAA63B800BB4C50 /* cpShape.c */, D3BC99AC0AB381AF0025A2C0 /* cpPolyShape.h */, D3BC99AB0AB381AF0025A2C0 /* cpPolyShape.c */, D37E231F0AAA728A00BB4C50 /* cpCollision.c */, ); name = Collision; path = ../src; sourceTree = ""; }; D3800E0E0E9815FC00A3D7FA /* constraints */ = { isa = PBXGroup; children = ( D3800E3A0E9820B900A3D7FA /* util.h */, D3800E0F0E9815FC00A3D7FA /* cpConstraint.h */, D3800E100E9815FC00A3D7FA /* cpConstraint.c */, D3800E1C0E98176F00A3D7FA /* cpPinJoint.h */, D3800E1B0E98176F00A3D7FA /* cpPinJoint.c */, D3800EA70E98260200A3D7FA /* cpSlideJoint.h */, D3800EA60E98260200A3D7FA /* cpSlideJoint.c */, D3800EA50E98260200A3D7FA /* cpPivotJoint.h */, D3800EA40E98260200A3D7FA /* cpPivotJoint.c */, D3800EA10E98260200A3D7FA /* cpGrooveJoint.h */, D3800EA00E98260200A3D7FA /* cpGrooveJoint.c */, D38011600E984FA400A3D7FA /* cpDampedSpring.h */, D380115F0E984FA400A3D7FA /* cpDampedSpring.c */, D36B192E0EA1364E0028A362 /* cpDampedRotarySpring.h */, D36B192D0EA1364E0028A362 /* cpDampedRotarySpring.c */, D37BB76D0EAADA6300C70958 /* cpRotaryLimitJoint.h */, D37BB76C0EAADA6300C70958 /* cpRotaryLimitJoint.c */, D36D87821012D63600DB5078 /* cpRatchetJoint.h */, D36D87811012D63600DB5078 /* cpRatchetJoint.c */, D37BB8B20EAB01E400C70958 /* cpGearJoint.h */, D37BB8B10EAB01E400C70958 /* cpGearJoint.c */, D37BB8EF0EAB06B600C70958 /* cpSimpleMotor.h */, D37BB8F00EAB06B600C70958 /* cpSimpleMotor.c */, ); name = constraints; path = ../src/constraints; sourceTree = SOURCE_ROOT; }; D3CCDF5B0AE35DA00080442F /* Demo */ = { isa = PBXGroup; children = ( D3CCEAE60E9B346100161D40 /* ChipmunkDemo.h */, D3BC99C00AB381EE0025A2C0 /* ChipmunkDemo.c */, D3FBA1B80E9B1F6300950BCC /* ChipmunkDebugDraw.h */, D3FBA1A60E9B1E0400950BCC /* ChipmunkDebugDraw.c */, D3CCDF460AE35D920080442F /* LogoSmash.c */, D3BAF9C40E9C4F250039DD5C /* PyramidStack.c */, D3BAFA030E9C52810039DD5C /* Plink.c */, D3BAFA350E9C53E50039DD5C /* Tumble.c */, D3BAFA500E9C549C0039DD5C /* PyramidTopple.c */, D3BAFB8A0E9C7C150039DD5C /* Planet.c */, D31402940E9DD07E00EF79DB /* Springies.c */, D393275B0EA02C710026F6A2 /* Pump.c */, D3185D1F0EC5610A00E6BFCB /* TheoJansen.c */, D31847740FC458FD00E30B0D /* Query.c */, D3BACF8210B5DF8900376394 /* OneWay.c */, D3BAD0C710B61AAD00376394 /* Player.c */, D3238F8110C1B5ED00C4BDC2 /* Joints.c */, D3102B161119FD3000E77771 /* Tank.c */, D3F52BD213C509DC00EB67D9 /* Chains.c */, D37282AC13C6432F00FFFA3F /* Crane.c */, D3F2EE2E14F898E9005FD439 /* Unicycle.c */, D37282D313C76C1B00FFFA3F /* Buoyancy.c */, D373FF0F13D0D66E000EDB87 /* ContactGraph.c */, D38996A5148B1E72006CFE0B /* Slice.c */, D38C029816840ED2009F612B /* Shatter.c */, D3F6EEDE156D581300A158A8 /* Convex.c */, D3DFB55C1613765700162F19 /* Sticky.c */, D3E4867513175AE000A00840 /* Bench.c */, ); name = Demo; path = ../Demo; sourceTree = ""; }; D3E5F0170AA32EAC004E361B = { isa = PBXGroup; children = ( D3C517841279B38300C2AFEB /* TODO.txt */, D390FDAD146EF0F8005D1E06 /* VERSION.txt */, D38BB1D1149933F20000EC41 /* chipmunk-docs.textile */, D3CCDF5B0AE35DA00080442F /* Demo */, D3E5F0C40AA75CC3004E361B /* chipmunk.h */, D3C2B4581282178B0080A718 /* chipmunk_private.h */, D39F478A0FD4AB4E00B244CA /* chipmunk_types.h */, D35420BF0F4E1FD70017F4F7 /* chipmunk_unsafe.h */, D36C44DD10F53DEB003D48B5 /* chipmunk_ffi.h */, D3B718E00AB2BC8900B500C9 /* chipmunk.c */, D3E5F2F30AAA575E004E361B /* Basics */, D3E5F0DD0AAA2273004E361B /* cpBody.h */, D3E5F0DE0AAA2273004E361B /* cpBody.c */, D37E24570AAAA48800BB4C50 /* Collision */, D3800E0E0E9815FC00A3D7FA /* constraints */, D34E9E5A12557FBF002C0FE5 /* Space */, D3E5F0520AA32FF5004E361B /* frameworks */, D3E5F04A0AA32FDE004E361B /* Products */, D3E5F04C0AA32FDE004E361B /* main-Info.plist */, ); sourceTree = ""; }; D3E5F04A0AA32FDE004E361B /* Products */ = { isa = PBXGroup; children = ( D3E5F0490AA32FDE004E361B /* ChipmunkDemo.app */, D34963BB0B56CAA300CAD239 /* libChipmunk.a */, D3C3787A11063B1B003EF1D9 /* libChipmunk-iPhone.a */, ); name = Products; sourceTree = ""; }; D3E5F0520AA32FF5004E361B /* frameworks */ = { isa = PBXGroup; children = ( D3E5F0530AA3303F004E361B /* GLUT.framework */, D3E5F0540AA3303F004E361B /* OpenGL.framework */, ); name = frameworks; sourceTree = ""; }; D3E5F2F30AAA575E004E361B /* Basics */ = { isa = PBXGroup; children = ( D353B6480B059C5F0038D274 /* prime.h */, D3E5F0270AA32F16004E361B /* cpVect.h */, D3E5F0260AA32F15004E361B /* cpVect.c */, D3E5F2D90AAA5622004E361B /* cpBB.h */, D3E5F2DA0AAA5622004E361B /* cpBB.c */, D3E5F2DD0AAA562B004E361B /* cpArray.c */, D30CE25D0B52535500427129 /* cpHashSet.c */, ); name = Basics; path = ../src; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ D34963B70B56CAA300CAD239 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D34963C10B56CBA900CAD239 /* chipmunk.h in Headers */, D34963C20B56CBA900CAD239 /* cpVect.h in Headers */, D34963C30B56CBA900CAD239 /* cpBB.h in Headers */, D34963C50B56CBA900CAD239 /* prime.h in Headers */, D34963C70B56CBA900CAD239 /* cpBody.h in Headers */, D34963C90B56CBA900CAD239 /* cpArbiter.h in Headers */, D34963CA0B56CBA900CAD239 /* cpPolyShape.h in Headers */, D34963CB0B56CBA900CAD239 /* cpShape.h in Headers */, D34963CD0B56CBA900CAD239 /* cpSpace.h in Headers */, D3800E120E9815FC00A3D7FA /* cpConstraint.h in Headers */, D3800E1F0E98176F00A3D7FA /* cpPinJoint.h in Headers */, D38011630E984FA400A3D7FA /* cpDampedSpring.h in Headers */, D37BB76F0EAADA6300C70958 /* cpRotaryLimitJoint.h in Headers */, D37BB8B40EAB01E400C70958 /* cpGearJoint.h in Headers */, D37BB8F10EAB06B600C70958 /* cpSimpleMotor.h in Headers */, D35420C00F4E1FD70017F4F7 /* chipmunk_unsafe.h in Headers */, D36D87841012D63600DB5078 /* cpRatchetJoint.h in Headers */, D3AA477C12AF0F9B00E27AAB /* cpSpatialIndex.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D3C3787611063B1B003EF1D9 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D3AA477E12AF0F9B00E27AAB /* cpSpatialIndex.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ D34963BA0B56CAA300CAD239 /* ChipmunkStatic */ = { isa = PBXNativeTarget; buildConfigurationList = D34963BE0B56CACA00CAD239 /* Build configuration list for PBXNativeTarget "ChipmunkStatic" */; buildPhases = ( D34963B70B56CAA300CAD239 /* Headers */, D34963B80B56CAA300CAD239 /* Sources */, D34963B90B56CAA300CAD239 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = ChipmunkStatic; productName = Chipmunk; productReference = D34963BB0B56CAA300CAD239 /* libChipmunk.a */; productType = "com.apple.product-type.library.static"; }; D3C3787911063B1B003EF1D9 /* ChipmunkStatic-iPhone */ = { isa = PBXNativeTarget; buildConfigurationList = D3C3787E11063BB5003EF1D9 /* Build configuration list for PBXNativeTarget "ChipmunkStatic-iPhone" */; buildPhases = ( D3C3787611063B1B003EF1D9 /* Headers */, D3C3787711063B1B003EF1D9 /* Sources */, D3C3787811063B1B003EF1D9 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = "ChipmunkStatic-iPhone"; productName = "ChipmunkStatic (iPhone)"; productReference = D3C3787A11063B1B003EF1D9 /* libChipmunk-iPhone.a */; productType = "com.apple.product-type.library.static"; }; D3E5F0480AA32FDE004E361B /* ChipmunkDemo */ = { isa = PBXNativeTarget; buildConfigurationList = D3E5F04D0AA32FDF004E361B /* Build configuration list for PBXNativeTarget "ChipmunkDemo" */; buildPhases = ( D3E5F0450AA32FDE004E361B /* Resources */, D3E5F0460AA32FDE004E361B /* Sources */, D3E5F0470AA32FDE004E361B /* Frameworks */, ); buildRules = ( ); dependencies = ( D38687D20BAFC688008B7008 /* PBXTargetDependency */, ); name = ChipmunkDemo; productName = main; productReference = D3E5F0490AA32FDE004E361B /* ChipmunkDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D3E5F0190AA32EAC004E361B /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0450; }; buildConfigurationList = D3E5F01A0AA32EAC004E361B /* Build configuration list for PBXProject "Chipmunk6" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( English, Japanese, French, German, ); mainGroup = D3E5F0170AA32EAC004E361B; productRefGroup = D3E5F04A0AA32FDE004E361B /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D3E5F0480AA32FDE004E361B /* ChipmunkDemo */, D34963BA0B56CAA300CAD239 /* ChipmunkStatic */, D3C3787911063B1B003EF1D9 /* ChipmunkStatic-iPhone */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ D3E5F0450AA32FDE004E361B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ D34963B80B56CAA300CAD239 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D34E9E6712558100002C0FE5 /* cpSpaceQuery.c in Sources */, D3800E130E9815FC00A3D7FA /* cpConstraint.c in Sources */, D3800E1E0E98176F00A3D7FA /* cpPinJoint.c in Sources */, D3E4A9C80E99683200EE08BA /* cpSlideJoint.c in Sources */, D3E4A9CA0E99683200EE08BA /* cpPivotJoint.c in Sources */, D3E4A9CC0E99683200EE08BA /* cpGrooveJoint.c in Sources */, D38011620E984FA400A3D7FA /* cpDampedSpring.c in Sources */, D34963CE0B56CBBF00CAD239 /* chipmunk.c in Sources */, D34963CF0B56CBBF00CAD239 /* cpVect.c in Sources */, D34963D00B56CBBF00CAD239 /* cpBB.c in Sources */, D34963D10B56CBBF00CAD239 /* cpArray.c in Sources */, D34963D20B56CBBF00CAD239 /* cpHashSet.c in Sources */, D34963D30B56CBBF00CAD239 /* cpBody.c in Sources */, D34963D40B56CBBF00CAD239 /* cpSpaceHash.c in Sources */, D34963D50B56CBBF00CAD239 /* cpArbiter.c in Sources */, D34963D60B56CBBF00CAD239 /* cpPolyShape.c in Sources */, D34963D70B56CBBF00CAD239 /* cpShape.c in Sources */, D34963D80B56CBBF00CAD239 /* cpCollision.c in Sources */, D34963D90B56CBBF00CAD239 /* cpSpace.c in Sources */, D36B19510EA13B6D0028A362 /* cpDampedRotarySpring.c in Sources */, D37BB76E0EAADA6300C70958 /* cpRotaryLimitJoint.c in Sources */, D37BB8B30EAB01E400C70958 /* cpGearJoint.c in Sources */, D37BB8F20EAB06B600C70958 /* cpSimpleMotor.c in Sources */, D36D87831012D63600DB5078 /* cpRatchetJoint.c in Sources */, D34E9E97125581DD002C0FE5 /* cpSpaceComponent.c in Sources */, D34E9EA312558A7C002C0FE5 /* cpSpaceStep.c in Sources */, D3AA477512AF0F8900E27AAB /* cpBBTree.c in Sources */, D3AA477612AF0F8900E27AAB /* cpSpatialIndex.c in Sources */, D317246613280FC900752CBE /* cpSweep1D.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D3C3787711063B1B003EF1D9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D34E9E681255810F002C0FE5 /* cpSpaceQuery.c in Sources */, D3C378F511063C57003EF1D9 /* cpConstraint.c in Sources */, D3C378F611063C57003EF1D9 /* cpPinJoint.c in Sources */, D3C378F711063C57003EF1D9 /* cpSlideJoint.c in Sources */, D3C378F811063C57003EF1D9 /* cpPivotJoint.c in Sources */, D3C378F911063C57003EF1D9 /* cpGrooveJoint.c in Sources */, D3C378FA11063C57003EF1D9 /* cpDampedSpring.c in Sources */, D3C378FB11063C57003EF1D9 /* chipmunk.c in Sources */, D3C378FC11063C57003EF1D9 /* cpVect.c in Sources */, D3C378FD11063C57003EF1D9 /* cpBB.c in Sources */, D3C378FE11063C57003EF1D9 /* cpArray.c in Sources */, D3C378FF11063C57003EF1D9 /* cpHashSet.c in Sources */, D3C3790011063C57003EF1D9 /* cpBody.c in Sources */, D3C3790111063C57003EF1D9 /* cpSpaceHash.c in Sources */, D3C3790211063C57003EF1D9 /* cpArbiter.c in Sources */, D3C3790311063C57003EF1D9 /* cpPolyShape.c in Sources */, D3C3790411063C57003EF1D9 /* cpShape.c in Sources */, D3C3790511063C57003EF1D9 /* cpCollision.c in Sources */, D3C3790611063C57003EF1D9 /* cpSpace.c in Sources */, D3C3790711063C57003EF1D9 /* cpDampedRotarySpring.c in Sources */, D3C3790811063C57003EF1D9 /* cpRotaryLimitJoint.c in Sources */, D3C3790911063C57003EF1D9 /* cpGearJoint.c in Sources */, D3C3790A11063C57003EF1D9 /* cpSimpleMotor.c in Sources */, D3C3790B11063C57003EF1D9 /* cpRatchetJoint.c in Sources */, D34E9E98125581DD002C0FE5 /* cpSpaceComponent.c in Sources */, D34E9EA412558A7C002C0FE5 /* cpSpaceStep.c in Sources */, D3AA477712AF0F8900E27AAB /* cpBBTree.c in Sources */, D3AA477812AF0F8900E27AAB /* cpSpatialIndex.c in Sources */, D317246713280FC900752CBE /* cpSweep1D.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D3E5F0460AA32FDE004E361B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D3BC99C10AB381EE0025A2C0 /* ChipmunkDemo.c in Sources */, D37697200B50C53900BB33CC /* LogoSmash.c in Sources */, D3FBA1A70E9B1E0400950BCC /* ChipmunkDebugDraw.c in Sources */, D3BAF9C50E9C4F250039DD5C /* PyramidStack.c in Sources */, D3BAFA040E9C52810039DD5C /* Plink.c in Sources */, D3BAFA360E9C53E50039DD5C /* Tumble.c in Sources */, D3BAFA510E9C549C0039DD5C /* PyramidTopple.c in Sources */, D3BAFB8B0E9C7C150039DD5C /* Planet.c in Sources */, D31402950E9DD07E00EF79DB /* Springies.c in Sources */, D393275C0EA02C710026F6A2 /* Pump.c in Sources */, D3185D200EC5610A00E6BFCB /* TheoJansen.c in Sources */, D31847750FC458FD00E30B0D /* Query.c in Sources */, D3BACF8310B5DF8900376394 /* OneWay.c in Sources */, D3BAD65810B8B52900376394 /* Player.c in Sources */, D3238F8210C1B5ED00C4BDC2 /* Joints.c in Sources */, D3102B171119FD3000E77771 /* Tank.c in Sources */, D3E4867613175AE000A00840 /* Bench.c in Sources */, D3F52BD313C509DC00EB67D9 /* Chains.c in Sources */, D37282AD13C6432F00FFFA3F /* Crane.c in Sources */, D37282D413C76C1B00FFFA3F /* Buoyancy.c in Sources */, D373FF1013D0D66E000EDB87 /* ContactGraph.c in Sources */, D38996A6148B1E72006CFE0B /* Slice.c in Sources */, D3F2EE2F14F898E9005FD439 /* Unicycle.c in Sources */, D3F6EEDF156D581300A158A8 /* Convex.c in Sources */, D3DFB55D1613765700162F19 /* Sticky.c in Sources */, D38C029916840ED3009F612B /* Shatter.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ D38687D20BAFC688008B7008 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D34963BA0B56CAA300CAD239 /* ChipmunkStatic */; targetProxy = D38687D10BAFC688008B7008 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ D34963BF0B56CACA00CAD239 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; INSTALL_PATH = /usr/local/lib; OTHER_CFLAGS = ( "-DCHIPMUNK_FFI", "-ffast-math", ); PRODUCT_NAME = Chipmunk; SKIP_INSTALL = YES; WARNING_CFLAGS = ( "-Wall", "-W", "-Wno-unused-parameter", "-Werror", "-Wnewline-eof", "-pedantic", ); }; name = Debug; }; D34963C00B56CACA00CAD239 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; INSTALL_PATH = /usr/local/lib; OTHER_CFLAGS = ( "-DCHIPMUNK_FFI", "-DNDEBUG", "-ffast-math", ); PRODUCT_NAME = Chipmunk; SKIP_INSTALL = YES; WARNING_CFLAGS = ( "-Wall", "-W", "-Wno-unused-parameter", "-Werror", "-Wnewline-eof", "-pedantic", ); }; name = Release; }; D3C3787B11063B1C003EF1D9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_THUMB_SUPPORT = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; IPHONEOS_DEPLOYMENT_TARGET = 3.0; PRODUCT_NAME = "Chipmunk-iPhone"; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Debug; }; D3C3787C11063B1C003EF1D9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_AUTO_VECTORIZATION = YES; GCC_THUMB_SUPPORT = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; IPHONEOS_DEPLOYMENT_TARGET = 3.0; PRODUCT_NAME = "Chipmunk-iPhone"; SDKROOT = iphoneos; SKIP_INSTALL = YES; ZERO_LINK = NO; }; name = Release; }; D3E5F01B0AA32EAC004E361B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(NATIVE_ARCH_ACTUAL)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../include/chipmunk; MACOSX_DEPLOYMENT_TARGET = 10.5; OTHER_CFLAGS = "-ffast-math"; WARNING_CFLAGS = ( "-Wall", "-W", "-Wno-unused-parameter", "-Werror", "-Wnewline-eof", ); }; name = Debug; }; D3E5F01C0AA32EAC004E361B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(NATIVE_ARCH_ACTUAL)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 3; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../include/chipmunk; MACOSX_DEPLOYMENT_TARGET = 10.5; OTHER_CFLAGS = ( "-DNDEBUG", "-ffast-math", ); WARNING_CFLAGS = ( "-Wall", "-W", "-Wno-unused-parameter", "-Werror", "-Wnewline-eof", ); }; name = Release; }; D3E5F04E0AA32FDF004E361B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = ""; INFOPLIST_FILE = "main-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/build/Release\""; OTHER_LDFLAGS = ( "-framework", Foundation, "-framework", AppKit, ); PRODUCT_NAME = ChipmunkDemo; SHARED_PRECOMPS_DIR = ""; WARNING_CFLAGS = "-Wall"; WRAPPER_EXTENSION = app; ZERO_LINK = NO; }; name = Debug; }; D3E5F04F0AA32FDF004E361B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_AUTO_VECTORIZATION = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = ""; INFOPLIST_FILE = "main-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/build/Release\""; OTHER_CFLAGS = ( "-ffast-math", "-DNDEBUG", ); OTHER_LDFLAGS = ( "-framework", Foundation, "-framework", AppKit, ); PRODUCT_NAME = ChipmunkDemo; SHARED_PRECOMPS_DIR = ""; WARNING_CFLAGS = "-Wall"; WRAPPER_EXTENSION = app; ZERO_LINK = NO; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ D34963BE0B56CACA00CAD239 /* Build configuration list for PBXNativeTarget "ChipmunkStatic" */ = { isa = XCConfigurationList; buildConfigurations = ( D34963BF0B56CACA00CAD239 /* Debug */, D34963C00B56CACA00CAD239 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D3C3787E11063BB5003EF1D9 /* Build configuration list for PBXNativeTarget "ChipmunkStatic-iPhone" */ = { isa = XCConfigurationList; buildConfigurations = ( D3C3787B11063B1C003EF1D9 /* Debug */, D3C3787C11063B1C003EF1D9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D3E5F01A0AA32EAC004E361B /* Build configuration list for PBXProject "Chipmunk6" */ = { isa = XCConfigurationList; buildConfigurations = ( D3E5F01B0AA32EAC004E361B /* Debug */, D3E5F01C0AA32EAC004E361B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D3E5F04D0AA32FDF004E361B /* Build configuration list for PBXNativeTarget "ChipmunkDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( D3E5F04E0AA32FDF004E361B /* Debug */, D3E5F04F0AA32FDF004E361B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D3E5F0190AA32EAC004E361B /* Project object */; } Chipmunk-6.1.5/xcode/Chipmunk6.xcodeproj/xcshareddata/000755 000765 000000 00000000000 12151675775 023641 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/xcode/Chipmunk6.xcodeproj/xcshareddata/xcdebugger/000755 000765 000000 00000000000 12151675775 025760 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/xcode/Chipmunk6.xcodeproj/xcshareddata/xcdebugger/Breakpoints.xcbkptlist000644 000765 000000 00000001155 12151675775 032354 0ustar00slembckewheel000000 000000 Chipmunk-6.1.5/src/chipmunk.c000644 000765 000000 00000022561 12151675775 017023 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "chipmunk_private.h" void cpMessage(const char *condition, const char *file, int line, cpBool isError, cpBool isHardError, const char *message, ...) { fprintf(stderr, (isError ? "Aborting due to Chipmunk error: " : "Chipmunk warning: ")); va_list vargs; va_start(vargs, message); { vfprintf(stderr, message, vargs); fprintf(stderr, "\n"); } va_end(vargs); fprintf(stderr, "\tFailed condition: %s\n", condition); fprintf(stderr, "\tSource:%s:%d\n", file, line); if(isError) abort(); } #define STR(s) #s #define XSTR(s) STR(s) const char *cpVersionString = XSTR(CP_VERSION_MAJOR)"."XSTR(CP_VERSION_MINOR)"."XSTR(CP_VERSION_RELEASE); void cpInitChipmunk(void) { cpAssertWarn(cpFalse, "cpInitChipmunk is deprecated and no longer required. It will be removed in the future."); } //MARK: Misc Functions cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset) { return m*(0.5f*(r1*r1 + r2*r2) + cpvlengthsq(offset)); } cpFloat cpAreaForCircle(cpFloat r1, cpFloat r2) { return (cpFloat)M_PI*cpfabs(r1*r1 - r2*r2); } cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b) { cpVect offset = cpvmult(cpvadd(a, b), 0.5f); return m*(cpvdistsq(b, a)/12.0f + cpvlengthsq(offset)); } cpFloat cpAreaForSegment(cpVect a, cpVect b, cpFloat r) { return r*((cpFloat)M_PI*r + 2.0f*cpvdist(a, b)); } cpFloat cpMomentForPoly(cpFloat m, const int numVerts, const cpVect *verts, cpVect offset) { cpFloat sum1 = 0.0f; cpFloat sum2 = 0.0f; for(int i=0; i max.x || (v.x == max.x && v.y > max.y)){ max = v; (*end) = i; } } } #define SWAP(__A__, __B__) {cpVect __TMP__ = __A__; __A__ = __B__; __B__ = __TMP__;} static int QHullPartition(cpVect *verts, int count, cpVect a, cpVect b, cpFloat tol) { if(count == 0) return 0; cpFloat max = 0; int pivot = 0; cpVect delta = cpvsub(b, a); cpFloat valueTol = tol*cpvlength(delta); int head = 0; for(int tail = count-1; head <= tail;){ cpFloat value = cpvcross(delta, cpvsub(verts[head], a)); if(value > valueTol){ if(value > max){ max = value; pivot = head; } head++; } else { SWAP(verts[head], verts[tail]); tail--; } } // move the new pivot to the front if it's not already there. if(pivot != 0) SWAP(verts[0], verts[pivot]); return head; } static int QHullReduce(cpFloat tol, cpVect *verts, int count, cpVect a, cpVect pivot, cpVect b, cpVect *result) { if(count < 0){ return 0; } else if(count == 0) { result[0] = pivot; return 1; } else { int left_count = QHullPartition(verts, count, a, pivot, tol); int index = QHullReduce(tol, verts + 1, left_count - 1, a, verts[0], pivot, result); result[index++] = pivot; int right_count = QHullPartition(verts + left_count, count - left_count, pivot, b, tol); return index + QHullReduce(tol, verts + left_count + 1, right_count - 1, pivot, verts[left_count], b, result + index); } } // QuickHull seemed like a neat algorithm, and efficient-ish for large input sets. // My implementation performs an in place reduction using the result array as scratch space. int cpConvexHull(int count, cpVect *verts, cpVect *result, int *first, cpFloat tol) { if(result){ // Copy the line vertexes into the empty part of the result polyline to use as a scratch buffer. memcpy(result, verts, count*sizeof(cpVect)); } else { // If a result array was not specified, reduce the input instead. result = verts; } // Degenerate case, all poins are the same. int start, end; cpLoopIndexes(verts, count, &start, &end); if(start == end){ if(first) (*first) = 0; return 1; } SWAP(result[0], result[start]); SWAP(result[1], result[end == 0 ? start : end]); cpVect a = result[0]; cpVect b = result[1]; if(first) (*first) = start; int resultCount = QHullReduce(tol, result + 2, count - 2, a, b, a, result + 1) + 1; cpAssertSoft(cpPolyValidate(result, resultCount), "Internal error: cpConvexHull() and cpPolyValidate() did not agree." "Please report this error with as much info as you can."); return resultCount; } //MARK: Alternate Block Iterators #if defined(__has_extension) #if __has_extension(blocks) static void IteratorFunc(void *ptr, void (^block)(void *ptr)){block(ptr);} void cpSpaceEachBody_b(cpSpace *space, void (^block)(cpBody *body)){ cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)IteratorFunc, block); } void cpSpaceEachShape_b(cpSpace *space, void (^block)(cpShape *shape)){ cpSpaceEachShape(space, (cpSpaceShapeIteratorFunc)IteratorFunc, block); } void cpSpaceEachConstraint_b(cpSpace *space, void (^block)(cpConstraint *constraint)){ cpSpaceEachConstraint(space, (cpSpaceConstraintIteratorFunc)IteratorFunc, block); } static void BodyIteratorFunc(cpBody *body, void *ptr, void (^block)(void *ptr)){block(ptr);} void cpBodyEachShape_b(cpBody *body, void (^block)(cpShape *shape)){ cpBodyEachShape(body, (cpBodyShapeIteratorFunc)BodyIteratorFunc, block); } void cpBodyEachConstraint_b(cpBody *body, void (^block)(cpConstraint *constraint)){ cpBodyEachConstraint(body, (cpBodyConstraintIteratorFunc)BodyIteratorFunc, block); } void cpBodyEachArbiter_b(cpBody *body, void (^block)(cpArbiter *arbiter)){ cpBodyEachArbiter(body, (cpBodyArbiterIteratorFunc)BodyIteratorFunc, block); } static void NearestPointQueryIteratorFunc(cpShape *shape, cpFloat distance, cpVect point, cpSpaceNearestPointQueryBlock block){block(shape, distance, point);} void cpSpaceNearestPointQuery_b(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryBlock block){ cpSpaceNearestPointQuery(space, point, maxDistance, layers, group, (cpSpaceNearestPointQueryFunc)NearestPointQueryIteratorFunc, block); } static void SegmentQueryIteratorFunc(cpShape *shape, cpFloat t, cpVect n, cpSpaceSegmentQueryBlock block){block(shape, t, n);} void cpSpaceSegmentQuery_b(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryBlock block){ cpSpaceSegmentQuery(space, start, end, layers, group, (cpSpaceSegmentQueryFunc)SegmentQueryIteratorFunc, block); } void cpSpaceBBQuery_b(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryBlock block){ cpSpaceBBQuery(space, bb, layers, group, (cpSpaceBBQueryFunc)IteratorFunc, block); } static void ShapeQueryIteratorFunc(cpShape *shape, cpContactPointSet *points, cpSpaceShapeQueryBlock block){block(shape, points);} cpBool cpSpaceShapeQuery_b(cpSpace *space, cpShape *shape, cpSpaceShapeQueryBlock block){ return cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)ShapeQueryIteratorFunc, block); } #endif #endif #include "chipmunk_ffi.h" Chipmunk-6.1.5/src/CMakeLists.txt000644 000765 000000 00000003202 12151675775 017570 0ustar00slembckewheel000000 000000 file(GLOB chipmunk_source_files "*.c" "constraints/*.c") file(GLOB chipmunk_public_header "${chipmunk_SOURCE_DIR}/include/chipmunk/*.h") file(GLOB chipmunk_constraint_header "${chipmunk_SOURCE_DIR}/include/chipmunk/constraints/*.h") include_directories(${chipmunk_SOURCE_DIR}/include/chipmunk) if(BUILD_SHARED) add_library(chipmunk SHARED ${chipmunk_source_files} ) # Tell MSVC to compile the code as C++. if(MSVC) set_source_files_properties(${chipmunk_source_files} PROPERTIES LANGUAGE CXX) set_target_properties(chipmunk PROPERTIES LINKER_LANGUAGE CXX) endif(MSVC) # set the lib's version number set_target_properties(chipmunk PROPERTIES VERSION 6.1.4) install(TARGETS chipmunk RUNTIME DESTINATION lib LIBRARY DESTINATION lib) endif(BUILD_SHARED) if(BUILD_STATIC) add_library(chipmunk_static STATIC ${chipmunk_source_files} ) # Tell MSVC to compile the code as C++. if(MSVC) set_source_files_properties(${chipmunk_source_files} PROPERTIES LANGUAGE CXX) set_target_properties(chipmunk_static PROPERTIES LINKER_LANGUAGE CXX) endif(MSVC) # Sets chipmunk_static to output "libchipmunk.a" not "libchipmunk_static.a" set_target_properties(chipmunk_static PROPERTIES OUTPUT_NAME chipmunk) if(INSTALL_STATIC) install(TARGETS chipmunk_static ARCHIVE DESTINATION lib) endif(INSTALL_STATIC) endif(BUILD_STATIC) if(BUILD_SHARED OR INSTALL_STATIC) # FIXME: change to PUBLIC_HEADER to allow building frameworks install(FILES ${chipmunk_public_header} DESTINATION include/chipmunk) install(FILES ${chipmunk_constraint_header} DESTINATION include/chipmunk/constraints) endif(BUILD_SHARED OR INSTALL_STATIC) Chipmunk-6.1.5/src/constraints/000755 000765 000000 00000000000 12151675775 017402 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/src/cpArbiter.c000644 000765 000000 00000023770 12151675775 017123 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash) { con->p = p; con->n = n; con->dist = dist; con->jnAcc = 0.0f; con->jtAcc = 0.0f; con->jBias = 0.0f; con->hash = hash; return con; } // TODO make this generic so I can reuse it for constraints also. static inline void unthreadHelper(cpArbiter *arb, cpBody *body) { struct cpArbiterThread *thread = cpArbiterThreadForBody(arb, body); cpArbiter *prev = thread->prev; cpArbiter *next = thread->next; if(prev){ cpArbiterThreadForBody(prev, body)->next = next; } else if(body->arbiterList == arb) { // IFF prev is NULL and body->arbiterList == arb, is arb at the head of the list. // This function may be called for an arbiter that was never in a list. // In that case, we need to protect it from wiping out the body->arbiterList pointer. body->arbiterList = next; } if(next) cpArbiterThreadForBody(next, body)->prev = prev; thread->prev = NULL; thread->next = NULL; } void cpArbiterUnthread(cpArbiter *arb) { unthreadHelper(arb, arb->body_a); unthreadHelper(arb, arb->body_b); } cpBool cpArbiterIsFirstContact(const cpArbiter *arb) { return arb->CP_PRIVATE(state) == cpArbiterStateFirstColl; } int cpArbiterGetCount(const cpArbiter *arb) { // Return 0 contacts if we are in a separate callback. return (arb->CP_PRIVATE(state) != cpArbiterStateCached ? arb->CP_PRIVATE(numContacts) : 0); } cpVect cpArbiterGetNormal(const cpArbiter *arb, int i) { cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter"); cpVect n = arb->contacts[i].n; return arb->swappedColl ? cpvneg(n) : n; } cpVect cpArbiterGetPoint(const cpArbiter *arb, int i) { cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter"); return arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(p); } cpFloat cpArbiterGetDepth(const cpArbiter *arb, int i) { cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter"); return arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(dist); } cpContactPointSet cpArbiterGetContactPointSet(const cpArbiter *arb) { cpContactPointSet set; set.count = cpArbiterGetCount(arb); for(int i=0; iCP_PRIVATE(contacts)[i].CP_PRIVATE(p); set.points[i].normal = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(n); set.points[i].dist = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(dist); } return set; } void cpArbiterSetContactPointSet(cpArbiter *arb, cpContactPointSet *set) { int count = set->count; arb->numContacts = count; for(int i=0; icontacts[i].p = set->points[i].point; arb->contacts[i].n = set->points[i].normal; arb->contacts[i].dist = set->points[i].dist; } } cpVect cpArbiterTotalImpulse(const cpArbiter *arb) { cpContact *contacts = arb->contacts; cpVect sum = cpvzero; for(int i=0, count=cpArbiterGetCount(arb); in, con->jnAcc)); } return (arb->swappedColl ? sum : cpvneg(sum)); } cpVect cpArbiterTotalImpulseWithFriction(const cpArbiter *arb) { cpContact *contacts = arb->contacts; cpVect sum = cpvzero; for(int i=0, count=cpArbiterGetCount(arb); in, cpv(con->jnAcc, con->jtAcc))); } return (arb->swappedColl ? sum : cpvneg(sum)); } cpFloat cpArbiterTotalKE(const cpArbiter *arb) { cpFloat eCoef = (1 - arb->e)/(1 + arb->e); cpFloat sum = 0.0; cpContact *contacts = arb->contacts; for(int i=0, count=cpArbiterGetCount(arb); ijnAcc; cpFloat jtAcc = con->jtAcc; sum += eCoef*jnAcc*jnAcc/con->nMass + jtAcc*jtAcc/con->tMass; } return sum; } // TODO this really shouldn't be a library function probably. // Should either decide to put it in the API or throw it in a demo. //cpFloat //cpContactsEstimateCrushingImpulse(cpContact *contacts, int numContacts) //{ // cpFloat fsum = 0.0f; // cpVect vsum = cpvzero; // // for(int i=0; in, cpv(con->jnAcc, con->jtAcc)); // // fsum += cpvlength(j); // vsum = cpvadd(vsum, j); // } // // cpFloat vmag = cpvlength(vsum); // return fsum - vmag; //} void cpArbiterIgnore(cpArbiter *arb) { arb->state = cpArbiterStateIgnore; } cpVect cpArbiterGetSurfaceVelocity(cpArbiter *arb) { return cpvmult(arb->surface_vr, arb->swappedColl ? -1.0f : 1.0); } void cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect vr) { arb->surface_vr = cpvmult(vr, arb->swappedColl ? -1.0f : 1.0); } cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b) { arb->handler = NULL; arb->swappedColl = cpFalse; arb->e = 0.0f; arb->u = 0.0f; arb->surface_vr = cpvzero; arb->numContacts = 0; arb->contacts = NULL; arb->a = a; arb->body_a = a->body; arb->b = b; arb->body_b = b->body; arb->thread_a.next = NULL; arb->thread_b.next = NULL; arb->thread_a.prev = NULL; arb->thread_b.prev = NULL; arb->stamp = 0; arb->state = cpArbiterStateFirstColl; arb->data = NULL; return arb; } void cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, cpCollisionHandler *handler, cpShape *a, cpShape *b) { // Iterate over the possible pairs to look for hash value matches. for(int i=0; inumContacts; j++){ cpContact *old = &arb->contacts[j]; // This could trigger false positives, but is fairly unlikely nor serious if it does. if(con->hash == old->hash){ // Copy the persistant contact information. con->jnAcc = old->jnAcc; con->jtAcc = old->jtAcc; } } } arb->contacts = contacts; arb->numContacts = numContacts; arb->handler = handler; arb->swappedColl = (a->collision_type != handler->a); arb->e = a->e * b->e; arb->u = a->u * b->u; // Currently all contacts will have the same normal. // This may change in the future. cpVect n = (numContacts ? contacts[0].n : cpvzero); cpVect surface_vr = cpvsub(a->surface_v, b->surface_v); arb->surface_vr = cpvsub(surface_vr, cpvmult(n, cpvdot(surface_vr, n))); // For collisions between two similar primitive types, the order could have been swapped. arb->a = a; arb->body_a = a->body; arb->b = b; arb->body_b = b->body; // mark it as new if it's been cached if(arb->state == cpArbiterStateCached) arb->state = cpArbiterStateFirstColl; } void cpArbiterPreStep(cpArbiter *arb, cpFloat dt, cpFloat slop, cpFloat bias) { cpBody *a = arb->body_a; cpBody *b = arb->body_b; for(int i=0; inumContacts; i++){ cpContact *con = &arb->contacts[i]; // Calculate the offsets. con->r1 = cpvsub(con->p, a->p); con->r2 = cpvsub(con->p, b->p); // Calculate the mass normal and mass tangent. con->nMass = 1.0f/k_scalar(a, b, con->r1, con->r2, con->n); con->tMass = 1.0f/k_scalar(a, b, con->r1, con->r2, cpvperp(con->n)); // Calculate the target bias velocity. con->bias = -bias*cpfmin(0.0f, con->dist + slop)/dt; con->jBias = 0.0f; // Calculate the target bounce velocity. con->bounce = normal_relative_velocity(a, b, con->r1, con->r2, con->n)*arb->e; } } void cpArbiterApplyCachedImpulse(cpArbiter *arb, cpFloat dt_coef) { if(cpArbiterIsFirstContact(arb)) return; cpBody *a = arb->body_a; cpBody *b = arb->body_b; for(int i=0; inumContacts; i++){ cpContact *con = &arb->contacts[i]; cpVect j = cpvrotate(con->n, cpv(con->jnAcc, con->jtAcc)); apply_impulses(a, b, con->r1, con->r2, cpvmult(j, dt_coef)); } } // TODO is it worth splitting velocity/position correction? void cpArbiterApplyImpulse(cpArbiter *arb) { cpBody *a = arb->body_a; cpBody *b = arb->body_b; cpVect surface_vr = arb->surface_vr; cpFloat friction = arb->u; for(int i=0; inumContacts; i++){ cpContact *con = &arb->contacts[i]; cpFloat nMass = con->nMass; cpVect n = con->n; cpVect r1 = con->r1; cpVect r2 = con->r2; cpVect vb1 = cpvadd(a->v_bias, cpvmult(cpvperp(r1), a->w_bias)); cpVect vb2 = cpvadd(b->v_bias, cpvmult(cpvperp(r2), b->w_bias)); cpVect vr = cpvadd(relative_velocity(a, b, r1, r2), surface_vr); cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n); cpFloat vrn = cpvdot(vr, n); cpFloat vrt = cpvdot(vr, cpvperp(n)); cpFloat jbn = (con->bias - vbn)*nMass; cpFloat jbnOld = con->jBias; con->jBias = cpfmax(jbnOld + jbn, 0.0f); cpFloat jn = -(con->bounce + vrn)*nMass; cpFloat jnOld = con->jnAcc; con->jnAcc = cpfmax(jnOld + jn, 0.0f); cpFloat jtMax = friction*con->jnAcc; cpFloat jt = -vrt*con->tMass; cpFloat jtOld = con->jtAcc; con->jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax); apply_bias_impulses(a, b, r1, r2, cpvmult(n, con->jBias - jbnOld)); apply_impulses(a, b, r1, r2, cpvrotate(n, cpv(con->jnAcc - jnOld, con->jtAcc - jtOld))); } } Chipmunk-6.1.5/src/cpArray.c000644 000765 000000 00000005342 12151675775 016604 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "chipmunk_private.h" cpArray * cpArrayNew(int size) { cpArray *arr = (cpArray *)cpcalloc(1, sizeof(cpArray)); arr->num = 0; arr->max = (size ? size : 4); arr->arr = (void **)cpcalloc(arr->max, sizeof(void**)); return arr; } void cpArrayFree(cpArray *arr) { if(arr){ cpfree(arr->arr); arr->arr = NULL; cpfree(arr); } } void cpArrayPush(cpArray *arr, void *object) { if(arr->num == arr->max){ arr->max *= 2; arr->arr = (void **)cprealloc(arr->arr, arr->max*sizeof(void**)); } arr->arr[arr->num] = object; arr->num++; } void * cpArrayPop(cpArray *arr) { arr->num--; void *value = arr->arr[arr->num]; arr->arr[arr->num] = NULL; return value; } //static void //cpArrayDeleteIndex(cpArray *arr, int idx) //{ // arr->num--; // // arr->arr[idx] = arr->arr[arr->num]; // arr->arr[arr->num] = NULL; //} void cpArrayDeleteObj(cpArray *arr, void *obj) { for(int i=0; inum; i++){ if(arr->arr[i] == obj){ arr->num--; arr->arr[i] = arr->arr[arr->num]; arr->arr[arr->num] = NULL; return; } } } //void //cpArrayAppend(cpArray *arr, cpArray *other) //{ // void *tail = &arr->arr[arr->num]; // // arr->num += other->num; // if(arr->num >= arr->max){ // arr->max = arr->num; // arr->arr = (void **)cprealloc(arr->arr, arr->max*sizeof(void**)); // } // // memcpy(tail, other->arr, other->num*sizeof(void**)); //} void cpArrayFreeEach(cpArray *arr, void (freeFunc)(void*)) { for(int i=0; inum; i++) freeFunc(arr->arr[i]); } cpBool cpArrayContains(cpArray *arr, void *ptr) { for(int i=0; inum; i++) if(arr->arr[i] == ptr) return cpTrue; return cpFalse; } Chipmunk-6.1.5/src/cpBB.c000644 000765 000000 00000002717 12151675775 016014 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" cpVect cpBBWrapVect(const cpBB bb, const cpVect v) { cpFloat ix = cpfabs(bb.r - bb.l); cpFloat modx = cpfmod(v.x - bb.l, ix); cpFloat x = (modx > 0.0f) ? modx : modx + ix; cpFloat iy = cpfabs(bb.t - bb.b); cpFloat mody = cpfmod(v.y - bb.b, iy); cpFloat y = (mody > 0.0f) ? mody : mody + iy; return cpv(x + bb.l, y + bb.b); } Chipmunk-6.1.5/src/cpBBTree.c000644 000765 000000 00000051336 12151675775 016635 0ustar00slembckewheel000000 000000 /* Copyright (c) 2009 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "stdlib.h" #include "stdio.h" #include "chipmunk_private.h" static inline cpSpatialIndexClass *Klass(); typedef struct Node Node; typedef struct Pair Pair; struct cpBBTree { cpSpatialIndex spatialIndex; cpBBTreeVelocityFunc velocityFunc; cpHashSet *leaves; Node *root; Node *pooledNodes; Pair *pooledPairs; cpArray *allocatedBuffers; cpTimestamp stamp; }; struct Node { void *obj; cpBB bb; Node *parent; union { // Internal nodes struct { Node *a, *b; } children; // Leaves struct { cpTimestamp stamp; Pair *pairs; } leaf; } node; }; // Can't use anonymous unions and still get good x-compiler compatability #define A node.children.a #define B node.children.b #define STAMP node.leaf.stamp #define PAIRS node.leaf.pairs typedef struct Thread { Pair *prev; Node *leaf; Pair *next; } Thread; struct Pair { Thread a, b; }; //MARK: Misc Functions static inline cpBB GetBB(cpBBTree *tree, void *obj) { cpBB bb = tree->spatialIndex.bbfunc(obj); cpBBTreeVelocityFunc velocityFunc = tree->velocityFunc; if(velocityFunc){ cpFloat coef = 0.1f; cpFloat x = (bb.r - bb.l)*coef; cpFloat y = (bb.t - bb.b)*coef; cpVect v = cpvmult(velocityFunc(obj), 0.1f); return cpBBNew(bb.l + cpfmin(-x, v.x), bb.b + cpfmin(-y, v.y), bb.r + cpfmax(x, v.x), bb.t + cpfmax(y, v.y)); } else { return bb; } } static inline cpBBTree * GetTree(cpSpatialIndex *index) { return (index && index->klass == Klass() ? (cpBBTree *)index : NULL); } static inline Node * GetRootIfTree(cpSpatialIndex *index){ return (index && index->klass == Klass() ? ((cpBBTree *)index)->root : NULL); } static inline cpBBTree * GetMasterTree(cpBBTree *tree) { cpBBTree *dynamicTree = GetTree(tree->spatialIndex.dynamicIndex); return (dynamicTree ? dynamicTree : tree); } static inline void IncrementStamp(cpBBTree *tree) { cpBBTree *dynamicTree = GetTree(tree->spatialIndex.dynamicIndex); if(dynamicTree){ dynamicTree->stamp++; } else { tree->stamp++; } } //MARK: Pair/Thread Functions static void PairRecycle(cpBBTree *tree, Pair *pair) { // Share the pool of the master tree. // TODO would be lovely to move the pairs stuff into an external data structure. tree = GetMasterTree(tree); pair->a.next = tree->pooledPairs; tree->pooledPairs = pair; } static Pair * PairFromPool(cpBBTree *tree) { // Share the pool of the master tree. // TODO would be lovely to move the pairs stuff into an external data structure. tree = GetMasterTree(tree); Pair *pair = tree->pooledPairs; if(pair){ tree->pooledPairs = pair->a.next; return pair; } else { // Pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(Pair); cpAssertHard(count, "Internal Error: Buffer size is too small."); Pair *buffer = (Pair *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(tree->allocatedBuffers, buffer); // push all but the first one, return the first instead for(int i=1; ia.leaf == thread.leaf) next->a.prev = prev; else next->b.prev = prev; } if(prev){ if(prev->a.leaf == thread.leaf) prev->a.next = next; else prev->b.next = next; } else { thread.leaf->PAIRS = next; } } static void PairsClear(Node *leaf, cpBBTree *tree) { Pair *pair = leaf->PAIRS; leaf->PAIRS = NULL; while(pair){ if(pair->a.leaf == leaf){ Pair *next = pair->a.next; ThreadUnlink(pair->b); PairRecycle(tree, pair); pair = next; } else { Pair *next = pair->b.next; ThreadUnlink(pair->a); PairRecycle(tree, pair); pair = next; } } } static void PairInsert(Node *a, Node *b, cpBBTree *tree) { Pair *nextA = a->PAIRS, *nextB = b->PAIRS; Pair *pair = PairFromPool(tree); Pair temp = {{NULL, a, nextA},{NULL, b, nextB}}; a->PAIRS = b->PAIRS = pair; *pair = temp; if(nextA){ if(nextA->a.leaf == a) nextA->a.prev = pair; else nextA->b.prev = pair; } if(nextB){ if(nextB->a.leaf == b) nextB->a.prev = pair; else nextB->b.prev = pair; } } //MARK: Node Functions static void NodeRecycle(cpBBTree *tree, Node *node) { node->parent = tree->pooledNodes; tree->pooledNodes = node; } static Node * NodeFromPool(cpBBTree *tree) { Node *node = tree->pooledNodes; if(node){ tree->pooledNodes = node->parent; return node; } else { // Pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(Node); cpAssertHard(count, "Internal Error: Buffer size is too small."); Node *buffer = (Node *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(tree->allocatedBuffers, buffer); // push all but the first one, return the first instead for(int i=1; iA = value; value->parent = node; } static inline void NodeSetB(Node *node, Node *value) { node->B = value; value->parent = node; } static Node * NodeNew(cpBBTree *tree, Node *a, Node *b) { Node *node = NodeFromPool(tree); node->obj = NULL; node->bb = cpBBMerge(a->bb, b->bb); node->parent = NULL; NodeSetA(node, a); NodeSetB(node, b); return node; } static inline cpBool NodeIsLeaf(Node *node) { return (node->obj != NULL); } static inline Node * NodeOther(Node *node, Node *child) { return (node->A == child ? node->B : node->A); } static inline void NodeReplaceChild(Node *parent, Node *child, Node *value, cpBBTree *tree) { cpAssertSoft(!NodeIsLeaf(parent), "Internal Error: Cannot replace child of a leaf."); cpAssertSoft(child == parent->A || child == parent->B, "Internal Error: Node is not a child of parent."); if(parent->A == child){ NodeRecycle(tree, parent->A); NodeSetA(parent, value); } else { NodeRecycle(tree, parent->B); NodeSetB(parent, value); } for(Node *node=parent; node; node = node->parent){ node->bb = cpBBMerge(node->A->bb, node->B->bb); } } //MARK: Subtree Functions static inline cpFloat cpBBProximity(cpBB a, cpBB b) { return cpfabs(a.l + a.r - b.l - b.r) + cpfabs(a.b + a.t - b.b - b.t); } static Node * SubtreeInsert(Node *subtree, Node *leaf, cpBBTree *tree) { if(subtree == NULL){ return leaf; } else if(NodeIsLeaf(subtree)){ return NodeNew(tree, leaf, subtree); } else { cpFloat cost_a = cpBBArea(subtree->B->bb) + cpBBMergedArea(subtree->A->bb, leaf->bb); cpFloat cost_b = cpBBArea(subtree->A->bb) + cpBBMergedArea(subtree->B->bb, leaf->bb); if(cost_a == cost_b){ cost_a = cpBBProximity(subtree->A->bb, leaf->bb); cost_b = cpBBProximity(subtree->B->bb, leaf->bb); } if(cost_b < cost_a){ NodeSetB(subtree, SubtreeInsert(subtree->B, leaf, tree)); } else { NodeSetA(subtree, SubtreeInsert(subtree->A, leaf, tree)); } subtree->bb = cpBBMerge(subtree->bb, leaf->bb); return subtree; } } static void SubtreeQuery(Node *subtree, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data) { if(cpBBIntersects(subtree->bb, bb)){ if(NodeIsLeaf(subtree)){ func(obj, subtree->obj, data); } else { SubtreeQuery(subtree->A, obj, bb, func, data); SubtreeQuery(subtree->B, obj, bb, func, data); } } } static cpFloat SubtreeSegmentQuery(Node *subtree, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data) { if(NodeIsLeaf(subtree)){ return func(obj, subtree->obj, data); } else { cpFloat t_a = cpBBSegmentQuery(subtree->A->bb, a, b); cpFloat t_b = cpBBSegmentQuery(subtree->B->bb, a, b); if(t_a < t_b){ if(t_a < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->A, obj, a, b, t_exit, func, data)); if(t_b < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->B, obj, a, b, t_exit, func, data)); } else { if(t_b < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->B, obj, a, b, t_exit, func, data)); if(t_a < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->A, obj, a, b, t_exit, func, data)); } return t_exit; } } static void SubtreeRecycle(cpBBTree *tree, Node *node) { if(!NodeIsLeaf(node)){ SubtreeRecycle(tree, node->A); SubtreeRecycle(tree, node->B); NodeRecycle(tree, node); } } static inline Node * SubtreeRemove(Node *subtree, Node *leaf, cpBBTree *tree) { if(leaf == subtree){ return NULL; } else { Node *parent = leaf->parent; if(parent == subtree){ Node *other = NodeOther(subtree, leaf); other->parent = subtree->parent; NodeRecycle(tree, subtree); return other; } else { NodeReplaceChild(parent->parent, parent, NodeOther(parent, leaf), tree); return subtree; } } } //MARK: Marking Functions typedef struct MarkContext { cpBBTree *tree; Node *staticRoot; cpSpatialIndexQueryFunc func; void *data; } MarkContext; static void MarkLeafQuery(Node *subtree, Node *leaf, cpBool left, MarkContext *context) { if(cpBBIntersects(leaf->bb, subtree->bb)){ if(NodeIsLeaf(subtree)){ if(left){ PairInsert(leaf, subtree, context->tree); } else { if(subtree->STAMP < leaf->STAMP) PairInsert(subtree, leaf, context->tree); context->func(leaf->obj, subtree->obj, context->data); } } else { MarkLeafQuery(subtree->A, leaf, left, context); MarkLeafQuery(subtree->B, leaf, left, context); } } } static void MarkLeaf(Node *leaf, MarkContext *context) { cpBBTree *tree = context->tree; if(leaf->STAMP == GetMasterTree(tree)->stamp){ Node *staticRoot = context->staticRoot; if(staticRoot) MarkLeafQuery(staticRoot, leaf, cpFalse, context); for(Node *node = leaf; node->parent; node = node->parent){ if(node == node->parent->A){ MarkLeafQuery(node->parent->B, leaf, cpTrue, context); } else { MarkLeafQuery(node->parent->A, leaf, cpFalse, context); } } } else { Pair *pair = leaf->PAIRS; while(pair){ if(leaf == pair->b.leaf){ context->func(pair->a.leaf->obj, leaf->obj, context->data); pair = pair->b.next; } else { pair = pair->a.next; } } } } static void MarkSubtree(Node *subtree, MarkContext *context) { if(NodeIsLeaf(subtree)){ MarkLeaf(subtree, context); } else { MarkSubtree(subtree->A, context); MarkSubtree(subtree->B, context); } } //MARK: Leaf Functions static Node * LeafNew(cpBBTree *tree, void *obj, cpBB bb) { Node *node = NodeFromPool(tree); node->obj = obj; node->bb = GetBB(tree, obj); node->parent = NULL; node->STAMP = 0; node->PAIRS = NULL; return node; } static cpBool LeafUpdate(Node *leaf, cpBBTree *tree) { Node *root = tree->root; cpBB bb = tree->spatialIndex.bbfunc(leaf->obj); if(!cpBBContainsBB(leaf->bb, bb)){ leaf->bb = GetBB(tree, leaf->obj); root = SubtreeRemove(root, leaf, tree); tree->root = SubtreeInsert(root, leaf, tree); PairsClear(leaf, tree); leaf->STAMP = GetMasterTree(tree)->stamp; return cpTrue; } return cpFalse; } static void VoidQueryFunc(void *obj1, void *obj2, void *data){} static void LeafAddPairs(Node *leaf, cpBBTree *tree) { cpSpatialIndex *dynamicIndex = tree->spatialIndex.dynamicIndex; if(dynamicIndex){ Node *dynamicRoot = GetRootIfTree(dynamicIndex); if(dynamicRoot){ cpBBTree *dynamicTree = GetTree(dynamicIndex); MarkContext context = {dynamicTree, NULL, NULL, NULL}; MarkLeafQuery(dynamicRoot, leaf, cpTrue, &context); } } else { Node *staticRoot = GetRootIfTree(tree->spatialIndex.staticIndex); MarkContext context = {tree, staticRoot, VoidQueryFunc, NULL}; MarkLeaf(leaf, &context); } } //MARK: Memory Management Functions cpBBTree * cpBBTreeAlloc(void) { return (cpBBTree *)cpcalloc(1, sizeof(cpBBTree)); } static int leafSetEql(void *obj, Node *node) { return (obj == node->obj); } static void * leafSetTrans(void *obj, cpBBTree *tree) { return LeafNew(tree, obj, tree->spatialIndex.bbfunc(obj)); } cpSpatialIndex * cpBBTreeInit(cpBBTree *tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { cpSpatialIndexInit((cpSpatialIndex *)tree, Klass(), bbfunc, staticIndex); tree->velocityFunc = NULL; tree->leaves = cpHashSetNew(0, (cpHashSetEqlFunc)leafSetEql); tree->root = NULL; tree->pooledNodes = NULL; tree->allocatedBuffers = cpArrayNew(0); tree->stamp = 0; return (cpSpatialIndex *)tree; } void cpBBTreeSetVelocityFunc(cpSpatialIndex *index, cpBBTreeVelocityFunc func) { if(index->klass != Klass()){ cpAssertWarn(cpFalse, "Ignoring cpBBTreeSetVelocityFunc() call to non-tree spatial index."); return; } ((cpBBTree *)index)->velocityFunc = func; } cpSpatialIndex * cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { return cpBBTreeInit(cpBBTreeAlloc(), bbfunc, staticIndex); } static void cpBBTreeDestroy(cpBBTree *tree) { cpHashSetFree(tree->leaves); if(tree->allocatedBuffers) cpArrayFreeEach(tree->allocatedBuffers, cpfree); cpArrayFree(tree->allocatedBuffers); } //MARK: Insert/Remove static void cpBBTreeInsert(cpBBTree *tree, void *obj, cpHashValue hashid) { Node *leaf = (Node *)cpHashSetInsert(tree->leaves, hashid, obj, tree, (cpHashSetTransFunc)leafSetTrans); Node *root = tree->root; tree->root = SubtreeInsert(root, leaf, tree); leaf->STAMP = GetMasterTree(tree)->stamp; LeafAddPairs(leaf, tree); IncrementStamp(tree); } static void cpBBTreeRemove(cpBBTree *tree, void *obj, cpHashValue hashid) { Node *leaf = (Node *)cpHashSetRemove(tree->leaves, hashid, obj); tree->root = SubtreeRemove(tree->root, leaf, tree); PairsClear(leaf, tree); NodeRecycle(tree, leaf); } static cpBool cpBBTreeContains(cpBBTree *tree, void *obj, cpHashValue hashid) { return (cpHashSetFind(tree->leaves, hashid, obj) != NULL); } //MARK: Reindex static void cpBBTreeReindexQuery(cpBBTree *tree, cpSpatialIndexQueryFunc func, void *data) { if(!tree->root) return; // LeafUpdate() may modify tree->root. Don't cache it. cpHashSetEach(tree->leaves, (cpHashSetIteratorFunc)LeafUpdate, tree); cpSpatialIndex *staticIndex = tree->spatialIndex.staticIndex; Node *staticRoot = (staticIndex && staticIndex->klass == Klass() ? ((cpBBTree *)staticIndex)->root : NULL); MarkContext context = {tree, staticRoot, func, data}; MarkSubtree(tree->root, &context); if(staticIndex && !staticRoot) cpSpatialIndexCollideStatic((cpSpatialIndex *)tree, staticIndex, func, data); IncrementStamp(tree); } static void cpBBTreeReindex(cpBBTree *tree) { cpBBTreeReindexQuery(tree, VoidQueryFunc, NULL); } static void cpBBTreeReindexObject(cpBBTree *tree, void *obj, cpHashValue hashid) { Node *leaf = (Node *)cpHashSetFind(tree->leaves, hashid, obj); if(leaf){ if(LeafUpdate(leaf, tree)) LeafAddPairs(leaf, tree); IncrementStamp(tree); } } //MARK: Query static void cpBBTreeSegmentQuery(cpBBTree *tree, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data) { Node *root = tree->root; if(root) SubtreeSegmentQuery(root, obj, a, b, t_exit, func, data); } static void cpBBTreeQuery(cpBBTree *tree, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data) { if(tree->root) SubtreeQuery(tree->root, obj, bb, func, data); } //MARK: Misc static int cpBBTreeCount(cpBBTree *tree) { return cpHashSetCount(tree->leaves); } typedef struct eachContext { cpSpatialIndexIteratorFunc func; void *data; } eachContext; static void each_helper(Node *node, eachContext *context){context->func(node->obj, context->data);} static void cpBBTreeEach(cpBBTree *tree, cpSpatialIndexIteratorFunc func, void *data) { eachContext context = {func, data}; cpHashSetEach(tree->leaves, (cpHashSetIteratorFunc)each_helper, &context); } static cpSpatialIndexClass klass = { (cpSpatialIndexDestroyImpl)cpBBTreeDestroy, (cpSpatialIndexCountImpl)cpBBTreeCount, (cpSpatialIndexEachImpl)cpBBTreeEach, (cpSpatialIndexContainsImpl)cpBBTreeContains, (cpSpatialIndexInsertImpl)cpBBTreeInsert, (cpSpatialIndexRemoveImpl)cpBBTreeRemove, (cpSpatialIndexReindexImpl)cpBBTreeReindex, (cpSpatialIndexReindexObjectImpl)cpBBTreeReindexObject, (cpSpatialIndexReindexQueryImpl)cpBBTreeReindexQuery, (cpSpatialIndexQueryImpl)cpBBTreeQuery, (cpSpatialIndexSegmentQueryImpl)cpBBTreeSegmentQuery, }; static inline cpSpatialIndexClass *Klass(){return &klass;} //MARK: Tree Optimization static int cpfcompare(const cpFloat *a, const cpFloat *b){ return (*a < *b ? -1 : (*b < *a ? 1 : 0)); } static void fillNodeArray(Node *node, Node ***cursor){ (**cursor) = node; (*cursor)++; } static Node * partitionNodes(cpBBTree *tree, Node **nodes, int count) { if(count == 1){ return nodes[0]; } else if(count == 2) { return NodeNew(tree, nodes[0], nodes[1]); } // Find the AABB for these nodes cpBB bb = nodes[0]->bb; for(int i=1; ibb); // Split it on it's longest axis cpBool splitWidth = (bb.r - bb.l > bb.t - bb.b); // Sort the bounds and use the median as the splitting point cpFloat *bounds = (cpFloat *)cpcalloc(count*2, sizeof(cpFloat)); if(splitWidth){ for(int i=0; ibb.l; bounds[2*i + 1] = nodes[i]->bb.r; } } else { for(int i=0; ibb.b; bounds[2*i + 1] = nodes[i]->bb.t; } } qsort(bounds, count*2, sizeof(cpFloat), (int (*)(const void *, const void *))cpfcompare); cpFloat split = (bounds[count - 1] + bounds[count])*0.5f; // use the medain as the split cpfree(bounds); // Generate the child BBs cpBB a = bb, b = bb; if(splitWidth) a.r = b.l = split; else a.t = b.b = split; // Partition the nodes int right = count; for(int left=0; left < right;){ Node *node = nodes[left]; if(cpBBMergedArea(node->bb, b) < cpBBMergedArea(node->bb, a)){ // if(cpBBProximity(node->bb, b) < cpBBProximity(node->bb, a)){ right--; nodes[left] = nodes[right]; nodes[right] = node; } else { left++; } } if(right == count){ Node *node = NULL; for(int i=0; iroot; // Node *node = root; // int bit = 0; // unsigned int path = tree->opath; // // while(!NodeIsLeaf(node)){ // node = (path&(1<a : node->b); // bit = (bit + 1)&(sizeof(unsigned int)*8 - 1); // } // // root = subtreeRemove(root, node, tree); // tree->root = subtreeInsert(root, node, tree); // } //} void cpBBTreeOptimize(cpSpatialIndex *index) { if(index->klass != &klass){ cpAssertWarn(cpFalse, "Ignoring cpBBTreeOptimize() call to non-tree spatial index."); return; } cpBBTree *tree = (cpBBTree *)index; Node *root = tree->root; if(!root) return; int count = cpBBTreeCount(tree); Node **nodes = (Node **)cpcalloc(count, sizeof(Node *)); Node **cursor = nodes; cpHashSetEach(tree->leaves, (cpHashSetIteratorFunc)fillNodeArray, &cursor); SubtreeRecycle(tree, root); tree->root = partitionNodes(tree, nodes, count); cpfree(nodes); } //MARK: Debug Draw //#define CP_BBTREE_DEBUG_DRAW #ifdef CP_BBTREE_DEBUG_DRAW #include "OpenGL/gl.h" #include "OpenGL/glu.h" #include static void NodeRender(Node *node, int depth) { if(!NodeIsLeaf(node) && depth <= 10){ NodeRender(node->a, depth + 1); NodeRender(node->b, depth + 1); } cpBB bb = node->bb; // GLfloat v = depth/2.0f; // glColor3f(1.0f - v, v, 0.0f); glLineWidth(cpfmax(5.0f - depth, 1.0f)); glBegin(GL_LINES); { glVertex2f(bb.l, bb.b); glVertex2f(bb.l, bb.t); glVertex2f(bb.l, bb.t); glVertex2f(bb.r, bb.t); glVertex2f(bb.r, bb.t); glVertex2f(bb.r, bb.b); glVertex2f(bb.r, bb.b); glVertex2f(bb.l, bb.b); }; glEnd(); } void cpBBTreeRenderDebug(cpSpatialIndex *index){ if(index->klass != &klass){ cpAssertWarn(cpFalse, "Ignoring cpBBTreeRenderDebug() call to non-tree spatial index."); return; } cpBBTree *tree = (cpBBTree *)index; if(tree->root) NodeRender(tree->root, 0); } #endif Chipmunk-6.1.5/src/cpBody.c000644 000765 000000 00000017260 12151675775 016425 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "chipmunk_private.h" #include "constraints/util.h" // initialized in cpInitChipmunk() cpBody cpStaticBodySingleton; cpBody* cpBodyAlloc(void) { return (cpBody *)cpcalloc(1, sizeof(cpBody)); } cpBody * cpBodyInit(cpBody *body, cpFloat m, cpFloat i) { body->space = NULL; body->shapeList = NULL; body->arbiterList = NULL; body->constraintList = NULL; body->velocity_func = cpBodyUpdateVelocity; body->position_func = cpBodyUpdatePosition; cpComponentNode node = {NULL, NULL, 0.0f}; body->node = node; body->p = cpvzero; body->v = cpvzero; body->f = cpvzero; body->w = 0.0f; body->t = 0.0f; body->v_bias = cpvzero; body->w_bias = 0.0f; body->v_limit = (cpFloat)INFINITY; body->w_limit = (cpFloat)INFINITY; body->data = NULL; // Setters must be called after full initialization so the sanity checks don't assert on garbage data. cpBodySetMass(body, m); cpBodySetMoment(body, i); cpBodySetAngle(body, 0.0f); return body; } cpBody* cpBodyNew(cpFloat m, cpFloat i) { return cpBodyInit(cpBodyAlloc(), m, i); } cpBody * cpBodyInitStatic(cpBody *body) { cpBodyInit(body, (cpFloat)INFINITY, (cpFloat)INFINITY); body->node.idleTime = (cpFloat)INFINITY; return body; } cpBody * cpBodyNewStatic(void) { return cpBodyInitStatic(cpBodyAlloc()); } void cpBodyDestroy(cpBody *body){} void cpBodyFree(cpBody *body) { if(body){ cpBodyDestroy(body); cpfree(body); } } static void cpv_assert_nan(cpVect v, char *message){cpAssertSoft(v.x == v.x && v.y == v.y, message);} static void cpv_assert_infinite(cpVect v, char *message){cpAssertSoft(cpfabs(v.x) != INFINITY && cpfabs(v.y) != INFINITY, message);} static void cpv_assert_sane(cpVect v, char *message){cpv_assert_nan(v, message); cpv_assert_infinite(v, message);} #ifdef __cplusplus extern "C" { #endif void cpBodySanityCheck(cpBody *body) { cpAssertSoft(body->m == body->m && body->m_inv == body->m_inv, "Body's mass is invalid."); cpAssertSoft(body->i == body->i && body->i_inv == body->i_inv, "Body's moment is invalid."); cpv_assert_sane(body->p, "Body's position is invalid."); cpv_assert_sane(body->v, "Body's velocity is invalid."); cpv_assert_sane(body->f, "Body's force is invalid."); cpAssertSoft(body->a == body->a && cpfabs(body->a) != INFINITY, "Body's angle is invalid."); cpAssertSoft(body->w == body->w && cpfabs(body->w) != INFINITY, "Body's angular velocity is invalid."); cpAssertSoft(body->t == body->t && cpfabs(body->t) != INFINITY, "Body's torque is invalid."); cpv_assert_sane(body->rot, "Body's rotation vector is invalid."); cpAssertSoft(body->v_limit == body->v_limit, "Body's velocity limit is invalid."); cpAssertSoft(body->w_limit == body->w_limit, "Body's angular velocity limit is invalid."); } #ifdef __cplusplus } #endif void cpBodySetMass(cpBody *body, cpFloat mass) { cpAssertHard(mass > 0.0f, "Mass must be positive and non-zero."); cpBodyActivate(body); body->m = mass; body->m_inv = 1.0f/mass; cpBodyAssertSane(body); } void cpBodySetMoment(cpBody *body, cpFloat moment) { cpAssertHard(moment > 0.0f, "Moment of Inertia must be positive and non-zero."); cpBodyActivate(body); body->i = moment; body->i_inv = 1.0f/moment; cpBodyAssertSane(body); } void cpBodyAddShape(cpBody *body, cpShape *shape) { cpShape *next = body->shapeList; if(next) next->prev = shape; shape->next = next; body->shapeList = shape; } void cpBodyRemoveShape(cpBody *body, cpShape *shape) { cpShape *prev = shape->prev; cpShape *next = shape->next; if(prev){ prev->next = next; } else { body->shapeList = next; } if(next){ next->prev = prev; } shape->prev = NULL; shape->next = NULL; } static cpConstraint * filterConstraints(cpConstraint *node, cpBody *body, cpConstraint *filter) { if(node == filter){ return cpConstraintNext(node, body); } else if(node->a == body){ node->next_a = filterConstraints(node->next_a, body, filter); } else { node->next_b = filterConstraints(node->next_b, body, filter); } return node; } void cpBodyRemoveConstraint(cpBody *body, cpConstraint *constraint) { body->constraintList = filterConstraints(body->constraintList, body, constraint); } void cpBodySetPos(cpBody *body, cpVect pos) { cpBodyActivate(body); body->p = pos; cpBodyAssertSane(body); } static inline void setAngle(cpBody *body, cpFloat angle) { body->a = angle;//fmod(a, (cpFloat)M_PI*2.0f); body->rot = cpvforangle(angle); cpBodyAssertSane(body); } void cpBodySetAngle(cpBody *body, cpFloat angle) { cpBodyActivate(body); setAngle(body, angle); } void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt) { body->v = cpvclamp(cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt)), body->v_limit); cpFloat w_limit = body->w_limit; body->w = cpfclamp(body->w*damping + body->t*body->i_inv*dt, -w_limit, w_limit); cpBodySanityCheck(body); } void cpBodyUpdatePosition(cpBody *body, cpFloat dt) { body->p = cpvadd(body->p, cpvmult(cpvadd(body->v, body->v_bias), dt)); setAngle(body, body->a + (body->w + body->w_bias)*dt); body->v_bias = cpvzero; body->w_bias = 0.0f; cpBodySanityCheck(body); } void cpBodyResetForces(cpBody *body) { cpBodyActivate(body); body->f = cpvzero; body->t = 0.0f; } void cpBodyApplyForce(cpBody *body, cpVect force, cpVect r) { cpBodyActivate(body); body->f = cpvadd(body->f, force); body->t += cpvcross(r, force); } void cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r) { cpBodyActivate(body); apply_impulse(body, j, r); } static inline cpVect cpBodyGetVelAtPoint(cpBody *body, cpVect r) { return cpvadd(body->v, cpvmult(cpvperp(r), body->w)); } cpVect cpBodyGetVelAtWorldPoint(cpBody *body, cpVect point) { return cpBodyGetVelAtPoint(body, cpvsub(point, body->p)); } cpVect cpBodyGetVelAtLocalPoint(cpBody *body, cpVect point) { return cpBodyGetVelAtPoint(body, cpvrotate(point, body->rot)); } void cpBodyEachShape(cpBody *body, cpBodyShapeIteratorFunc func, void *data) { cpShape *shape = body->shapeList; while(shape){ cpShape *next = shape->next; func(body, shape, data); shape = next; } } void cpBodyEachConstraint(cpBody *body, cpBodyConstraintIteratorFunc func, void *data) { cpConstraint *constraint = body->constraintList; while(constraint){ cpConstraint *next = cpConstraintNext(constraint, body); func(body, constraint, data); constraint = next; } } void cpBodyEachArbiter(cpBody *body, cpBodyArbiterIteratorFunc func, void *data) { cpArbiter *arb = body->arbiterList; while(arb){ cpArbiter *next = cpArbiterNext(arb, body); arb->swappedColl = (body == arb->body_b); func(body, arb, data); arb = next; } } Chipmunk-6.1.5/src/cpCollision.c000644 000765 000000 00000030701 12151675775 017456 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" typedef int (*collisionFunc)(const cpShape *, const cpShape *, cpContact *); // Add contact points for circle to circle collisions. // Used by several collision tests. static int circle2circleQuery(const cpVect p1, const cpVect p2, const cpFloat r1, const cpFloat r2, cpContact *con) { cpFloat mindist = r1 + r2; cpVect delta = cpvsub(p2, p1); cpFloat distsq = cpvlengthsq(delta); if(distsq >= mindist*mindist) return 0; cpFloat dist = cpfsqrt(distsq); // Allocate and initialize the contact. cpContactInit( con, cpvadd(p1, cpvmult(delta, 0.5f + (r1 - 0.5f*mindist)/(dist ? dist : INFINITY))), (dist ? cpvmult(delta, 1.0f/dist) : cpv(1.0f, 0.0f)), dist - mindist, 0 ); return 1; } // Collide circle shapes. static int circle2circle(const cpShape *shape1, const cpShape *shape2, cpContact *arr) { cpCircleShape *circ1 = (cpCircleShape *)shape1; //TODO cpCircleShape *circ2 = (cpCircleShape *)shape2; return circle2circleQuery(circ1->tc, circ2->tc, circ1->r, circ2->r, arr); } static int circle2segment(const cpCircleShape *circleShape, const cpSegmentShape *segmentShape, cpContact *con) { cpVect seg_a = segmentShape->ta; cpVect seg_b = segmentShape->tb; cpVect center = circleShape->tc; cpVect seg_delta = cpvsub(seg_b, seg_a); cpFloat closest_t = cpfclamp01(cpvdot(seg_delta, cpvsub(center, seg_a))/cpvlengthsq(seg_delta)); cpVect closest = cpvadd(seg_a, cpvmult(seg_delta, closest_t)); if(circle2circleQuery(center, closest, circleShape->r, segmentShape->r, con)){ cpVect n = con[0].n; // Reject endcap collisions if tangents are provided. if( (closest_t == 0.0f && cpvdot(n, segmentShape->a_tangent) < 0.0) || (closest_t == 1.0f && cpvdot(n, segmentShape->b_tangent) < 0.0) ) return 0; return 1; } else { return 0; } } // Helper function for working with contact buffers // This used to malloc/realloc memory on the fly but was repurposed. static cpContact * nextContactPoint(cpContact *arr, int *numPtr) { int index = *numPtr; if(index < CP_MAX_CONTACTS_PER_ARBITER){ (*numPtr) = index + 1; return &arr[index]; } else { return &arr[CP_MAX_CONTACTS_PER_ARBITER - 1]; } } // Find the minimum separating axis for the give poly and axis list. static inline int findMSA(const cpPolyShape *poly, const cpSplittingPlane *planes, const int num, cpFloat *min_out) { int min_index = 0; cpFloat min = cpPolyShapeValueOnAxis(poly, planes->n, planes->d); if(min > 0.0f) return -1; for(int i=1; i 0.0f) { return -1; } else if(dist > min){ min = dist; min_index = i; } } (*min_out) = min; return min_index; } // Add contacts for probably penetrating vertexes. // This handles the degenerate case where an overlap was detected, but no vertexes fall inside // the opposing polygon. (like a star of david) static inline int findVertsFallback(cpContact *arr, const cpPolyShape *poly1, const cpPolyShape *poly2, const cpVect n, const cpFloat dist) { int num = 0; for(int i=0; inumVerts; i++){ cpVect v = poly1->tVerts[i]; if(cpPolyShapeContainsVertPartial(poly2, v, cpvneg(n))) cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly1->shape.hashid, i)); } for(int i=0; inumVerts; i++){ cpVect v = poly2->tVerts[i]; if(cpPolyShapeContainsVertPartial(poly1, v, n)) cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly2->shape.hashid, i)); } return num; } // Add contacts for penetrating vertexes. static inline int findVerts(cpContact *arr, const cpPolyShape *poly1, const cpPolyShape *poly2, const cpVect n, const cpFloat dist) { int num = 0; for(int i=0; inumVerts; i++){ cpVect v = poly1->tVerts[i]; if(cpPolyShapeContainsVert(poly2, v)) cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly1->shape.hashid, i)); } for(int i=0; inumVerts; i++){ cpVect v = poly2->tVerts[i]; if(cpPolyShapeContainsVert(poly1, v)) cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly2->shape.hashid, i)); } return (num ? num : findVertsFallback(arr, poly1, poly2, n, dist)); } // Collide poly shapes together. static int poly2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr) { cpPolyShape *poly1 = (cpPolyShape *)shape1; cpPolyShape *poly2 = (cpPolyShape *)shape2; cpFloat min1; int mini1 = findMSA(poly2, poly1->tPlanes, poly1->numVerts, &min1); if(mini1 == -1) return 0; cpFloat min2; int mini2 = findMSA(poly1, poly2->tPlanes, poly2->numVerts, &min2); if(mini2 == -1) return 0; // There is overlap, find the penetrating verts if(min1 > min2) return findVerts(arr, poly1, poly2, poly1->tPlanes[mini1].n, min1); else return findVerts(arr, poly1, poly2, cpvneg(poly2->tPlanes[mini2].n), min2); } // Like cpPolyValueOnAxis(), but for segments. static inline cpFloat segValueOnAxis(const cpSegmentShape *seg, const cpVect n, const cpFloat d) { cpFloat a = cpvdot(n, seg->ta) - seg->r; cpFloat b = cpvdot(n, seg->tb) - seg->r; return cpfmin(a, b) - d; } // Identify vertexes that have penetrated the segment. static inline void findPointsBehindSeg(cpContact *arr, int *num, const cpSegmentShape *seg, const cpPolyShape *poly, const cpFloat pDist, const cpFloat coef) { cpFloat dta = cpvcross(seg->tn, seg->ta); cpFloat dtb = cpvcross(seg->tn, seg->tb); cpVect n = cpvmult(seg->tn, coef); for(int i=0; inumVerts; i++){ cpVect v = poly->tVerts[i]; if(cpvdot(v, n) < cpvdot(seg->tn, seg->ta)*coef + seg->r){ cpFloat dt = cpvcross(seg->tn, v); if(dta >= dt && dt >= dtb){ cpContactInit(nextContactPoint(arr, num), v, n, pDist, CP_HASH_PAIR(poly->shape.hashid, i)); } } } } // This one is complicated and gross. Just don't go there... // TODO: Comment me! static int seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr) { cpSegmentShape *seg = (cpSegmentShape *)shape1; cpPolyShape *poly = (cpPolyShape *)shape2; cpSplittingPlane *planes = poly->tPlanes; cpFloat segD = cpvdot(seg->tn, seg->ta); cpFloat minNorm = cpPolyShapeValueOnAxis(poly, seg->tn, segD) - seg->r; cpFloat minNeg = cpPolyShapeValueOnAxis(poly, cpvneg(seg->tn), -segD) - seg->r; if(minNeg > 0.0f || minNorm > 0.0f) return 0; int mini = 0; cpFloat poly_min = segValueOnAxis(seg, planes->n, planes->d); if(poly_min > 0.0f) return 0; for(int i=0; inumVerts; i++){ cpFloat dist = segValueOnAxis(seg, planes[i].n, planes[i].d); if(dist > 0.0f){ return 0; } else if(dist > poly_min){ poly_min = dist; mini = i; } } int num = 0; cpVect poly_n = cpvneg(planes[mini].n); cpVect va = cpvadd(seg->ta, cpvmult(poly_n, seg->r)); cpVect vb = cpvadd(seg->tb, cpvmult(poly_n, seg->r)); if(cpPolyShapeContainsVert(poly, va)) cpContactInit(nextContactPoint(arr, &num), va, poly_n, poly_min, CP_HASH_PAIR(seg->shape.hashid, 0)); if(cpPolyShapeContainsVert(poly, vb)) cpContactInit(nextContactPoint(arr, &num), vb, poly_n, poly_min, CP_HASH_PAIR(seg->shape.hashid, 1)); // Floating point precision problems here. // This will have to do for now. // poly_min -= cp_collision_slop; // TODO is this needed anymore? if(minNorm >= poly_min || minNeg >= poly_min) { if(minNorm > minNeg) findPointsBehindSeg(arr, &num, seg, poly, minNorm, 1.0f); else findPointsBehindSeg(arr, &num, seg, poly, minNeg, -1.0f); } // If no other collision points are found, try colliding endpoints. if(num == 0){ cpVect poly_a = poly->tVerts[mini]; cpVect poly_b = poly->tVerts[(mini + 1)%poly->numVerts]; if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr)) return 1; if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr)) return 1; if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr)) return 1; if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr)) return 1; } return num; } // This one is less gross, but still gross. // TODO: Comment me! static int circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con) { cpCircleShape *circ = (cpCircleShape *)shape1; cpPolyShape *poly = (cpPolyShape *)shape2; cpSplittingPlane *planes = poly->tPlanes; int mini = 0; cpFloat min = cpSplittingPlaneCompare(planes[0], circ->tc) - circ->r; for(int i=0; inumVerts; i++){ cpFloat dist = cpSplittingPlaneCompare(planes[i], circ->tc) - circ->r; if(dist > 0.0f){ return 0; } else if(dist > min) { min = dist; mini = i; } } cpVect n = planes[mini].n; cpVect a = poly->tVerts[mini]; cpVect b = poly->tVerts[(mini + 1)%poly->numVerts]; cpFloat dta = cpvcross(n, a); cpFloat dtb = cpvcross(n, b); cpFloat dt = cpvcross(n, circ->tc); if(dt < dtb){ return circle2circleQuery(circ->tc, b, circ->r, 0.0f, con); } else if(dt < dta) { cpContactInit( con, cpvsub(circ->tc, cpvmult(n, circ->r + min/2.0f)), cpvneg(n), min, 0 ); return 1; } else { return circle2circleQuery(circ->tc, a, circ->r, 0.0f, con); } } // Submitted by LegoCyclon static int seg2seg(const cpShape* shape1, const cpShape* shape2, cpContact* con) { cpSegmentShape* seg1 = (cpSegmentShape *)shape1; cpSegmentShape* seg2 = (cpSegmentShape *)shape2; cpVect v1 = cpvsub(seg1->tb, seg1->ta); cpVect v2 = cpvsub(seg2->tb, seg2->ta); cpFloat v1lsq = cpvlengthsq(v1); cpFloat v2lsq = cpvlengthsq(v2); // project seg2 onto seg1 cpVect p1a = cpvproject(cpvsub(seg2->ta, seg1->ta), v1); cpVect p1b = cpvproject(cpvsub(seg2->tb, seg1->ta), v1); // project seg1 onto seg2 cpVect p2a = cpvproject(cpvsub(seg1->ta, seg2->ta), v2); cpVect p2b = cpvproject(cpvsub(seg1->tb, seg2->ta), v2); // clamp projections to segment endcaps if (cpvdot(p1a, v1) < 0.0f) p1a = cpvzero; else if (cpvdot(p1a, v1) > 0.0f && cpvlengthsq(p1a) > v1lsq) p1a = v1; if (cpvdot(p1b, v1) < 0.0f) p1b = cpvzero; else if (cpvdot(p1b, v1) > 0.0f && cpvlengthsq(p1b) > v1lsq) p1b = v1; if (cpvdot(p2a, v2) < 0.0f) p2a = cpvzero; else if (cpvdot(p2a, v2) > 0.0f && cpvlengthsq(p2a) > v2lsq) p2a = v2; if (cpvdot(p2b, v2) < 0.0f) p2b = cpvzero; else if (cpvdot(p2b, v2) > 0.0f && cpvlengthsq(p2b) > v2lsq) p2b = v2; p1a = cpvadd(p1a, seg1->ta); p1b = cpvadd(p1b, seg1->ta); p2a = cpvadd(p2a, seg2->ta); p2b = cpvadd(p2b, seg2->ta); int num = 0; if (!circle2circleQuery(p1a, p2a, seg1->r, seg2->r, nextContactPoint(con, &num))) --num; if (!circle2circleQuery(p1b, p2b, seg1->r, seg2->r, nextContactPoint(con, &num))) --num; if (!circle2circleQuery(p1a, p2b, seg1->r, seg2->r, nextContactPoint(con, &num))) --num; if (!circle2circleQuery(p1b, p2a, seg1->r, seg2->r, nextContactPoint(con, &num))) --num; return num; } static const collisionFunc builtinCollisionFuncs[9] = { circle2circle, NULL, NULL, (collisionFunc)circle2segment, NULL, NULL, circle2poly, seg2poly, poly2poly, }; static const collisionFunc *colfuncs = builtinCollisionFuncs; static const collisionFunc segmentCollisions[9] = { circle2circle, NULL, NULL, (collisionFunc)circle2segment, seg2seg, NULL, circle2poly, seg2poly, poly2poly, }; void cpEnableSegmentToSegmentCollisions(void) { colfuncs = segmentCollisions; } int cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr) { // Their shape types must be in order. cpAssertSoft(a->klass->type <= b->klass->type, "Collision shapes passed to cpCollideShapes() are not sorted."); collisionFunc cfunc = colfuncs[a->klass->type + b->klass->type*CP_NUM_SHAPES]; return (cfunc) ? cfunc(a, b, arr) : 0; } Chipmunk-6.1.5/src/cpHashSet.c000644 000765 000000 00000013134 12151675775 017063 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "prime.h" typedef struct cpHashSetBin { void *elt; cpHashValue hash; struct cpHashSetBin *next; } cpHashSetBin; struct cpHashSet { unsigned int entries, size; cpHashSetEqlFunc eql; void *default_value; cpHashSetBin **table; cpHashSetBin *pooledBins; cpArray *allocatedBuffers; }; void cpHashSetFree(cpHashSet *set) { if(set){ cpfree(set->table); cpArrayFreeEach(set->allocatedBuffers, cpfree); cpArrayFree(set->allocatedBuffers); cpfree(set); } } cpHashSet * cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc) { cpHashSet *set = (cpHashSet *)cpcalloc(1, sizeof(cpHashSet)); set->size = next_prime(size); set->entries = 0; set->eql = eqlFunc; set->default_value = NULL; set->table = (cpHashSetBin **)cpcalloc(set->size, sizeof(cpHashSetBin *)); set->pooledBins = NULL; set->allocatedBuffers = cpArrayNew(0); return set; } void cpHashSetSetDefaultValue(cpHashSet *set, void *default_value) { set->default_value = default_value; } static int setIsFull(cpHashSet *set) { return (set->entries >= set->size); } static void cpHashSetResize(cpHashSet *set) { // Get the next approximate doubled prime. unsigned int newSize = next_prime(set->size + 1); // Allocate a new table. cpHashSetBin **newTable = (cpHashSetBin **)cpcalloc(newSize, sizeof(cpHashSetBin *)); // Iterate over the chains. for(unsigned int i=0; isize; i++){ // Rehash the bins into the new table. cpHashSetBin *bin = set->table[i]; while(bin){ cpHashSetBin *next = bin->next; cpHashValue idx = bin->hash%newSize; bin->next = newTable[idx]; newTable[idx] = bin; bin = next; } } cpfree(set->table); set->table = newTable; set->size = newSize; } static inline void recycleBin(cpHashSet *set, cpHashSetBin *bin) { bin->next = set->pooledBins; set->pooledBins = bin; bin->elt = NULL; } static cpHashSetBin * getUnusedBin(cpHashSet *set) { cpHashSetBin *bin = set->pooledBins; if(bin){ set->pooledBins = bin->next; return bin; } else { // Pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(cpHashSetBin); cpAssertHard(count, "Internal Error: Buffer size is too small."); cpHashSetBin *buffer = (cpHashSetBin *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(set->allocatedBuffers, buffer); // push all but the first one, return it instead for(int i=1; ientries; } void * cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data, cpHashSetTransFunc trans) { cpHashValue idx = hash%set->size; // Find the bin with the matching element. cpHashSetBin *bin = set->table[idx]; while(bin && !set->eql(ptr, bin->elt)) bin = bin->next; // Create it if necessary. if(!bin){ bin = getUnusedBin(set); bin->hash = hash; bin->elt = (trans ? trans(ptr, data) : data); bin->next = set->table[idx]; set->table[idx] = bin; set->entries++; if(setIsFull(set)) cpHashSetResize(set); } return bin->elt; } void * cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr) { cpHashValue idx = hash%set->size; cpHashSetBin **prev_ptr = &set->table[idx]; cpHashSetBin *bin = set->table[idx]; // Find the bin while(bin && !set->eql(ptr, bin->elt)){ prev_ptr = &bin->next; bin = bin->next; } // Remove it if it exists. if(bin){ // Update the previous linked list pointer (*prev_ptr) = bin->next; set->entries--; void *elt = bin->elt; recycleBin(set, bin); return elt; } return NULL; } void * cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr) { cpHashValue idx = hash%set->size; cpHashSetBin *bin = set->table[idx]; while(bin && !set->eql(ptr, bin->elt)) bin = bin->next; return (bin ? bin->elt : set->default_value); } void cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data) { for(unsigned int i=0; isize; i++){ cpHashSetBin *bin = set->table[i]; while(bin){ cpHashSetBin *next = bin->next; func(bin->elt, data); bin = next; } } } void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data) { for(unsigned int i=0; isize; i++){ // The rest works similarly to cpHashSetRemove() above. cpHashSetBin **prev_ptr = &set->table[i]; cpHashSetBin *bin = set->table[i]; while(bin){ cpHashSetBin *next = bin->next; if(func(bin->elt, data)){ prev_ptr = &bin->next; } else { (*prev_ptr) = next; set->entries--; recycleBin(set, bin); } bin = next; } } } Chipmunk-6.1.5/src/cpPolyShape.c000644 000765 000000 00000015660 12151675775 017436 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "chipmunk_unsafe.h" cpPolyShape * cpPolyShapeAlloc(void) { return (cpPolyShape *)cpcalloc(1, sizeof(cpPolyShape)); } static cpBB cpPolyShapeTransformVerts(cpPolyShape *poly, cpVect p, cpVect rot) { cpVect *src = poly->verts; cpVect *dst = poly->tVerts; cpFloat l = (cpFloat)INFINITY, r = -(cpFloat)INFINITY; cpFloat b = (cpFloat)INFINITY, t = -(cpFloat)INFINITY; for(int i=0; inumVerts; i++){ cpVect v = cpvadd(p, cpvrotate(src[i], rot)); dst[i] = v; l = cpfmin(l, v.x); r = cpfmax(r, v.x); b = cpfmin(b, v.y); t = cpfmax(t, v.y); } return cpBBNew(l, b, r, t); } static void cpPolyShapeTransformAxes(cpPolyShape *poly, cpVect p, cpVect rot) { cpSplittingPlane *src = poly->planes; cpSplittingPlane *dst = poly->tPlanes; for(int i=0; inumVerts; i++){ cpVect n = cpvrotate(src[i].n, rot); dst[i].n = n; dst[i].d = cpvdot(p, n) + src[i].d; } } static cpBB cpPolyShapeCacheData(cpPolyShape *poly, cpVect p, cpVect rot) { cpPolyShapeTransformAxes(poly, p, rot); cpBB bb = poly->shape.bb = cpPolyShapeTransformVerts(poly, p, rot); return bb; } static void cpPolyShapeDestroy(cpPolyShape *poly) { cpfree(poly->verts); cpfree(poly->planes); } static void cpPolyShapeNearestPointQuery(cpPolyShape *poly, cpVect p, cpNearestPointQueryInfo *info){ int count = poly->numVerts; cpSplittingPlane *planes = poly->tPlanes; cpVect *verts = poly->tVerts; cpVect v0 = verts[count - 1]; cpFloat minDist = INFINITY; cpVect closestPoint = cpvzero; cpBool outside = cpFalse; for(int i=0; i 0.0f) outside = cpTrue; cpVect v1 = verts[i]; cpVect closest = cpClosetPointOnSegment(p, v0, v1); cpFloat dist = cpvdist(p, closest); if(dist < minDist){ minDist = dist; closestPoint = closest; } v0 = v1; } info->shape = (cpShape *)poly; info->p = closestPoint; // TODO div/0 info->d = (outside ? minDist : -minDist); } static void cpPolyShapeSegmentQuery(cpPolyShape *poly, cpVect a, cpVect b, cpSegmentQueryInfo *info) { cpSplittingPlane *axes = poly->tPlanes; cpVect *verts = poly->tVerts; int numVerts = poly->numVerts; for(int i=0; i an) continue; cpFloat bn = cpvdot(b, n); cpFloat t = (axes[i].d - an)/(bn - an); if(t < 0.0f || 1.0f < t) continue; cpVect point = cpvlerp(a, b, t); cpFloat dt = -cpvcross(n, point); cpFloat dtMin = -cpvcross(n, verts[i]); cpFloat dtMax = -cpvcross(n, verts[(i+1)%numVerts]); if(dtMin <= dt && dt <= dtMax){ info->shape = (cpShape *)poly; info->t = t; info->n = n; } } } static const cpShapeClass polyClass = { CP_POLY_SHAPE, (cpShapeCacheDataImpl)cpPolyShapeCacheData, (cpShapeDestroyImpl)cpPolyShapeDestroy, (cpShapeNearestPointQueryImpl)cpPolyShapeNearestPointQuery, (cpShapeSegmentQueryImpl)cpPolyShapeSegmentQuery, }; cpBool cpPolyValidate(const cpVect *verts, const int numVerts) { for(int i=0; i 0.0f){ return cpFalse; } } return cpTrue; } int cpPolyShapeGetNumVerts(cpShape *shape) { cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape."); return ((cpPolyShape *)shape)->numVerts; } cpVect cpPolyShapeGetVert(cpShape *shape, int idx) { cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape."); cpAssertHard(0 <= idx && idx < cpPolyShapeGetNumVerts(shape), "Index out of range."); return ((cpPolyShape *)shape)->verts[idx]; } static void setUpVerts(cpPolyShape *poly, int numVerts, const cpVect *verts, cpVect offset) { // Fail if the user attempts to pass a concave poly, or a bad winding. cpAssertHard(cpPolyValidate(verts, numVerts), "Polygon is concave or has a reversed winding. Consider using cpConvexHull() or CP_CONVEX_HULL()."); poly->numVerts = numVerts; poly->verts = (cpVect *)cpcalloc(2*numVerts, sizeof(cpVect)); poly->planes = (cpSplittingPlane *)cpcalloc(2*numVerts, sizeof(cpSplittingPlane)); poly->tVerts = poly->verts + numVerts; poly->tPlanes = poly->planes + numVerts; for(int i=0; iverts[i] = a; poly->planes[i].n = n; poly->planes[i].d = cpvdot(n, a); } } cpPolyShape * cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, const cpVect *verts, cpVect offset) { setUpVerts(poly, numVerts, verts, offset); cpShapeInit((cpShape *)poly, &polyClass, body); return poly; } cpShape * cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset) { return (cpShape *)cpPolyShapeInit(cpPolyShapeAlloc(), body, numVerts, verts, offset); } cpPolyShape * cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height) { cpFloat hw = width/2.0f; cpFloat hh = height/2.0f; return cpBoxShapeInit2(poly, body, cpBBNew(-hw, -hh, hw, hh)); } cpPolyShape * cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box) { cpVect verts[] = { cpv(box.l, box.b), cpv(box.l, box.t), cpv(box.r, box.t), cpv(box.r, box.b), }; return cpPolyShapeInit(poly, body, 4, verts, cpvzero); } cpShape * cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height) { return (cpShape *)cpBoxShapeInit(cpPolyShapeAlloc(), body, width, height); } cpShape * cpBoxShapeNew2(cpBody *body, cpBB box) { return (cpShape *)cpBoxShapeInit2(cpPolyShapeAlloc(), body, box); } // Unsafe API (chipmunk_unsafe.h) void cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset) { cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape."); cpPolyShapeDestroy((cpPolyShape *)shape); setUpVerts((cpPolyShape *)shape, numVerts, verts, offset); } Chipmunk-6.1.5/src/cpShape.c000644 000765 000000 00000023642 12151675775 016571 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "chipmunk_unsafe.h" #define CP_DefineShapeGetter(struct, type, member, name) \ CP_DeclareShapeGetter(struct, type, name){ \ cpAssertHard(shape->klass == &struct##Class, "shape is not a "#struct); \ return ((struct *)shape)->member; \ } static cpHashValue cpShapeIDCounter = 0; void cpResetShapeIdCounter(void) { cpShapeIDCounter = 0; } cpShape* cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body) { shape->klass = klass; shape->hashid = cpShapeIDCounter; cpShapeIDCounter++; shape->body = body; shape->sensor = 0; shape->e = 0.0f; shape->u = 0.0f; shape->surface_v = cpvzero; shape->collision_type = 0; shape->group = CP_NO_GROUP; shape->layers = CP_ALL_LAYERS; shape->data = NULL; shape->space = NULL; shape->next = NULL; shape->prev = NULL; return shape; } void cpShapeDestroy(cpShape *shape) { if(shape->klass && shape->klass->destroy) shape->klass->destroy(shape); } void cpShapeFree(cpShape *shape) { if(shape){ cpShapeDestroy(shape); cpfree(shape); } } void cpShapeSetBody(cpShape *shape, cpBody *body) { cpAssertHard(!cpShapeActive(shape), "You cannot change the body on an active shape. You must remove the shape from the space before changing the body."); shape->body = body; } cpBB cpShapeCacheBB(cpShape *shape) { cpBody *body = shape->body; return cpShapeUpdate(shape, body->p, body->rot); } cpBB cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot) { return (shape->bb = shape->klass->cacheData(shape, pos, rot)); } cpBool cpShapePointQuery(cpShape *shape, cpVect p){ cpNearestPointQueryInfo info = {NULL, cpvzero, INFINITY}; cpShapeNearestPointQuery(shape, p, &info); return (info.d < 0.0f); } cpFloat cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *info) { cpNearestPointQueryInfo blank = {NULL, cpvzero, INFINITY}; if(info){ (*info) = blank; } else { info = ␣ } shape->klass->nearestPointQuery(shape, p, info); return info->d; } cpBool cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){ cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero}; if(info){ (*info) = blank; } else { info = ␣ } cpNearestPointQueryInfo nearest; shape->klass->nearestPointQuery(shape, a, &nearest); if(nearest.d <= 0.0){ info->shape = shape; info->t = 0.0; info->n = cpvnormalize(cpvsub(a, nearest.p)); } else { shape->klass->segmentQuery(shape, a, b, info); } return (info->shape != NULL); } cpCircleShape * cpCircleShapeAlloc(void) { return (cpCircleShape *)cpcalloc(1, sizeof(cpCircleShape)); } static cpBB cpCircleShapeCacheData(cpCircleShape *circle, cpVect p, cpVect rot) { cpVect c = circle->tc = cpvadd(p, cpvrotate(circle->c, rot)); return cpBBNewForCircle(c, circle->r); } static void cpCicleShapeNearestPointQuery(cpCircleShape *circle, cpVect p, cpNearestPointQueryInfo *info) { cpVect delta = cpvsub(p, circle->tc); cpFloat d = cpvlength(delta); cpFloat r = circle->r; info->shape = (cpShape *)circle; info->p = cpvadd(circle->tc, cpvmult(delta, r/d)); // TODO div/0 info->d = d - r; } static void circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo *info) { cpVect da = cpvsub(a, center); cpVect db = cpvsub(b, center); cpFloat qa = cpvdot(da, da) - 2.0f*cpvdot(da, db) + cpvdot(db, db); cpFloat qb = -2.0f*cpvdot(da, da) + 2.0f*cpvdot(da, db); cpFloat qc = cpvdot(da, da) - r*r; cpFloat det = qb*qb - 4.0f*qa*qc; if(det >= 0.0f){ cpFloat t = (-qb - cpfsqrt(det))/(2.0f*qa); if(0.0f<= t && t <= 1.0f){ info->shape = shape; info->t = t; info->n = cpvnormalize(cpvlerp(da, db, t)); } } } static void cpCircleShapeSegmentQuery(cpCircleShape *circle, cpVect a, cpVect b, cpSegmentQueryInfo *info) { circleSegmentQuery((cpShape *)circle, circle->tc, circle->r, a, b, info); } static const cpShapeClass cpCircleShapeClass = { CP_CIRCLE_SHAPE, (cpShapeCacheDataImpl)cpCircleShapeCacheData, NULL, (cpShapeNearestPointQueryImpl)cpCicleShapeNearestPointQuery, (cpShapeSegmentQueryImpl)cpCircleShapeSegmentQuery, }; cpCircleShape * cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset) { circle->c = offset; circle->r = radius; cpShapeInit((cpShape *)circle, &cpCircleShapeClass, body); return circle; } cpShape * cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset) { return (cpShape *)cpCircleShapeInit(cpCircleShapeAlloc(), body, radius, offset); } CP_DefineShapeGetter(cpCircleShape, cpVect, c, Offset) CP_DefineShapeGetter(cpCircleShape, cpFloat, r, Radius) cpSegmentShape * cpSegmentShapeAlloc(void) { return (cpSegmentShape *)cpcalloc(1, sizeof(cpSegmentShape)); } static cpBB cpSegmentShapeCacheData(cpSegmentShape *seg, cpVect p, cpVect rot) { seg->ta = cpvadd(p, cpvrotate(seg->a, rot)); seg->tb = cpvadd(p, cpvrotate(seg->b, rot)); seg->tn = cpvrotate(seg->n, rot); cpFloat l,r,b,t; if(seg->ta.x < seg->tb.x){ l = seg->ta.x; r = seg->tb.x; } else { l = seg->tb.x; r = seg->ta.x; } if(seg->ta.y < seg->tb.y){ b = seg->ta.y; t = seg->tb.y; } else { b = seg->tb.y; t = seg->ta.y; } cpFloat rad = seg->r; return cpBBNew(l - rad, b - rad, r + rad, t + rad); } static void cpSegmentShapeNearestPointQuery(cpSegmentShape *seg, cpVect p, cpNearestPointQueryInfo *info) { cpVect closest = cpClosetPointOnSegment(p, seg->ta, seg->tb); cpVect delta = cpvsub(p, closest); cpFloat d = cpvlength(delta); cpFloat r = seg->r; info->shape = (cpShape *)seg; info->p = (d ? cpvadd(closest, cpvmult(delta, r/d)) : closest); info->d = d - r; } static void cpSegmentShapeSegmentQuery(cpSegmentShape *seg, cpVect a, cpVect b, cpSegmentQueryInfo *info) { cpVect n = seg->tn; cpFloat d = cpvdot(cpvsub(seg->ta, a), n); cpFloat r = seg->r; cpVect flipped_n = (d > 0.0f ? cpvneg(n) : n); cpVect seg_offset = cpvsub(cpvmult(flipped_n, r), a); // Make the endpoints relative to 'a' and move them by the thickness of the segment. cpVect seg_a = cpvadd(seg->ta, seg_offset); cpVect seg_b = cpvadd(seg->tb, seg_offset); cpVect delta = cpvsub(b, a); if(cpvcross(delta, seg_a)*cpvcross(delta, seg_b) <= 0.0f){ cpFloat d_offset = d + (d > 0.0f ? -r : r); cpFloat ad = -d_offset; cpFloat bd = cpvdot(delta, n) - d_offset; if(ad*bd < 0.0f){ info->shape = (cpShape *)seg; info->t = ad/(ad - bd); info->n = flipped_n; } } else if(r != 0.0f){ cpSegmentQueryInfo info1 = {NULL, 1.0f, cpvzero}; cpSegmentQueryInfo info2 = {NULL, 1.0f, cpvzero}; circleSegmentQuery((cpShape *)seg, seg->ta, seg->r, a, b, &info1); circleSegmentQuery((cpShape *)seg, seg->tb, seg->r, a, b, &info2); if(info1.t < info2.t){ (*info) = info1; } else { (*info) = info2; } } } static const cpShapeClass cpSegmentShapeClass = { CP_SEGMENT_SHAPE, (cpShapeCacheDataImpl)cpSegmentShapeCacheData, NULL, (cpShapeNearestPointQueryImpl)cpSegmentShapeNearestPointQuery, (cpShapeSegmentQueryImpl)cpSegmentShapeSegmentQuery, }; cpSegmentShape * cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r) { seg->a = a; seg->b = b; seg->n = cpvperp(cpvnormalize(cpvsub(b, a))); seg->r = r; seg->a_tangent = cpvzero; seg->b_tangent = cpvzero; cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body); return seg; } cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r) { return (cpShape *)cpSegmentShapeInit(cpSegmentShapeAlloc(), body, a, b, r); } CP_DefineShapeGetter(cpSegmentShape, cpVect, a, A) CP_DefineShapeGetter(cpSegmentShape, cpVect, b, B) CP_DefineShapeGetter(cpSegmentShape, cpVect, n, Normal) CP_DefineShapeGetter(cpSegmentShape, cpFloat, r, Radius) void cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next) { cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape."); cpSegmentShape *seg = (cpSegmentShape *)shape; seg->a_tangent = cpvsub(prev, seg->a); seg->b_tangent = cpvsub(next, seg->b); } // Unsafe API (chipmunk_unsafe.h) void cpCircleShapeSetRadius(cpShape *shape, cpFloat radius) { cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape."); cpCircleShape *circle = (cpCircleShape *)shape; circle->r = radius; } void cpCircleShapeSetOffset(cpShape *shape, cpVect offset) { cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape."); cpCircleShape *circle = (cpCircleShape *)shape; circle->c = offset; } void cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b) { cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape."); cpSegmentShape *seg = (cpSegmentShape *)shape; seg->a = a; seg->b = b; seg->n = cpvperp(cpvnormalize(cpvsub(b, a))); } void cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius) { cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape."); cpSegmentShape *seg = (cpSegmentShape *)shape; seg->r = radius; } Chipmunk-6.1.5/src/cpSpace.c000644 000765 000000 00000042460 12151675775 016563 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include "chipmunk_private.h" //MARK: Contact Set Helpers // Equal function for arbiterSet. static cpBool arbiterSetEql(cpShape **shapes, cpArbiter *arb) { cpShape *a = shapes[0]; cpShape *b = shapes[1]; return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b)); } //MARK: Collision Handler Set HelperFunctions // Equals function for collisionHandlers. static cpBool handlerSetEql(cpCollisionHandler *check, cpCollisionHandler *pair) { return ((check->a == pair->a && check->b == pair->b) || (check->b == pair->a && check->a == pair->b)); } // Transformation function for collisionHandlers. static void * handlerSetTrans(cpCollisionHandler *handler, void *unused) { cpCollisionHandler *copy = (cpCollisionHandler *)cpcalloc(1, sizeof(cpCollisionHandler)); (*copy) = (*handler); return copy; } //MARK: Misc Helper Funcs // Default collision functions. static cpBool alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;} static void nothing(cpArbiter *arb, cpSpace *space, void *data){} // function to get the estimated velocity of a shape for the cpBBTree. static cpVect shapeVelocityFunc(cpShape *shape){return shape->body->v;} static void freeWrap(void *ptr, void *unused){cpfree(ptr);} //MARK: Memory Management Functions cpSpace * cpSpaceAlloc(void) { return (cpSpace *)cpcalloc(1, sizeof(cpSpace)); } cpCollisionHandler cpDefaultCollisionHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL}; cpSpace* cpSpaceInit(cpSpace *space) { #ifndef NDEBUG static cpBool done = cpFalse; if(!done){ printf("Initializing cpSpace - Chipmunk v%s (Debug Enabled)\n", cpVersionString); printf("Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks\n"); done = cpTrue; } #endif space->iterations = 10; space->gravity = cpvzero; space->damping = 1.0f; space->collisionSlop = 0.1f; space->collisionBias = cpfpow(1.0f - 0.1f, 60.0f); space->collisionPersistence = 3; space->locked = 0; space->stamp = 0; space->staticShapes = cpBBTreeNew((cpSpatialIndexBBFunc)cpShapeGetBB, NULL); space->activeShapes = cpBBTreeNew((cpSpatialIndexBBFunc)cpShapeGetBB, space->staticShapes); cpBBTreeSetVelocityFunc(space->activeShapes, (cpBBTreeVelocityFunc)shapeVelocityFunc); space->allocatedBuffers = cpArrayNew(0); space->bodies = cpArrayNew(0); space->sleepingComponents = cpArrayNew(0); space->rousedBodies = cpArrayNew(0); space->sleepTimeThreshold = INFINITY; space->idleSpeedThreshold = 0.0f; space->enableContactGraph = cpFalse; space->arbiters = cpArrayNew(0); space->pooledArbiters = cpArrayNew(0); space->contactBuffersHead = NULL; space->cachedArbiters = cpHashSetNew(0, (cpHashSetEqlFunc)arbiterSetEql); space->constraints = cpArrayNew(0); space->defaultHandler = cpDefaultCollisionHandler; space->collisionHandlers = cpHashSetNew(0, (cpHashSetEqlFunc)handlerSetEql); cpHashSetSetDefaultValue(space->collisionHandlers, &cpDefaultCollisionHandler); space->postStepCallbacks = cpArrayNew(0); space->skipPostStep = cpFalse; cpBodyInitStatic(&space->_staticBody); space->staticBody = &space->_staticBody; return space; } cpSpace* cpSpaceNew(void) { return cpSpaceInit(cpSpaceAlloc()); } void cpSpaceDestroy(cpSpace *space) { cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)cpBodyActivate, NULL); cpSpatialIndexFree(space->staticShapes); cpSpatialIndexFree(space->activeShapes); cpArrayFree(space->bodies); cpArrayFree(space->sleepingComponents); cpArrayFree(space->rousedBodies); cpArrayFree(space->constraints); cpHashSetFree(space->cachedArbiters); cpArrayFree(space->arbiters); cpArrayFree(space->pooledArbiters); if(space->allocatedBuffers){ cpArrayFreeEach(space->allocatedBuffers, cpfree); cpArrayFree(space->allocatedBuffers); } if(space->postStepCallbacks){ cpArrayFreeEach(space->postStepCallbacks, cpfree); cpArrayFree(space->postStepCallbacks); } if(space->collisionHandlers) cpHashSetEach(space->collisionHandlers, freeWrap, NULL); cpHashSetFree(space->collisionHandlers); } void cpSpaceFree(cpSpace *space) { if(space){ cpSpaceDestroy(space); cpfree(space); } } #define cpAssertSpaceUnlocked(space) \ cpAssertHard(!space->locked, \ "This operation cannot be done safely during a call to cpSpaceStep() or during a query. " \ "Put these calls into a post-step callback." \ ); //MARK: Collision Handler Function Management void cpSpaceAddCollisionHandler( cpSpace *space, cpCollisionType a, cpCollisionType b, cpCollisionBeginFunc begin, cpCollisionPreSolveFunc preSolve, cpCollisionPostSolveFunc postSolve, cpCollisionSeparateFunc separate, void *data ){ cpAssertSpaceUnlocked(space); // Remove any old function so the new one will get added. cpSpaceRemoveCollisionHandler(space, a, b); cpCollisionHandler handler = { a, b, begin ? begin : alwaysCollide, preSolve ? preSolve : alwaysCollide, postSolve ? postSolve : nothing, separate ? separate : nothing, data }; cpHashSetInsert(space->collisionHandlers, CP_HASH_PAIR(a, b), &handler, NULL, (cpHashSetTransFunc)handlerSetTrans); } void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b) { cpAssertSpaceUnlocked(space); struct { cpCollisionType a, b; } ids = {a, b}; cpCollisionHandler *old_handler = (cpCollisionHandler *) cpHashSetRemove(space->collisionHandlers, CP_HASH_PAIR(a, b), &ids); cpfree(old_handler); } void cpSpaceSetDefaultCollisionHandler( cpSpace *space, cpCollisionBeginFunc begin, cpCollisionPreSolveFunc preSolve, cpCollisionPostSolveFunc postSolve, cpCollisionSeparateFunc separate, void *data ){ cpAssertSpaceUnlocked(space); cpCollisionHandler handler = { 0, 0, begin ? begin : alwaysCollide, preSolve ? preSolve : alwaysCollide, postSolve ? postSolve : nothing, separate ? separate : nothing, data }; space->defaultHandler = handler; cpHashSetSetDefaultValue(space->collisionHandlers, &space->defaultHandler); } //MARK: Body, Shape, and Joint Management cpShape * cpSpaceAddShape(cpSpace *space, cpShape *shape) { cpBody *body = shape->body; if(cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape); cpAssertHard(shape->space != space, "You have already added this shape to this space. You must not add it a second time."); cpAssertHard(!shape->space, "You have already added this shape to another space. You cannot add it to a second."); cpAssertSpaceUnlocked(space); cpBodyActivate(body); cpBodyAddShape(body, shape); cpShapeUpdate(shape, body->p, body->rot); cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid); shape->space = space; return shape; } cpShape * cpSpaceAddStaticShape(cpSpace *space, cpShape *shape) { cpAssertHard(shape->space != space, "You have already added this shape to this space. You must not add it a second time."); cpAssertHard(!shape->space, "You have already added this shape to another space. You cannot add it to a second."); cpAssertHard(cpBodyIsRogue(shape->body), "You are adding a static shape to a dynamic body. Did you mean to attach it to a static or rogue body? See the documentation for more information."); cpAssertSpaceUnlocked(space); cpBody *body = shape->body; cpBodyAddShape(body, shape); cpShapeUpdate(shape, body->p, body->rot); cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid); shape->space = space; return shape; } cpBody * cpSpaceAddBody(cpSpace *space, cpBody *body) { cpAssertHard(!cpBodyIsStatic(body), "Do not add static bodies to a space. Static bodies do not move and should not be simulated."); cpAssertHard(body->space != space, "You have already added this body to this space. You must not add it a second time."); cpAssertHard(!body->space, "You have already added this body to another space. You cannot add it to a second."); cpAssertSpaceUnlocked(space); cpArrayPush(space->bodies, body); body->space = space; return body; } cpConstraint * cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint) { cpAssertHard(constraint->space != space, "You have already added this constraint to this space. You must not add it a second time."); cpAssertHard(!constraint->space, "You have already added this constraint to another space. You cannot add it to a second."); cpAssertHard(constraint->a && constraint->b, "Constraint is attached to a NULL body."); cpAssertSpaceUnlocked(space); cpBodyActivate(constraint->a); cpBodyActivate(constraint->b); cpArrayPush(space->constraints, constraint); // Push onto the heads of the bodies' constraint lists cpBody *a = constraint->a, *b = constraint->b; constraint->next_a = a->constraintList; a->constraintList = constraint; constraint->next_b = b->constraintList; b->constraintList = constraint; constraint->space = space; return constraint; } struct arbiterFilterContext { cpSpace *space; cpBody *body; cpShape *shape; }; static cpBool cachedArbitersFilter(cpArbiter *arb, struct arbiterFilterContext *context) { cpShape *shape = context->shape; cpBody *body = context->body; // Match on the filter shape, or if it's NULL the filter body if( (body == arb->body_a && (shape == arb->a || shape == NULL)) || (body == arb->body_b && (shape == arb->b || shape == NULL)) ){ // Call separate when removing shapes. if(shape && arb->state != cpArbiterStateCached) cpArbiterCallSeparate(arb, context->space); cpArbiterUnthread(arb); cpArrayDeleteObj(context->space->arbiters, arb); cpArrayPush(context->space->pooledArbiters, arb); return cpFalse; } return cpTrue; } void cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter) { cpSpaceLock(space); { struct arbiterFilterContext context = {space, body, filter}; cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cachedArbitersFilter, &context); } cpSpaceUnlock(space, cpTrue); } void cpSpaceRemoveShape(cpSpace *space, cpShape *shape) { cpBody *body = shape->body; if(cpBodyIsStatic(body)){ cpSpaceRemoveStaticShape(space, shape); } else { cpAssertHard(cpSpaceContainsShape(space, shape), "Cannot remove a shape that was not added to the space. (Removed twice maybe?)"); cpAssertSpaceUnlocked(space); cpBodyActivate(body); cpBodyRemoveShape(body, shape); cpSpaceFilterArbiters(space, body, shape); cpSpatialIndexRemove(space->activeShapes, shape, shape->hashid); shape->space = NULL; } } void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape) { cpAssertHard(cpSpaceContainsShape(space, shape), "Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)"); cpAssertSpaceUnlocked(space); cpBody *body = shape->body; if(cpBodyIsStatic(body)) cpBodyActivateStatic(body, shape); cpBodyRemoveShape(body, shape); cpSpaceFilterArbiters(space, body, shape); cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid); shape->space = NULL; } void cpSpaceRemoveBody(cpSpace *space, cpBody *body) { cpAssertHard(cpSpaceContainsBody(space, body), "Cannot remove a body that was not added to the space. (Removed twice maybe?)"); cpAssertSpaceUnlocked(space); cpBodyActivate(body); // cpSpaceFilterArbiters(space, body, NULL); cpArrayDeleteObj(space->bodies, body); body->space = NULL; } void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint) { cpAssertHard(cpSpaceContainsConstraint(space, constraint), "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)"); cpAssertSpaceUnlocked(space); cpBodyActivate(constraint->a); cpBodyActivate(constraint->b); cpArrayDeleteObj(space->constraints, constraint); cpBodyRemoveConstraint(constraint->a, constraint); cpBodyRemoveConstraint(constraint->b, constraint); constraint->space = NULL; } cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape) { return (shape->space == space); } cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body) { return (body->space == space); } cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint) { return (constraint->space == space); } //MARK: Static/rogue body conversion. void cpSpaceConvertBodyToStatic(cpSpace *space, cpBody *body) { cpAssertHard(!cpBodyIsStatic(body), "Body is already static."); cpAssertHard(cpBodyIsRogue(body), "Remove the body from the space before calling this function."); cpAssertSpaceUnlocked(space); cpBodySetMass(body, INFINITY); cpBodySetMoment(body, INFINITY); cpBodySetVel(body, cpvzero); cpBodySetAngVel(body, 0.0f); body->node.idleTime = INFINITY; CP_BODY_FOREACH_SHAPE(body, shape){ cpSpatialIndexRemove(space->activeShapes, shape, shape->hashid); cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid); } } void cpSpaceConvertBodyToDynamic(cpSpace *space, cpBody *body, cpFloat m, cpFloat i) { cpAssertHard(cpBodyIsStatic(body), "Body is already dynamic."); cpAssertSpaceUnlocked(space); cpBodyActivateStatic(body, NULL); cpBodySetMass(body, m); cpBodySetMoment(body, i); body->node.idleTime = 0.0f; CP_BODY_FOREACH_SHAPE(body, shape){ cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid); cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid); } } //MARK: Iteration void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data) { cpSpaceLock(space); { cpArray *bodies = space->bodies; for(int i=0; inum; i++){ func((cpBody *)bodies->arr[i], data); } cpArray *components = space->sleepingComponents; for(int i=0; inum; i++){ cpBody *root = (cpBody *)components->arr[i]; cpBody *body = root; while(body){ cpBody *next = body->node.next; func(body, data); body = next; } } } cpSpaceUnlock(space, cpTrue); } typedef struct spaceShapeContext { cpSpaceShapeIteratorFunc func; void *data; } spaceShapeContext; static void spaceEachShapeIterator(cpShape *shape, spaceShapeContext *context) { context->func(shape, context->data); } void cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data) { cpSpaceLock(space); { spaceShapeContext context = {func, data}; cpSpatialIndexEach(space->activeShapes, (cpSpatialIndexIteratorFunc)spaceEachShapeIterator, &context); cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)spaceEachShapeIterator, &context); } cpSpaceUnlock(space, cpTrue); } void cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data) { cpSpaceLock(space); { cpArray *constraints = space->constraints; for(int i=0; inum; i++){ func((cpConstraint *)constraints->arr[i], data); } } cpSpaceUnlock(space, cpTrue); } //MARK: Spatial Index Management static void updateBBCache(cpShape *shape, void *unused) { cpBody *body = shape->body; cpShapeUpdate(shape, body->p, body->rot); } void cpSpaceReindexStatic(cpSpace *space) { cpAssertHard(!space->locked, "You cannot manually reindex objects while the space is locked. Wait until the current query or step is complete."); cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)&updateBBCache, NULL); cpSpatialIndexReindex(space->staticShapes); } void cpSpaceReindexShape(cpSpace *space, cpShape *shape) { cpAssertHard(!space->locked, "You cannot manually reindex objects while the space is locked. Wait until the current query or step is complete."); cpBody *body = shape->body; cpShapeUpdate(shape, body->p, body->rot); // attempt to rehash the shape in both hashes cpSpatialIndexReindexObject(space->activeShapes, shape, shape->hashid); cpSpatialIndexReindexObject(space->staticShapes, shape, shape->hashid); } void cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body) { CP_BODY_FOREACH_SHAPE(body, shape) cpSpaceReindexShape(space, shape); } static void copyShapes(cpShape *shape, cpSpatialIndex *index) { cpSpatialIndexInsert(index, shape, shape->hashid); } void cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count) { cpSpatialIndex *staticShapes = cpSpaceHashNew(dim, count, (cpSpatialIndexBBFunc)cpShapeGetBB, NULL); cpSpatialIndex *activeShapes = cpSpaceHashNew(dim, count, (cpSpatialIndexBBFunc)cpShapeGetBB, staticShapes); cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)copyShapes, staticShapes); cpSpatialIndexEach(space->activeShapes, (cpSpatialIndexIteratorFunc)copyShapes, activeShapes); cpSpatialIndexFree(space->staticShapes); cpSpatialIndexFree(space->activeShapes); space->staticShapes = staticShapes; space->activeShapes = activeShapes; } Chipmunk-6.1.5/src/cpSpaceComponent.c000644 000765 000000 00000027200 12151675775 020441 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "chipmunk_private.h" //MARK: Sleeping Functions void cpSpaceActivateBody(cpSpace *space, cpBody *body) { cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rogue body."); if(space->locked){ // cpSpaceActivateBody() is called again once the space is unlocked if(!cpArrayContains(space->rousedBodies, body)) cpArrayPush(space->rousedBodies, body); } else { cpAssertSoft(body->node.root == NULL && body->node.next == NULL, "Internal error: Activating body non-NULL node pointers."); cpArrayPush(space->bodies, body); CP_BODY_FOREACH_SHAPE(body, shape){ cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid); cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid); } CP_BODY_FOREACH_ARBITER(body, arb){ cpBody *bodyA = arb->body_a; // Arbiters are shared between two bodies that are always woken up together. // You only want to restore the arbiter once, so bodyA is arbitrarily chosen to own the arbiter. // The edge case is when static bodies are involved as the static bodies never actually sleep. // If the static body is bodyB then all is good. If the static body is bodyA, that can easily be checked. if(body == bodyA || cpBodyIsStatic(bodyA)){ int numContacts = arb->numContacts; cpContact *contacts = arb->contacts; // Restore contact values back to the space's contact buffer memory arb->contacts = cpContactBufferGetArray(space); memcpy(arb->contacts, contacts, numContacts*sizeof(cpContact)); cpSpacePushContacts(space, numContacts); // Reinsert the arbiter into the arbiter cache cpShape *a = arb->a, *b = arb->b; cpShape *shape_pair[] = {a, b}; cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b); cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, arb, NULL); // Update the arbiter's state arb->stamp = space->stamp; arb->handler = cpSpaceLookupHandler(space, a->collision_type, b->collision_type); cpArrayPush(space->arbiters, arb); cpfree(contacts); } } CP_BODY_FOREACH_CONSTRAINT(body, constraint){ cpBody *bodyA = constraint->a; if(body == bodyA || cpBodyIsStatic(bodyA)) cpArrayPush(space->constraints, constraint); } } } static void cpSpaceDeactivateBody(cpSpace *space, cpBody *body) { cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to deactivate a rouge body."); cpArrayDeleteObj(space->bodies, body); CP_BODY_FOREACH_SHAPE(body, shape){ cpSpatialIndexRemove(space->activeShapes, shape, shape->hashid); cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid); } CP_BODY_FOREACH_ARBITER(body, arb){ cpBody *bodyA = arb->body_a; if(body == bodyA || cpBodyIsStatic(bodyA)){ cpSpaceUncacheArbiter(space, arb); // Save contact values to a new block of memory so they won't time out size_t bytes = arb->numContacts*sizeof(cpContact); cpContact *contacts = (cpContact *)cpcalloc(1, bytes); memcpy(contacts, arb->contacts, bytes); arb->contacts = contacts; } } CP_BODY_FOREACH_CONSTRAINT(body, constraint){ cpBody *bodyA = constraint->a; if(body == bodyA || cpBodyIsStatic(bodyA)) cpArrayDeleteObj(space->constraints, constraint); } } static inline cpBody * ComponentRoot(cpBody *body) { return (body ? body->node.root : NULL); } static inline void ComponentActivate(cpBody *root) { if(!root || !cpBodyIsSleeping(root)) return; cpAssertHard(!cpBodyIsRogue(root), "Internal Error: ComponentActivate() called on a rogue body."); cpSpace *space = root->space; cpBody *body = root; while(body){ cpBody *next = body->node.next; body->node.idleTime = 0.0f; body->node.root = NULL; body->node.next = NULL; cpSpaceActivateBody(space, body); body = next; } cpArrayDeleteObj(space->sleepingComponents, root); } void cpBodyActivate(cpBody *body) { if(!cpBodyIsRogue(body)){ body->node.idleTime = 0.0f; ComponentActivate(ComponentRoot(body)); } CP_BODY_FOREACH_ARBITER(body, arb){ // Reset the idle timer of things the body is touching as well. // That way things don't get left hanging in the air. cpBody *other = (arb->body_a == body ? arb->body_b : arb->body_a); if(!cpBodyIsStatic(other)) other->node.idleTime = 0.0f; } } void cpBodyActivateStatic(cpBody *body, cpShape *filter) { cpAssertHard(cpBodyIsStatic(body), "cpBodyActivateStatic() called on a non-static body."); CP_BODY_FOREACH_ARBITER(body, arb){ if(!filter || filter == arb->a || filter == arb->b){ cpBodyActivate(arb->body_a == body ? arb->body_b : arb->body_a); } } // TODO should also activate joints? } static inline void cpBodyPushArbiter(cpBody *body, cpArbiter *arb) { cpAssertSoft(cpArbiterThreadForBody(arb, body)->next == NULL, "Internal Error: Dangling contact graph pointers detected. (A)"); cpAssertSoft(cpArbiterThreadForBody(arb, body)->prev == NULL, "Internal Error: Dangling contact graph pointers detected. (B)"); cpArbiter *next = body->arbiterList; cpAssertSoft(next == NULL || cpArbiterThreadForBody(next, body)->prev == NULL, "Internal Error: Dangling contact graph pointers detected. (C)"); cpArbiterThreadForBody(arb, body)->next = next; if(next) cpArbiterThreadForBody(next, body)->prev = arb; body->arbiterList = arb; } static inline void ComponentAdd(cpBody *root, cpBody *body){ body->node.root = root; if(body != root){ body->node.next = root->node.next; root->node.next = body; } } static inline void FloodFillComponent(cpBody *root, cpBody *body) { // Rogue bodies cannot be put to sleep and prevent bodies they are touching from sleepining anyway. // Static bodies (which are a type of rogue body) are effectively sleeping all the time. if(!cpBodyIsRogue(body)){ cpBody *other_root = ComponentRoot(body); if(other_root == NULL){ ComponentAdd(root, body); CP_BODY_FOREACH_ARBITER(body, arb) FloodFillComponent(root, (body == arb->body_a ? arb->body_b : arb->body_a)); CP_BODY_FOREACH_CONSTRAINT(body, constraint) FloodFillComponent(root, (body == constraint->a ? constraint->b : constraint->a)); } else { cpAssertSoft(other_root == root, "Internal Error: Inconsistency dectected in the contact graph."); } } } static inline cpBool ComponentActive(cpBody *root, cpFloat threshold) { CP_BODY_FOREACH_COMPONENT(root, body){ if(body->node.idleTime < threshold) return cpTrue; } return cpFalse; } void cpSpaceProcessComponents(cpSpace *space, cpFloat dt) { cpBool sleep = (space->sleepTimeThreshold != INFINITY); cpArray *bodies = space->bodies; #ifndef NDEBUG for(int i=0; inum; i++){ cpBody *body = (cpBody*)bodies->arr[i]; cpAssertSoft(body->node.next == NULL, "Internal Error: Dangling next pointer detected in contact graph."); cpAssertSoft(body->node.root == NULL, "Internal Error: Dangling root pointer detected in contact graph."); } #endif // Calculate the kinetic energy of all the bodies. if(sleep){ cpFloat dv = space->idleSpeedThreshold; cpFloat dvsq = (dv ? dv*dv : cpvlengthsq(space->gravity)*dt*dt); // update idling and reset component nodes for(int i=0; inum; i++){ cpBody *body = (cpBody*)bodies->arr[i]; // Need to deal with infinite mass objects cpFloat keThreshold = (dvsq ? body->m*dvsq : 0.0f); body->node.idleTime = (cpBodyKineticEnergy(body) > keThreshold ? 0.0f : body->node.idleTime + dt); } } // Awaken any sleeping bodies found and then push arbiters to the bodies' lists. cpArray *arbiters = space->arbiters; for(int i=0, count=arbiters->num; iarr[i]; cpBody *a = arb->body_a, *b = arb->body_b; if(sleep){ if((cpBodyIsRogue(b) && !cpBodyIsStatic(b)) || cpBodyIsSleeping(a)) cpBodyActivate(a); if((cpBodyIsRogue(a) && !cpBodyIsStatic(a)) || cpBodyIsSleeping(b)) cpBodyActivate(b); } cpBodyPushArbiter(a, arb); cpBodyPushArbiter(b, arb); } if(sleep){ // Bodies should be held active if connected by a joint to a non-static rouge body. cpArray *constraints = space->constraints; for(int i=0; inum; i++){ cpConstraint *constraint = (cpConstraint *)constraints->arr[i]; cpBody *a = constraint->a, *b = constraint->b; if(cpBodyIsRogue(b) && !cpBodyIsStatic(b)) cpBodyActivate(a); if(cpBodyIsRogue(a) && !cpBodyIsStatic(a)) cpBodyActivate(b); } // Generate components and deactivate sleeping ones for(int i=0; inum;){ cpBody *body = (cpBody*)bodies->arr[i]; if(ComponentRoot(body) == NULL){ // Body not in a component yet. Perform a DFS to flood fill mark // the component in the contact graph using this body as the root. FloodFillComponent(body, body); // Check if the component should be put to sleep. if(!ComponentActive(body, space->sleepTimeThreshold)){ cpArrayPush(space->sleepingComponents, body); CP_BODY_FOREACH_COMPONENT(body, other) cpSpaceDeactivateBody(space, other); // cpSpaceDeactivateBody() removed the current body from the list. // Skip incrementing the index counter. continue; } } i++; // Only sleeping bodies retain their component node pointers. body->node.root = NULL; body->node.next = NULL; } } } void cpBodySleep(cpBody *body) { cpBodySleepWithGroup(body, NULL); } void cpBodySleepWithGroup(cpBody *body, cpBody *group){ cpAssertHard(!cpBodyIsRogue(body), "Rogue (and static) bodies cannot be put to sleep."); cpSpace *space = body->space; cpAssertHard(!space->locked, "Bodies cannot be put to sleep during a query or a call to cpSpaceStep(). Put these calls into a post-step callback."); cpAssertHard(group == NULL || cpBodyIsSleeping(group), "Cannot use a non-sleeping body as a group identifier."); if(cpBodyIsSleeping(body)){ cpAssertHard(ComponentRoot(body) == ComponentRoot(group), "The body is already sleeping and it's group cannot be reassigned."); return; } CP_BODY_FOREACH_SHAPE(body, shape) cpShapeUpdate(shape, body->p, body->rot); cpSpaceDeactivateBody(space, body); if(group){ cpBody *root = ComponentRoot(group); cpComponentNode node = {root, root->node.next, 0.0f}; body->node = node; root->node.next = body; } else { cpComponentNode node = {body, NULL, 0.0f}; body->node = node; cpArrayPush(space->sleepingComponents, body); } cpArrayDeleteObj(space->bodies, body); } static void activateTouchingHelper(cpShape *shape, cpContactPointSet *points, cpShape *other){ cpBodyActivate(shape->body); } void cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape){ if(space->sleepTimeThreshold != INFINITY){ cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)activateTouchingHelper, shape); } } Chipmunk-6.1.5/src/cpSpaceHash.c000644 000765 000000 00000036547 12151675775 017400 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "prime.h" typedef struct cpSpaceHashBin cpSpaceHashBin; typedef struct cpHandle cpHandle; struct cpSpaceHash { cpSpatialIndex spatialIndex; int numcells; cpFloat celldim; cpSpaceHashBin **table; cpHashSet *handleSet; cpSpaceHashBin *pooledBins; cpArray *pooledHandles; cpArray *allocatedBuffers; cpTimestamp stamp; }; //MARK: Handle Functions struct cpHandle { void *obj; int retain; cpTimestamp stamp; }; static cpHandle* cpHandleInit(cpHandle *hand, void *obj) { hand->obj = obj; hand->retain = 0; hand->stamp = 0; return hand; } static inline void cpHandleRetain(cpHandle *hand){hand->retain++;} static inline void cpHandleRelease(cpHandle *hand, cpArray *pooledHandles) { hand->retain--; if(hand->retain == 0) cpArrayPush(pooledHandles, hand); } static int handleSetEql(void *obj, cpHandle *hand){return (obj == hand->obj);} static void * handleSetTrans(void *obj, cpSpaceHash *hash) { if(hash->pooledHandles->num == 0){ // handle pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(cpHandle); cpAssertHard(count, "Internal Error: Buffer size is too small."); cpHandle *buffer = (cpHandle *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(hash->allocatedBuffers, buffer); for(int i=0; ipooledHandles, buffer + i); } cpHandle *hand = cpHandleInit((cpHandle *)cpArrayPop(hash->pooledHandles), obj); cpHandleRetain(hand); return hand; } //MARK: Bin Functions struct cpSpaceHashBin { cpHandle *handle; cpSpaceHashBin *next; }; static inline void recycleBin(cpSpaceHash *hash, cpSpaceHashBin *bin) { bin->next = hash->pooledBins; hash->pooledBins = bin; } static inline void clearTableCell(cpSpaceHash *hash, int idx) { cpSpaceHashBin *bin = hash->table[idx]; while(bin){ cpSpaceHashBin *next = bin->next; cpHandleRelease(bin->handle, hash->pooledHandles); recycleBin(hash, bin); bin = next; } hash->table[idx] = NULL; } static void clearTable(cpSpaceHash *hash) { for(int i=0; inumcells; i++) clearTableCell(hash, i); } // Get a recycled or new bin. static inline cpSpaceHashBin * getEmptyBin(cpSpaceHash *hash) { cpSpaceHashBin *bin = hash->pooledBins; if(bin){ hash->pooledBins = bin->next; return bin; } else { // Pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(cpSpaceHashBin); cpAssertHard(count, "Internal Error: Buffer size is too small."); cpSpaceHashBin *buffer = (cpSpaceHashBin *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(hash->allocatedBuffers, buffer); // push all but the first one, return the first instead for(int i=1; itable); hash->numcells = numcells; hash->table = (cpSpaceHashBin **)cpcalloc(numcells, sizeof(cpSpaceHashBin *)); } static inline cpSpatialIndexClass *Klass(); cpSpatialIndex * cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { cpSpatialIndexInit((cpSpatialIndex *)hash, Klass(), bbfunc, staticIndex); cpSpaceHashAllocTable(hash, next_prime(numcells)); hash->celldim = celldim; hash->handleSet = cpHashSetNew(0, (cpHashSetEqlFunc)handleSetEql); hash->pooledHandles = cpArrayNew(0); hash->pooledBins = NULL; hash->allocatedBuffers = cpArrayNew(0); hash->stamp = 1; return (cpSpatialIndex *)hash; } cpSpatialIndex * cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc, staticIndex); } static void cpSpaceHashDestroy(cpSpaceHash *hash) { if(hash->table) clearTable(hash); cpfree(hash->table); cpHashSetFree(hash->handleSet); cpArrayFreeEach(hash->allocatedBuffers, cpfree); cpArrayFree(hash->allocatedBuffers); cpArrayFree(hash->pooledHandles); } //MARK: Helper Functions static inline cpBool containsHandle(cpSpaceHashBin *bin, cpHandle *hand) { while(bin){ if(bin->handle == hand) return cpTrue; bin = bin->next; } return cpFalse; } // The hash function itself. static inline cpHashValue hash_func(cpHashValue x, cpHashValue y, cpHashValue n) { return (x*1640531513ul ^ y*2654435789ul) % n; } // Much faster than (int)floor(f) // Profiling showed floor() to be a sizable performance hog static inline int floor_int(cpFloat f) { int i = (int)f; return (f < 0.0f && f != i ? i - 1 : i); } static inline void hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb) { // Find the dimensions in cell coordinates. cpFloat dim = hash->celldim; int l = floor_int(bb.l/dim); // Fix by ShiftZ int r = floor_int(bb.r/dim); int b = floor_int(bb.b/dim); int t = floor_int(bb.t/dim); int n = hash->numcells; for(int i=l; i<=r; i++){ for(int j=b; j<=t; j++){ cpHashValue idx = hash_func(i,j,n); cpSpaceHashBin *bin = hash->table[idx]; // Don't add an object twice to the same cell. if(containsHandle(bin, hand)) continue; cpHandleRetain(hand); // Insert a new bin for the handle in this cell. cpSpaceHashBin *newBin = getEmptyBin(hash); newBin->handle = hand; newBin->next = bin; hash->table[idx] = newBin; } } } //MARK: Basic Operations static void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid) { cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, hash, (cpHashSetTransFunc)handleSetTrans); hashHandle(hash, hand, hash->spatialIndex.bbfunc(obj)); } static void cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue hashid) { cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj); if(hand){ hand->obj = NULL; cpHandleRelease(hand, hash->pooledHandles); cpSpaceHashInsert(hash, obj, hashid); } } static void rehash_helper(cpHandle *hand, cpSpaceHash *hash) { hashHandle(hash, hand, hash->spatialIndex.bbfunc(hand->obj)); } static void cpSpaceHashRehash(cpSpaceHash *hash) { clearTable(hash); cpHashSetEach(hash->handleSet, (cpHashSetIteratorFunc)rehash_helper, hash); } static void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue hashid) { cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj); if(hand){ hand->obj = NULL; cpHandleRelease(hand, hash->pooledHandles); } } typedef struct eachContext { cpSpatialIndexIteratorFunc func; void *data; } eachContext; static void eachHelper(cpHandle *hand, eachContext *context){context->func(hand->obj, context->data);} static void cpSpaceHashEach(cpSpaceHash *hash, cpSpatialIndexIteratorFunc func, void *data) { eachContext context = {func, data}; cpHashSetEach(hash->handleSet, (cpHashSetIteratorFunc)eachHelper, &context); } static void remove_orphaned_handles(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr) { cpSpaceHashBin *bin = *bin_ptr; while(bin){ cpHandle *hand = bin->handle; cpSpaceHashBin *next = bin->next; if(!hand->obj){ // orphaned handle, unlink and recycle the bin (*bin_ptr) = bin->next; recycleBin(hash, bin); cpHandleRelease(hand, hash->pooledHandles); } else { bin_ptr = &bin->next; } bin = next; } } //MARK: Query Functions static inline void query_helper(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpatialIndexQueryFunc func, void *data) { restart: for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){ cpHandle *hand = bin->handle; void *other = hand->obj; if(hand->stamp == hash->stamp || obj == other){ continue; } else if(other){ func(obj, other, data); hand->stamp = hash->stamp; } else { // The object for this handle has been removed // cleanup this cell and restart the query remove_orphaned_handles(hash, bin_ptr); goto restart; // GCC not smart enough/able to tail call an inlined function. } } } static void cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data) { // Get the dimensions in cell coordinates. cpFloat dim = hash->celldim; int l = floor_int(bb.l/dim); // Fix by ShiftZ int r = floor_int(bb.r/dim); int b = floor_int(bb.b/dim); int t = floor_int(bb.t/dim); int n = hash->numcells; cpSpaceHashBin **table = hash->table; // Iterate over the cells and query them. for(int i=l; i<=r; i++){ for(int j=b; j<=t; j++){ query_helper(hash, &table[hash_func(i,j,n)], obj, func, data); } } hash->stamp++; } // Similar to struct eachPair above. typedef struct queryRehashContext { cpSpaceHash *hash; cpSpatialIndexQueryFunc func; void *data; } queryRehashContext; // Hashset iterator func used with cpSpaceHashQueryRehash(). static void queryRehash_helper(cpHandle *hand, queryRehashContext *context) { cpSpaceHash *hash = context->hash; cpSpatialIndexQueryFunc func = context->func; void *data = context->data; cpFloat dim = hash->celldim; int n = hash->numcells; void *obj = hand->obj; cpBB bb = hash->spatialIndex.bbfunc(obj); int l = floor_int(bb.l/dim); int r = floor_int(bb.r/dim); int b = floor_int(bb.b/dim); int t = floor_int(bb.t/dim); cpSpaceHashBin **table = hash->table; for(int i=l; i<=r; i++){ for(int j=b; j<=t; j++){ cpHashValue idx = hash_func(i,j,n); cpSpaceHashBin *bin = table[idx]; if(containsHandle(bin, hand)) continue; cpHandleRetain(hand); // this MUST be done first in case the object is removed in func() query_helper(hash, &bin, obj, func, data); cpSpaceHashBin *newBin = getEmptyBin(hash); newBin->handle = hand; newBin->next = bin; table[idx] = newBin; } } // Increment the stamp for each object hashed. hash->stamp++; } static void cpSpaceHashReindexQuery(cpSpaceHash *hash, cpSpatialIndexQueryFunc func, void *data) { clearTable(hash); queryRehashContext context = {hash, func, data}; cpHashSetEach(hash->handleSet, (cpHashSetIteratorFunc)queryRehash_helper, &context); cpSpatialIndexCollideStatic((cpSpatialIndex *)hash, hash->spatialIndex.staticIndex, func, data); } static inline cpFloat segmentQuery_helper(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpatialIndexSegmentQueryFunc func, void *data) { cpFloat t = 1.0f; restart: for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){ cpHandle *hand = bin->handle; void *other = hand->obj; // Skip over certain conditions if(hand->stamp == hash->stamp){ continue; } else if(other){ t = cpfmin(t, func(obj, other, data)); hand->stamp = hash->stamp; } else { // The object for this handle has been removed // cleanup this cell and restart the query remove_orphaned_handles(hash, bin_ptr); goto restart; // GCC not smart enough/able to tail call an inlined function. } } return t; } // modified from http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html static void cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data) { a = cpvmult(a, 1.0f/hash->celldim); b = cpvmult(b, 1.0f/hash->celldim); int cell_x = floor_int(a.x), cell_y = floor_int(a.y); cpFloat t = 0; int x_inc, y_inc; cpFloat temp_v, temp_h; if (b.x > a.x){ x_inc = 1; temp_h = (cpffloor(a.x + 1.0f) - a.x); } else { x_inc = -1; temp_h = (a.x - cpffloor(a.x)); } if (b.y > a.y){ y_inc = 1; temp_v = (cpffloor(a.y + 1.0f) - a.y); } else { y_inc = -1; temp_v = (a.y - cpffloor(a.y)); } // Division by zero is *very* slow on ARM cpFloat dx = cpfabs(b.x - a.x), dy = cpfabs(b.y - a.y); cpFloat dt_dx = (dx ? 1.0f/dx : INFINITY), dt_dy = (dy ? 1.0f/dy : INFINITY); // fix NANs in horizontal directions cpFloat next_h = (temp_h ? temp_h*dt_dx : dt_dx); cpFloat next_v = (temp_v ? temp_v*dt_dy : dt_dy); int n = hash->numcells; cpSpaceHashBin **table = hash->table; while(t < t_exit){ cpHashValue idx = hash_func(cell_x, cell_y, n); t_exit = cpfmin(t_exit, segmentQuery_helper(hash, &table[idx], obj, func, data)); if (next_v < next_h){ cell_y += y_inc; t = next_v; next_v += dt_dy; } else { cell_x += x_inc; t = next_h; next_h += dt_dx; } } hash->stamp++; } //MARK: Misc void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells) { if(hash->spatialIndex.klass != Klass()){ cpAssertWarn(cpFalse, "Ignoring cpSpaceHashResize() call to non-cpSpaceHash spatial index."); return; } clearTable(hash); hash->celldim = celldim; cpSpaceHashAllocTable(hash, next_prime(numcells)); } static int cpSpaceHashCount(cpSpaceHash *hash) { return cpHashSetCount(hash->handleSet); } static int cpSpaceHashContains(cpSpaceHash *hash, void *obj, cpHashValue hashid) { return cpHashSetFind(hash->handleSet, hashid, obj) != NULL; } static cpSpatialIndexClass klass = { (cpSpatialIndexDestroyImpl)cpSpaceHashDestroy, (cpSpatialIndexCountImpl)cpSpaceHashCount, (cpSpatialIndexEachImpl)cpSpaceHashEach, (cpSpatialIndexContainsImpl)cpSpaceHashContains, (cpSpatialIndexInsertImpl)cpSpaceHashInsert, (cpSpatialIndexRemoveImpl)cpSpaceHashRemove, (cpSpatialIndexReindexImpl)cpSpaceHashRehash, (cpSpatialIndexReindexObjectImpl)cpSpaceHashRehashObject, (cpSpatialIndexReindexQueryImpl)cpSpaceHashReindexQuery, (cpSpatialIndexQueryImpl)cpSpaceHashQuery, (cpSpatialIndexSegmentQueryImpl)cpSpaceHashSegmentQuery, }; static inline cpSpatialIndexClass *Klass(){return &klass;} //MARK: Debug Drawing //#define CP_BBTREE_DEBUG_DRAW #ifdef CP_BBTREE_DEBUG_DRAW #include "OpenGL/gl.h" #include "OpenGL/glu.h" #include void cpSpaceHashRenderDebug(cpSpatialIndex *index) { if(index->klass != &klass){ cpAssertWarn(cpFalse, "Ignoring cpSpaceHashRenderDebug() call to non-spatial hash spatial index."); return; } cpSpaceHash *hash = (cpSpaceHash *)index; cpBB bb = cpBBNew(-320, -240, 320, 240); cpFloat dim = hash->celldim; int n = hash->numcells; int l = (int)floor(bb.l/dim); int r = (int)floor(bb.r/dim); int b = (int)floor(bb.b/dim); int t = (int)floor(bb.t/dim); for(int i=l; i<=r; i++){ for(int j=b; j<=t; j++){ int cell_count = 0; int index = hash_func(i,j,n); for(cpSpaceHashBin *bin = hash->table[index]; bin; bin = bin->next) cell_count++; GLfloat v = 1.0f - (GLfloat)cell_count/10.0f; glColor3f(v,v,v); glRectf(i*dim, j*dim, (i + 1)*dim, (j + 1)*dim); } } } #endif Chipmunk-6.1.5/src/cpSpaceQuery.c000644 000765 000000 00000022043 12151675775 017604 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" //MARK: Point Query Functions struct PointQueryContext { cpVect point; cpLayers layers; cpGroup group; cpSpacePointQueryFunc func; void *data; }; static void PointQuery(struct PointQueryContext *context, cpShape *shape, void *data) { if( !(shape->group && context->group == shape->group) && (context->layers&shape->layers) && cpShapePointQuery(shape, context->point) ){ context->func(shape, context->data); } } void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data) { struct PointQueryContext context = {point, layers, group, func, data}; cpBB bb = cpBBNewForCircle(point, 0.0f); cpSpaceLock(space); { cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)PointQuery, data); cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)PointQuery, data); } cpSpaceUnlock(space, cpTrue); } static void PointQueryFirst(cpShape *shape, cpShape **outShape) { if(!shape->sensor) *outShape = shape; } cpShape * cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group) { cpShape *shape = NULL; cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)PointQueryFirst, &shape); return shape; } //MARK: Nearest Point Query Functions struct NearestPointQueryContext { cpVect point; cpFloat maxDistance; cpLayers layers; cpGroup group; cpSpaceNearestPointQueryFunc func; }; static void NearestPointQuery(struct NearestPointQueryContext *context, cpShape *shape, void *data) { if( !(shape->group && context->group == shape->group) && (context->layers&shape->layers) ){ cpNearestPointQueryInfo info; cpShapeNearestPointQuery(shape, context->point, &info); if(info.shape && info.d < context->maxDistance) context->func(shape, info.d, info.p, data); } } void cpSpaceNearestPointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryFunc func, void *data) { struct NearestPointQueryContext context = {point, maxDistance, layers, group, func}; cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f)); cpSpaceLock(space); { cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data); cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data); } cpSpaceUnlock(space, cpTrue); } static void NearestPointQueryNearest(struct NearestPointQueryContext *context, cpShape *shape, cpNearestPointQueryInfo *out) { if( !(shape->group && context->group == shape->group) && (context->layers&shape->layers) && !shape->sensor ){ cpNearestPointQueryInfo info; cpShapeNearestPointQuery(shape, context->point, &info); if(info.d < out->d) (*out) = info; } } cpShape * cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out) { cpNearestPointQueryInfo info = {NULL, cpvzero, maxDistance}; if(out){ (*out) = info; } else { out = &info; } struct NearestPointQueryContext context = { point, maxDistance, layers, group, NULL }; cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f)); cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out); cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out); return out->shape; } //MARK: Segment Query Functions struct SegmentQueryContext { cpVect start, end; cpLayers layers; cpGroup group; cpSpaceSegmentQueryFunc func; }; static cpFloat SegmentQuery(struct SegmentQueryContext *context, cpShape *shape, void *data) { cpSegmentQueryInfo info; if( !(shape->group && context->group == shape->group) && (context->layers&shape->layers) && cpShapeSegmentQuery(shape, context->start, context->end, &info) ){ context->func(shape, info.t, info.n, data); } return 1.0f; } void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data) { struct SegmentQueryContext context = { start, end, layers, group, func, }; cpSpaceLock(space); { cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data); cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data); } cpSpaceUnlock(space, cpTrue); } static cpFloat SegmentQueryFirst(struct SegmentQueryContext *context, cpShape *shape, cpSegmentQueryInfo *out) { cpSegmentQueryInfo info; if( !(shape->group && context->group == shape->group) && (context->layers&shape->layers) && !shape->sensor && cpShapeSegmentQuery(shape, context->start, context->end, &info) && info.t < out->t ){ (*out) = info; } return out->t; } cpShape * cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out) { cpSegmentQueryInfo info = {NULL, 1.0f, cpvzero}; if(out){ (*out) = info; } else { out = &info; } struct SegmentQueryContext context = { start, end, layers, group, NULL }; cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out); cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out); return out->shape; } //MARK: BB Query Functions struct BBQueryContext { cpBB bb; cpLayers layers; cpGroup group; cpSpaceBBQueryFunc func; }; static void BBQuery(struct BBQueryContext *context, cpShape *shape, void *data) { if( !(shape->group && context->group == shape->group) && (context->layers&shape->layers) && cpBBIntersects(context->bb, shape->bb) ){ context->func(shape, data); } } void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data) { struct BBQueryContext context = {bb, layers, group, func}; cpSpaceLock(space); { cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data); cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data); } cpSpaceUnlock(space, cpTrue); } //MARK: Shape Query Functions struct ShapeQueryContext { cpSpaceShapeQueryFunc func; void *data; cpBool anyCollision; }; // Callback from the spatial hash. static void ShapeQuery(cpShape *a, cpShape *b, struct ShapeQueryContext *context) { // Reject any of the simple cases if( (a->group && a->group == b->group) || !(a->layers & b->layers) || a == b ) return; cpContact contacts[CP_MAX_CONTACTS_PER_ARBITER]; int numContacts = 0; // Shape 'a' should have the lower shape type. (required by cpCollideShapes() ) if(a->klass->type <= b->klass->type){ numContacts = cpCollideShapes(a, b, contacts); } else { numContacts = cpCollideShapes(b, a, contacts); for(int i=0; ianyCollision = !(a->sensor || b->sensor); if(context->func){ cpContactPointSet set; set.count = numContacts; for(int i=0; ifunc(b, &set, context->data); } } } cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data) { cpBody *body = shape->body; cpBB bb = (body ? cpShapeUpdate(shape, body->p, body->rot) : shape->bb); struct ShapeQueryContext context = {func, data, cpFalse}; cpSpaceLock(space); { cpSpatialIndexQuery(space->activeShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context); cpSpatialIndexQuery(space->staticShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context); } cpSpaceUnlock(space, cpTrue); return context.anyCollision; } Chipmunk-6.1.5/src/cpSpaceStep.c000644 000765 000000 00000032515 12151675775 017417 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" //MARK: Post Step Callback Functions cpPostStepCallback * cpSpaceGetPostStepCallback(cpSpace *space, void *key) { cpArray *arr = space->postStepCallbacks; for(int i=0; inum; i++){ cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i]; if(callback && callback->key == key) return callback; } return NULL; } static void PostStepDoNothing(cpSpace *space, void *obj, void *data){} cpBool cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data) { cpAssertWarn(space->locked, "Adding a post-step callback when the space is not locked is unnecessary. " "Post-step callbacks will not called until the end of the next call to cpSpaceStep() or the next query."); if(!cpSpaceGetPostStepCallback(space, key)){ cpPostStepCallback *callback = (cpPostStepCallback *)cpcalloc(1, sizeof(cpPostStepCallback)); callback->func = (func ? func : PostStepDoNothing); callback->key = key; callback->data = data; cpArrayPush(space->postStepCallbacks, callback); return cpTrue; } else { return cpFalse; } } //MARK: Locking Functions void cpSpaceLock(cpSpace *space) { space->locked++; } void cpSpaceUnlock(cpSpace *space, cpBool runPostStep) { space->locked--; cpAssertHard(space->locked >= 0, "Internal Error: Space lock underflow."); if(space->locked == 0){ cpArray *waking = space->rousedBodies; for(int i=0, count=waking->num; iarr[i]); waking->arr[i] = NULL; } waking->num = 0; if(space->locked == 0 && runPostStep && !space->skipPostStep){ space->skipPostStep = cpTrue; cpArray *arr = space->postStepCallbacks; for(int i=0; inum; i++){ cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i]; cpPostStepFunc func = callback->func; // Mark the func as NULL in case calling it calls cpSpaceRunPostStepCallbacks() again. // TODO need more tests around this case I think. callback->func = NULL; if(func) func(space, callback->key, callback->data); arr->arr[i] = NULL; cpfree(callback); } arr->num = 0; space->skipPostStep = cpFalse; } } } //MARK: Contact Buffer Functions struct cpContactBufferHeader { cpTimestamp stamp; cpContactBufferHeader *next; unsigned int numContacts; }; #define CP_CONTACTS_BUFFER_SIZE ((CP_BUFFER_BYTES - sizeof(cpContactBufferHeader))/sizeof(cpContact)) typedef struct cpContactBuffer { cpContactBufferHeader header; cpContact contacts[CP_CONTACTS_BUFFER_SIZE]; } cpContactBuffer; static cpContactBufferHeader * cpSpaceAllocContactBuffer(cpSpace *space) { cpContactBuffer *buffer = (cpContactBuffer *)cpcalloc(1, sizeof(cpContactBuffer)); cpArrayPush(space->allocatedBuffers, buffer); return (cpContactBufferHeader *)buffer; } static cpContactBufferHeader * cpContactBufferHeaderInit(cpContactBufferHeader *header, cpTimestamp stamp, cpContactBufferHeader *splice) { header->stamp = stamp; header->next = (splice ? splice->next : header); header->numContacts = 0; return header; } void cpSpacePushFreshContactBuffer(cpSpace *space) { cpTimestamp stamp = space->stamp; cpContactBufferHeader *head = space->contactBuffersHead; if(!head){ // No buffers have been allocated, make one space->contactBuffersHead = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, NULL); } else if(stamp - head->next->stamp > space->collisionPersistence){ // The tail buffer is available, rotate the ring cpContactBufferHeader *tail = head->next; space->contactBuffersHead = cpContactBufferHeaderInit(tail, stamp, tail); } else { // Allocate a new buffer and push it into the ring cpContactBufferHeader *buffer = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, head); space->contactBuffersHead = head->next = buffer; } } cpContact * cpContactBufferGetArray(cpSpace *space) { if(space->contactBuffersHead->numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){ // contact buffer could overflow on the next collision, push a fresh one. cpSpacePushFreshContactBuffer(space); } cpContactBufferHeader *head = space->contactBuffersHead; return ((cpContactBuffer *)head)->contacts + head->numContacts; } void cpSpacePushContacts(cpSpace *space, int count) { cpAssertHard(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error: Contact buffer overflow!"); space->contactBuffersHead->numContacts += count; } static void cpSpacePopContacts(cpSpace *space, int count){ space->contactBuffersHead->numContacts -= count; } //MARK: Collision Detection Functions static void * cpSpaceArbiterSetTrans(cpShape **shapes, cpSpace *space) { if(space->pooledArbiters->num == 0){ // arbiter pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(cpArbiter); cpAssertHard(count, "Internal Error: Buffer size too small."); cpArbiter *buffer = (cpArbiter *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(space->allocatedBuffers, buffer); for(int i=0; ipooledArbiters, buffer + i); } return cpArbiterInit((cpArbiter *)cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]); } static inline cpBool queryReject(cpShape *a, cpShape *b) { return ( // BBoxes must overlap !cpBBIntersects(a->bb, b->bb) // Don't collide shapes attached to the same body. || a->body == b->body // Don't collide objects in the same non-zero group || (a->group && a->group == b->group) // Don't collide objects that don't share at least on layer. || !(a->layers & b->layers) // Don't collide infinite mass objects || (a->body->m == INFINITY && b->body->m == INFINITY) ); } // Callback from the spatial hash. void cpSpaceCollideShapes(cpShape *a, cpShape *b, cpSpace *space) { // Reject any of the simple cases if(queryReject(a,b)) return; cpCollisionHandler *handler = cpSpaceLookupHandler(space, a->collision_type, b->collision_type); cpBool sensor = a->sensor || b->sensor; if(sensor && handler == &cpDefaultCollisionHandler) return; // Shape 'a' should have the lower shape type. (required by cpCollideShapes() ) if(a->klass->type > b->klass->type){ cpShape *temp = a; a = b; b = temp; } // Narrow-phase collision detection. cpContact *contacts = cpContactBufferGetArray(space); int numContacts = cpCollideShapes(a, b, contacts); if(!numContacts) return; // Shapes are not colliding. cpSpacePushContacts(space, numContacts); // Get an arbiter from space->arbiterSet for the two shapes. // This is where the persistant contact magic comes from. cpShape *shape_pair[] = {a, b}; cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b); cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, space, (cpHashSetTransFunc)cpSpaceArbiterSetTrans); cpArbiterUpdate(arb, contacts, numContacts, handler, a, b); // Call the begin function first if it's the first step if(arb->state == cpArbiterStateFirstColl && !handler->begin(arb, space, handler->data)){ cpArbiterIgnore(arb); // permanently ignore the collision until separation } if( // Ignore the arbiter if it has been flagged (arb->state != cpArbiterStateIgnore) && // Call preSolve handler->preSolve(arb, space, handler->data) && // Process, but don't add collisions for sensors. !sensor ){ cpArrayPush(space->arbiters, arb); } else { cpSpacePopContacts(space, numContacts); arb->contacts = NULL; arb->numContacts = 0; // Normally arbiters are set as used after calling the post-solve callback. // However, post-solve callbacks are not called for sensors or arbiters rejected from pre-solve. if(arb->state != cpArbiterStateIgnore) arb->state = cpArbiterStateNormal; } // Time stamp the arbiter so we know it was used recently. arb->stamp = space->stamp; } // Hashset filter func to throw away old arbiters. cpBool cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space) { cpTimestamp ticks = space->stamp - arb->stamp; cpBody *a = arb->body_a, *b = arb->body_b; // TODO should make an arbiter state for this so it doesn't require filtering arbiters for dangling body pointers on body removal. // Preserve arbiters on sensors and rejected arbiters for sleeping objects. // This prevents errant separate callbacks from happenening. if( (cpBodyIsStatic(a) || cpBodyIsSleeping(a)) && (cpBodyIsStatic(b) || cpBodyIsSleeping(b)) ){ return cpTrue; } // Arbiter was used last frame, but not this one if(ticks >= 1 && arb->state != cpArbiterStateCached){ arb->state = cpArbiterStateCached; cpArbiterCallSeparate(arb, space); } if(ticks >= space->collisionPersistence){ arb->contacts = NULL; arb->numContacts = 0; cpArrayPush(space->pooledArbiters, arb); return cpFalse; } return cpTrue; } //MARK: All Important cpSpaceStep() Function void cpShapeUpdateFunc(cpShape *shape, void *unused) { cpBody *body = shape->body; cpShapeUpdate(shape, body->p, body->rot); } void cpSpaceStep(cpSpace *space, cpFloat dt) { // don't step if the timestep is 0! if(dt == 0.0f) return; space->stamp++; cpFloat prev_dt = space->curr_dt; space->curr_dt = dt; cpArray *bodies = space->bodies; cpArray *constraints = space->constraints; cpArray *arbiters = space->arbiters; // Reset and empty the arbiter lists. for(int i=0; inum; i++){ cpArbiter *arb = (cpArbiter *)arbiters->arr[i]; arb->state = cpArbiterStateNormal; // If both bodies are awake, unthread the arbiter from the contact graph. if(!cpBodyIsSleeping(arb->body_a) && !cpBodyIsSleeping(arb->body_b)){ cpArbiterUnthread(arb); } } arbiters->num = 0; cpSpaceLock(space); { // Integrate positions for(int i=0; inum; i++){ cpBody *body = (cpBody *)bodies->arr[i]; body->position_func(body, dt); } // Find colliding pairs. cpSpacePushFreshContactBuffer(space); cpSpatialIndexEach(space->activeShapes, (cpSpatialIndexIteratorFunc)cpShapeUpdateFunc, NULL); cpSpatialIndexReindexQuery(space->activeShapes, (cpSpatialIndexQueryFunc)cpSpaceCollideShapes, space); } cpSpaceUnlock(space, cpFalse); // Rebuild the contact graph (and detect sleeping components if sleeping is enabled) cpSpaceProcessComponents(space, dt); cpSpaceLock(space); { // Clear out old cached arbiters and call separate callbacks cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cpSpaceArbiterSetFilter, space); // Prestep the arbiters and constraints. cpFloat slop = space->collisionSlop; cpFloat biasCoef = 1.0f - cpfpow(space->collisionBias, dt); for(int i=0; inum; i++){ cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt, slop, biasCoef); } for(int i=0; inum; i++){ cpConstraint *constraint = (cpConstraint *)constraints->arr[i]; cpConstraintPreSolveFunc preSolve = constraint->preSolve; if(preSolve) preSolve(constraint, space); constraint->klass->preStep(constraint, dt); } // Integrate velocities. cpFloat damping = cpfpow(space->damping, dt); cpVect gravity = space->gravity; for(int i=0; inum; i++){ cpBody *body = (cpBody *)bodies->arr[i]; body->velocity_func(body, gravity, damping, dt); } // Apply cached impulses cpFloat dt_coef = (prev_dt == 0.0f ? 0.0f : dt/prev_dt); for(int i=0; inum; i++){ cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i], dt_coef); } for(int i=0; inum; i++){ cpConstraint *constraint = (cpConstraint *)constraints->arr[i]; constraint->klass->applyCachedImpulse(constraint, dt_coef); } // Run the impulse solver. for(int i=0; iiterations; i++){ for(int j=0; jnum; j++){ cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j]); } for(int j=0; jnum; j++){ cpConstraint *constraint = (cpConstraint *)constraints->arr[j]; constraint->klass->applyImpulse(constraint, dt); } } // Run the constraint post-solve callbacks for(int i=0; inum; i++){ cpConstraint *constraint = (cpConstraint *)constraints->arr[i]; cpConstraintPostSolveFunc postSolve = constraint->postSolve; if(postSolve) postSolve(constraint, space); } // run the post-solve callbacks for(int i=0; inum; i++){ cpArbiter *arb = (cpArbiter *) arbiters->arr[i]; cpCollisionHandler *handler = arb->handler; handler->postSolve(arb, space, handler->data); } } cpSpaceUnlock(space, cpTrue); } Chipmunk-6.1.5/src/cpSpatialIndex.c000644 000765 000000 00000004573 12151675775 020120 0ustar00slembckewheel000000 000000 /* Copyright (c) 2010 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" void cpSpatialIndexFree(cpSpatialIndex *index) { if(index){ cpSpatialIndexDestroy(index); cpfree(index); } } cpSpatialIndex * cpSpatialIndexInit(cpSpatialIndex *index, cpSpatialIndexClass *klass, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { index->klass = klass; index->bbfunc = bbfunc; index->staticIndex = staticIndex; if(staticIndex){ cpAssertHard(!staticIndex->dynamicIndex, "This static index is already associated with a dynamic index."); staticIndex->dynamicIndex = index; } return index; } typedef struct dynamicToStaticContext { cpSpatialIndexBBFunc bbfunc; cpSpatialIndex *staticIndex; cpSpatialIndexQueryFunc queryFunc; void *data; } dynamicToStaticContext; static void dynamicToStaticIter(void *obj, dynamicToStaticContext *context) { cpSpatialIndexQuery(context->staticIndex, obj, context->bbfunc(obj), context->queryFunc, context->data); } void cpSpatialIndexCollideStatic(cpSpatialIndex *dynamicIndex, cpSpatialIndex *staticIndex, cpSpatialIndexQueryFunc func, void *data) { if(staticIndex && cpSpatialIndexCount(staticIndex) > 0){ dynamicToStaticContext context = {dynamicIndex->bbfunc, staticIndex, func, data}; cpSpatialIndexEach(dynamicIndex, (cpSpatialIndexIteratorFunc)dynamicToStaticIter, &context); } } Chipmunk-6.1.5/src/cpSweep1D.c000644 000765 000000 00000014561 12151675775 017001 0ustar00slembckewheel000000 000000 /* Copyright (c) 2010 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" static inline cpSpatialIndexClass *Klass(); //MARK: Basic Structures typedef struct Bounds { cpFloat min, max; } Bounds; typedef struct TableCell { void *obj; Bounds bounds; } TableCell; struct cpSweep1D { cpSpatialIndex spatialIndex; int num; int max; TableCell *table; }; static inline cpBool BoundsOverlap(Bounds a, Bounds b) { return (a.min <= b.max && b.min <= a.max); } static inline Bounds BBToBounds(cpSweep1D *sweep, cpBB bb) { Bounds bounds = {bb.l, bb.r}; return bounds; } static inline TableCell MakeTableCell(cpSweep1D *sweep, void *obj) { TableCell cell = {obj, BBToBounds(sweep, sweep->spatialIndex.bbfunc(obj))}; return cell; } //MARK: Memory Management Functions cpSweep1D * cpSweep1DAlloc(void) { return (cpSweep1D *)cpcalloc(1, sizeof(cpSweep1D)); } static void ResizeTable(cpSweep1D *sweep, int size) { sweep->max = size; sweep->table = (TableCell *)cprealloc(sweep->table, size*sizeof(TableCell)); } cpSpatialIndex * cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { cpSpatialIndexInit((cpSpatialIndex *)sweep, Klass(), bbfunc, staticIndex); sweep->num = 0; ResizeTable(sweep, 32); return (cpSpatialIndex *)sweep; } cpSpatialIndex * cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { return cpSweep1DInit(cpSweep1DAlloc(), bbfunc, staticIndex); } static void cpSweep1DDestroy(cpSweep1D *sweep) { cpfree(sweep->table); sweep->table = NULL; } //MARK: Misc static int cpSweep1DCount(cpSweep1D *sweep) { return sweep->num; } static void cpSweep1DEach(cpSweep1D *sweep, cpSpatialIndexIteratorFunc func, void *data) { TableCell *table = sweep->table; for(int i=0, count=sweep->num; itable; for(int i=0, count=sweep->num; inum == sweep->max) ResizeTable(sweep, sweep->max*2); sweep->table[sweep->num] = MakeTableCell(sweep, obj); sweep->num++; } static void cpSweep1DRemove(cpSweep1D *sweep, void *obj, cpHashValue hashid) { TableCell *table = sweep->table; for(int i=0, count=sweep->num; inum; table[i] = table[num]; table[num].obj = NULL; return; } } } //MARK: Reindexing Functions static void cpSweep1DReindexObject(cpSweep1D *sweep, void *obj, cpHashValue hashid) { // Nothing to do here } static void cpSweep1DReindex(cpSweep1D *sweep) { // Nothing to do here // Could perform a sort, but queries are not accelerated anyway. } //MARK: Query Functions static void cpSweep1DQuery(cpSweep1D *sweep, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data) { // Implementing binary search here would allow you to find an upper limit // but not a lower limit. Probably not worth the hassle. Bounds bounds = BBToBounds(sweep, bb); TableCell *table = sweep->table; for(int i=0, count=sweep->num; itable; for(int i=0, count=sweep->num; ibounds.min < b->bounds.min ? -1 : (a->bounds.min > b->bounds.min ? 1 : 0)); } static void cpSweep1DReindexQuery(cpSweep1D *sweep, cpSpatialIndexQueryFunc func, void *data) { TableCell *table = sweep->table; int count = sweep->num; // Update bounds and sort for(int i=0; ispatialIndex.staticIndex, func, data); } static cpSpatialIndexClass klass = { (cpSpatialIndexDestroyImpl)cpSweep1DDestroy, (cpSpatialIndexCountImpl)cpSweep1DCount, (cpSpatialIndexEachImpl)cpSweep1DEach, (cpSpatialIndexContainsImpl)cpSweep1DContains, (cpSpatialIndexInsertImpl)cpSweep1DInsert, (cpSpatialIndexRemoveImpl)cpSweep1DRemove, (cpSpatialIndexReindexImpl)cpSweep1DReindex, (cpSpatialIndexReindexObjectImpl)cpSweep1DReindexObject, (cpSpatialIndexReindexQueryImpl)cpSweep1DReindexQuery, (cpSpatialIndexQueryImpl)cpSweep1DQuery, (cpSpatialIndexSegmentQueryImpl)cpSweep1DSegmentQuery, }; static inline cpSpatialIndexClass *Klass(){return &klass;} Chipmunk-6.1.5/src/cpVect.c000644 000765 000000 00000003722 12151675775 016427 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include "chipmunk_private.h" cpVect cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t) { cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2)); cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f)); if(omega < 1e-3){ // If the angle between two vectors is very small, lerp instead to avoid precision issues. return cpvlerp(v1, v2, t); } else { cpFloat denom = 1.0f/cpfsin(omega); return cpvadd(cpvmult(v1, cpfsin((1.0f - t)*omega)*denom), cpvmult(v2, cpfsin(t*omega)*denom)); } } cpVect cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a) { cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2)); cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f)); return cpvslerp(v1, v2, cpfmin(a, omega)/omega); } char* cpvstr(const cpVect v) { static char str[256]; sprintf(str, "(% .3f, % .3f)", v.x, v.y); return str; } Chipmunk-6.1.5/src/prime.h000644 000765 000000 00000003354 12151675775 016325 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // Used for resizing hash tables. // Values approximately double. // http://planetmath.org/encyclopedia/GoodHashTablePrimes.html static int primes[] = { 5, 13, 23, 47, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 0, }; static inline int next_prime(int n) { int i = 0; while(n > primes[i]){ i++; cpAssertHard(primes[i], "Tried to resize a hash table to a size greater than 1610612741 O_o"); // realistically this should never happen } return primes[i]; } Chipmunk-6.1.5/src/constraints/cpConstraint.c000644 000765 000000 00000003601 12151675775 022215 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" // TODO: Comment me! void cpConstraintDestroy(cpConstraint *constraint){} void cpConstraintFree(cpConstraint *constraint) { if(constraint){ cpConstraintDestroy(constraint); cpfree(constraint); } } // *** declared in util.h TODO move declaration to chipmunk_private.h void cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b) { constraint->klass = klass; constraint->a = a; constraint->b = b; constraint->space = NULL; constraint->next_a = NULL; constraint->next_b = NULL; constraint->maxForce = (cpFloat)INFINITY; constraint->errorBias = cpfpow(1.0f - 0.1f, 60.0f); constraint->maxBias = (cpFloat)INFINITY; constraint->preSolve = NULL; constraint->postSolve = NULL; } Chipmunk-6.1.5/src/constraints/cpDampedRotarySpring.c000644 000765 000000 00000007325 12151675775 023656 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static cpFloat defaultSpringTorque(cpDampedRotarySpring *spring, cpFloat relativeAngle){ return (relativeAngle - spring->restAngle)*spring->stiffness; } static void preStep(cpDampedRotarySpring *spring, cpFloat dt) { cpBody *a = spring->constraint.a; cpBody *b = spring->constraint.b; cpFloat moment = a->i_inv + b->i_inv; cpAssertSoft(moment != 0.0, "Unsolvable spring."); spring->iSum = 1.0f/moment; spring->w_coef = 1.0f - cpfexp(-spring->damping*dt*moment); spring->target_wrn = 0.0f; // apply spring torque cpFloat j_spring = spring->springTorqueFunc((cpConstraint *)spring, a->a - b->a)*dt; spring->jAcc = j_spring; a->w -= j_spring*a->i_inv; b->w += j_spring*b->i_inv; } static void applyCachedImpulse(cpDampedRotarySpring *spring, cpFloat dt_coef){} static void applyImpulse(cpDampedRotarySpring *spring, cpFloat dt) { cpBody *a = spring->constraint.a; cpBody *b = spring->constraint.b; // compute relative velocity cpFloat wrn = a->w - b->w;//normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn; // compute velocity loss from drag // not 100% certain this is derived correctly, though it makes sense cpFloat w_damp = (spring->target_wrn - wrn)*spring->w_coef; spring->target_wrn = wrn + w_damp; //apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass)); cpFloat j_damp = w_damp*spring->iSum; spring->jAcc += j_damp; a->w += j_damp*a->i_inv; b->w -= j_damp*b->i_inv; } static cpFloat getImpulse(cpDampedRotarySpring *spring) { return spring->jAcc; } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpDampedRotarySpring) cpDampedRotarySpring * cpDampedRotarySpringAlloc(void) { return (cpDampedRotarySpring *)cpcalloc(1, sizeof(cpDampedRotarySpring)); } cpDampedRotarySpring * cpDampedRotarySpringInit(cpDampedRotarySpring *spring, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping) { cpConstraintInit((cpConstraint *)spring, &klass, a, b); spring->restAngle = restAngle; spring->stiffness = stiffness; spring->damping = damping; spring->springTorqueFunc = (cpDampedRotarySpringTorqueFunc)defaultSpringTorque; spring->jAcc = 0.0f; return spring; } cpConstraint * cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping) { return (cpConstraint *)cpDampedRotarySpringInit(cpDampedRotarySpringAlloc(), a, b, restAngle, stiffness, damping); } Chipmunk-6.1.5/src/constraints/cpDampedSpring.c000644 000765 000000 00000007710 12151675775 022453 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static cpFloat defaultSpringForce(cpDampedSpring *spring, cpFloat dist){ return (spring->restLength - dist)*spring->stiffness; } static void preStep(cpDampedSpring *spring, cpFloat dt) { cpBody *a = spring->constraint.a; cpBody *b = spring->constraint.b; spring->r1 = cpvrotate(spring->anchr1, a->rot); spring->r2 = cpvrotate(spring->anchr2, b->rot); cpVect delta = cpvsub(cpvadd(b->p, spring->r2), cpvadd(a->p, spring->r1)); cpFloat dist = cpvlength(delta); spring->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY)); cpFloat k = k_scalar(a, b, spring->r1, spring->r2, spring->n); cpAssertSoft(k != 0.0, "Unsolvable spring."); spring->nMass = 1.0f/k; spring->target_vrn = 0.0f; spring->v_coef = 1.0f - cpfexp(-spring->damping*dt*k); // apply spring force cpFloat f_spring = spring->springForceFunc((cpConstraint *)spring, dist); cpFloat j_spring = spring->jAcc = f_spring*dt; apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, j_spring)); } static void applyCachedImpulse(cpDampedSpring *spring, cpFloat dt_coef){} static void applyImpulse(cpDampedSpring *spring, cpFloat dt) { cpBody *a = spring->constraint.a; cpBody *b = spring->constraint.b; cpVect n = spring->n; cpVect r1 = spring->r1; cpVect r2 = spring->r2; // compute relative velocity cpFloat vrn = normal_relative_velocity(a, b, r1, r2, n); // compute velocity loss from drag cpFloat v_damp = (spring->target_vrn - vrn)*spring->v_coef; spring->target_vrn = vrn + v_damp; cpFloat j_damp = v_damp*spring->nMass; spring->jAcc += j_damp; apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, j_damp)); } static cpFloat getImpulse(cpDampedSpring *spring) { return spring->jAcc; } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpDampedSpring) cpDampedSpring * cpDampedSpringAlloc(void) { return (cpDampedSpring *)cpcalloc(1, sizeof(cpDampedSpring)); } cpDampedSpring * cpDampedSpringInit(cpDampedSpring *spring, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping) { cpConstraintInit((cpConstraint *)spring, cpDampedSpringGetClass(), a, b); spring->anchr1 = anchr1; spring->anchr2 = anchr2; spring->restLength = restLength; spring->stiffness = stiffness; spring->damping = damping; spring->springForceFunc = (cpDampedSpringForceFunc)defaultSpringForce; spring->jAcc = 0.0f; return spring; } cpConstraint * cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping) { return (cpConstraint *)cpDampedSpringInit(cpDampedSpringAlloc(), a, b, anchr1, anchr2, restLength, stiffness, damping); } Chipmunk-6.1.5/src/constraints/cpGearJoint.c000644 000765 000000 00000006717 12151675775 021766 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpGearJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; // calculate moment of inertia coefficient. joint->iSum = 1.0f/(a->i_inv*joint->ratio_inv + joint->ratio*b->i_inv); // calculate bias velocity cpFloat maxBias = joint->constraint.maxBias; joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*(b->a*joint->ratio - a->a - joint->phase)/dt, -maxBias, maxBias); } static void applyCachedImpulse(cpGearJoint *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpFloat j = joint->jAcc*dt_coef; a->w -= j*a->i_inv*joint->ratio_inv; b->w += j*b->i_inv; } static void applyImpulse(cpGearJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; // compute relative rotational velocity cpFloat wr = b->w*joint->ratio - a->w; cpFloat jMax = joint->constraint.maxForce*dt; // compute normal impulse cpFloat j = (joint->bias - wr)*joint->iSum; cpFloat jOld = joint->jAcc; joint->jAcc = cpfclamp(jOld + j, -jMax, jMax); j = joint->jAcc - jOld; // apply impulse a->w -= j*a->i_inv*joint->ratio_inv; b->w += j*b->i_inv; } static cpFloat getImpulse(cpGearJoint *joint) { return cpfabs(joint->jAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpGearJoint) cpGearJoint * cpGearJointAlloc(void) { return (cpGearJoint *)cpcalloc(1, sizeof(cpGearJoint)); } cpGearJoint * cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->phase = phase; joint->ratio = ratio; joint->ratio_inv = 1.0f/ratio; joint->jAcc = 0.0f; return joint; } cpConstraint * cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio) { return (cpConstraint *)cpGearJointInit(cpGearJointAlloc(), a, b, phase, ratio); } void cpGearJointSetRatio(cpConstraint *constraint, cpFloat value) { cpConstraintCheckCast(constraint, cpGearJoint); ((cpGearJoint *)constraint)->ratio = value; ((cpGearJoint *)constraint)->ratio_inv = 1.0f/value; cpConstraintActivateBodies(constraint); } Chipmunk-6.1.5/src/constraints/cpGrooveJoint.c000644 000765 000000 00000011517 12151675775 022343 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpGrooveJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; // calculate endpoints in worldspace cpVect ta = cpBodyLocal2World(a, joint->grv_a); cpVect tb = cpBodyLocal2World(a, joint->grv_b); // calculate axis cpVect n = cpvrotate(joint->grv_n, a->rot); cpFloat d = cpvdot(ta, n); joint->grv_tn = n; joint->r2 = cpvrotate(joint->anchr2, b->rot); // calculate tangential distance along the axis of r2 cpFloat td = cpvcross(cpvadd(b->p, joint->r2), n); // calculate clamping factor and r2 if(td <= cpvcross(ta, n)){ joint->clamp = 1.0f; joint->r1 = cpvsub(ta, a->p); } else if(td >= cpvcross(tb, n)){ joint->clamp = -1.0f; joint->r1 = cpvsub(tb, a->p); } else { joint->clamp = 0.0f; joint->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p); } // Calculate mass tensor joint->k = k_tensor(a, b, joint->r1, joint->r2); // calculate bias velocity cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1)); joint->bias = cpvclamp(cpvmult(delta, -bias_coef(joint->constraint.errorBias, dt)/dt), joint->constraint.maxBias); } static void applyCachedImpulse(cpGrooveJoint *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; apply_impulses(a, b, joint->r1, joint->r2, cpvmult(joint->jAcc, dt_coef)); } static inline cpVect grooveConstrain(cpGrooveJoint *joint, cpVect j, cpFloat dt){ cpVect n = joint->grv_tn; cpVect jClamp = (joint->clamp*cpvcross(j, n) > 0.0f) ? j : cpvproject(j, n); return cpvclamp(jClamp, joint->constraint.maxForce*dt); } static void applyImpulse(cpGrooveJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpVect r1 = joint->r1; cpVect r2 = joint->r2; // compute impulse cpVect vr = relative_velocity(a, b, r1, r2); cpVect j = cpMat2x2Transform(joint->k, cpvsub(joint->bias, vr)); cpVect jOld = joint->jAcc; joint->jAcc = grooveConstrain(joint, cpvadd(jOld, j), dt); j = cpvsub(joint->jAcc, jOld); // apply impulse apply_impulses(a, b, joint->r1, joint->r2, j); } static cpFloat getImpulse(cpGrooveJoint *joint) { return cpvlength(joint->jAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpGrooveJoint) cpGrooveJoint * cpGrooveJointAlloc(void) { return (cpGrooveJoint *)cpcalloc(1, sizeof(cpGrooveJoint)); } cpGrooveJoint * cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->grv_a = groove_a; joint->grv_b = groove_b; joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a))); joint->anchr2 = anchr2; joint->jAcc = cpvzero; return joint; } cpConstraint * cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2) { return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2); } void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value) { cpGrooveJoint *g = (cpGrooveJoint *)constraint; cpConstraintCheckCast(constraint, cpGrooveJoint); g->grv_a = value; g->grv_n = cpvperp(cpvnormalize(cpvsub(g->grv_b, value))); cpConstraintActivateBodies(constraint); } void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value) { cpGrooveJoint *g = (cpGrooveJoint *)constraint; cpConstraintCheckCast(constraint, cpGrooveJoint); g->grv_b = value; g->grv_n = cpvperp(cpvnormalize(cpvsub(value, g->grv_a))); cpConstraintActivateBodies(constraint); } Chipmunk-6.1.5/src/constraints/cpPinJoint.c000644 000765 000000 00000007410 12151675775 021625 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpPinJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; joint->r1 = cpvrotate(joint->anchr1, a->rot); joint->r2 = cpvrotate(joint->anchr2, b->rot); cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1)); cpFloat dist = cpvlength(delta); joint->n = cpvmult(delta, 1.0f/(dist ? dist : (cpFloat)INFINITY)); // calculate mass normal joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n); // calculate bias velocity cpFloat maxBias = joint->constraint.maxBias; joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*(dist - joint->dist)/dt, -maxBias, maxBias); } static void applyCachedImpulse(cpPinJoint *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpVect j = cpvmult(joint->n, joint->jnAcc*dt_coef); apply_impulses(a, b, joint->r1, joint->r2, j); } static void applyImpulse(cpPinJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpVect n = joint->n; // compute relative velocity cpFloat vrn = normal_relative_velocity(a, b, joint->r1, joint->r2, n); cpFloat jnMax = joint->constraint.maxForce*dt; // compute normal impulse cpFloat jn = (joint->bias - vrn)*joint->nMass; cpFloat jnOld = joint->jnAcc; joint->jnAcc = cpfclamp(jnOld + jn, -jnMax, jnMax); jn = joint->jnAcc - jnOld; // apply impulse apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn)); } static cpFloat getImpulse(cpPinJoint *joint) { return cpfabs(joint->jnAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpPinJoint) cpPinJoint * cpPinJointAlloc(void) { return (cpPinJoint *)cpcalloc(1, sizeof(cpPinJoint)); } cpPinJoint * cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->anchr1 = anchr1; joint->anchr2 = anchr2; // STATIC_BODY_CHECK cpVect p1 = (a ? cpvadd(a->p, cpvrotate(anchr1, a->rot)) : anchr1); cpVect p2 = (b ? cpvadd(b->p, cpvrotate(anchr2, b->rot)) : anchr2); joint->dist = cpvlength(cpvsub(p2, p1)); cpAssertWarn(joint->dist > 0.0, "You created a 0 length pin joint. A pivot joint will be much more stable."); joint->jnAcc = 0.0f; return joint; } cpConstraint * cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2) { return (cpConstraint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchr1, anchr2); } Chipmunk-6.1.5/src/constraints/cpPivotJoint.c000644 000765 000000 00000007045 12151675775 022204 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpPivotJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; joint->r1 = cpvrotate(joint->anchr1, a->rot); joint->r2 = cpvrotate(joint->anchr2, b->rot); // Calculate mass tensor joint-> k = k_tensor(a, b, joint->r1, joint->r2); // calculate bias velocity cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1)); joint->bias = cpvclamp(cpvmult(delta, -bias_coef(joint->constraint.errorBias, dt)/dt), joint->constraint.maxBias); } static void applyCachedImpulse(cpPivotJoint *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; apply_impulses(a, b, joint->r1, joint->r2, cpvmult(joint->jAcc, dt_coef)); } static void applyImpulse(cpPivotJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpVect r1 = joint->r1; cpVect r2 = joint->r2; // compute relative velocity cpVect vr = relative_velocity(a, b, r1, r2); // compute normal impulse cpVect j = cpMat2x2Transform(joint->k, cpvsub(joint->bias, vr)); cpVect jOld = joint->jAcc; joint->jAcc = cpvclamp(cpvadd(joint->jAcc, j), joint->constraint.maxForce*dt); j = cpvsub(joint->jAcc, jOld); // apply impulse apply_impulses(a, b, joint->r1, joint->r2, j); } static cpFloat getImpulse(cpConstraint *joint) { return cpvlength(((cpPivotJoint *)joint)->jAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpPivotJoint) cpPivotJoint * cpPivotJointAlloc(void) { return (cpPivotJoint *)cpcalloc(1, sizeof(cpPivotJoint)); } cpPivotJoint * cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->anchr1 = anchr1; joint->anchr2 = anchr2; joint->jAcc = cpvzero; return joint; } cpConstraint * cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2) { return (cpConstraint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, anchr1, anchr2); } cpConstraint * cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot) { cpVect anchr1 = (a ? cpBodyWorld2Local(a, pivot) : pivot); cpVect anchr2 = (b ? cpBodyWorld2Local(b, pivot) : pivot); return cpPivotJointNew2(a, b, anchr1, anchr2); } Chipmunk-6.1.5/src/constraints/cpRatchetJoint.c000644 000765 000000 00000007320 12151675775 022471 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpRatchetJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpFloat angle = joint->angle; cpFloat phase = joint->phase; cpFloat ratchet = joint->ratchet; cpFloat delta = b->a - a->a; cpFloat diff = angle - delta; cpFloat pdist = 0.0f; if(diff*ratchet > 0.0f){ pdist = diff; } else { joint->angle = cpffloor((delta - phase)/ratchet)*ratchet + phase; } // calculate moment of inertia coefficient. joint->iSum = 1.0f/(a->i_inv + b->i_inv); // calculate bias velocity cpFloat maxBias = joint->constraint.maxBias; joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias); // If the bias is 0, the joint is not at a limit. Reset the impulse. if(!joint->bias) joint->jAcc = 0.0f; } static void applyCachedImpulse(cpRatchetJoint *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpFloat j = joint->jAcc*dt_coef; a->w -= j*a->i_inv; b->w += j*b->i_inv; } static void applyImpulse(cpRatchetJoint *joint, cpFloat dt) { if(!joint->bias) return; // early exit cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; // compute relative rotational velocity cpFloat wr = b->w - a->w; cpFloat ratchet = joint->ratchet; cpFloat jMax = joint->constraint.maxForce*dt; // compute normal impulse cpFloat j = -(joint->bias + wr)*joint->iSum; cpFloat jOld = joint->jAcc; joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, jMax*cpfabs(ratchet))/ratchet; j = joint->jAcc - jOld; // apply impulse a->w -= j*a->i_inv; b->w += j*b->i_inv; } static cpFloat getImpulse(cpRatchetJoint *joint) { return cpfabs(joint->jAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpRatchetJoint) cpRatchetJoint * cpRatchetJointAlloc(void) { return (cpRatchetJoint *)cpcalloc(1, sizeof(cpRatchetJoint)); } cpRatchetJoint * cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->angle = 0.0f; joint->phase = phase; joint->ratchet = ratchet; // STATIC_BODY_CHECK joint->angle = (b ? b->a : 0.0f) - (a ? a->a : 0.0f); return joint; } cpConstraint * cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet) { return (cpConstraint *)cpRatchetJointInit(cpRatchetJointAlloc(), a, b, phase, ratchet); } Chipmunk-6.1.5/src/constraints/cpRotaryLimitJoint.c000644 000765 000000 00000007054 12151675775 023362 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpRotaryLimitJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpFloat dist = b->a - a->a; cpFloat pdist = 0.0f; if(dist > joint->max) { pdist = joint->max - dist; } else if(dist < joint->min) { pdist = joint->min - dist; } // calculate moment of inertia coefficient. joint->iSum = 1.0f/(1.0f/a->i + 1.0f/b->i); // calculate bias velocity cpFloat maxBias = joint->constraint.maxBias; joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias); // If the bias is 0, the joint is not at a limit. Reset the impulse. if(!joint->bias) joint->jAcc = 0.0f; } static void applyCachedImpulse(cpRotaryLimitJoint *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpFloat j = joint->jAcc*dt_coef; a->w -= j*a->i_inv; b->w += j*b->i_inv; } static void applyImpulse(cpRotaryLimitJoint *joint, cpFloat dt) { if(!joint->bias) return; // early exit cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; // compute relative rotational velocity cpFloat wr = b->w - a->w; cpFloat jMax = joint->constraint.maxForce*dt; // compute normal impulse cpFloat j = -(joint->bias + wr)*joint->iSum; cpFloat jOld = joint->jAcc; if(joint->bias < 0.0f){ joint->jAcc = cpfclamp(jOld + j, 0.0f, jMax); } else { joint->jAcc = cpfclamp(jOld + j, -jMax, 0.0f); } j = joint->jAcc - jOld; // apply impulse a->w -= j*a->i_inv; b->w += j*b->i_inv; } static cpFloat getImpulse(cpRotaryLimitJoint *joint) { return cpfabs(joint->jAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpRotaryLimitJoint) cpRotaryLimitJoint * cpRotaryLimitJointAlloc(void) { return (cpRotaryLimitJoint *)cpcalloc(1, sizeof(cpRotaryLimitJoint)); } cpRotaryLimitJoint * cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->min = min; joint->max = max; joint->jAcc = 0.0f; return joint; } cpConstraint * cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max) { return (cpConstraint *)cpRotaryLimitJointInit(cpRotaryLimitJointAlloc(), a, b, min, max); } Chipmunk-6.1.5/src/constraints/cpSimpleMotor.c000644 000765 000000 00000005550 12151675775 022350 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpSimpleMotor *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; // calculate moment of inertia coefficient. joint->iSum = 1.0f/(a->i_inv + b->i_inv); } static void applyCachedImpulse(cpSimpleMotor *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpFloat j = joint->jAcc*dt_coef; a->w -= j*a->i_inv; b->w += j*b->i_inv; } static void applyImpulse(cpSimpleMotor *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; // compute relative rotational velocity cpFloat wr = b->w - a->w + joint->rate; cpFloat jMax = joint->constraint.maxForce*dt; // compute normal impulse cpFloat j = -wr*joint->iSum; cpFloat jOld = joint->jAcc; joint->jAcc = cpfclamp(jOld + j, -jMax, jMax); j = joint->jAcc - jOld; // apply impulse a->w -= j*a->i_inv; b->w += j*b->i_inv; } static cpFloat getImpulse(cpSimpleMotor *joint) { return cpfabs(joint->jAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpSimpleMotor) cpSimpleMotor * cpSimpleMotorAlloc(void) { return (cpSimpleMotor *)cpcalloc(1, sizeof(cpSimpleMotor)); } cpSimpleMotor * cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->rate = rate; joint->jAcc = 0.0f; return joint; } cpConstraint * cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate) { return (cpConstraint *)cpSimpleMotorInit(cpSimpleMotorAlloc(), a, b, rate); } Chipmunk-6.1.5/src/constraints/cpSlideJoint.c000644 000765 000000 00000007572 12151675775 022150 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "constraints/util.h" static void preStep(cpSlideJoint *joint, cpFloat dt) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; joint->r1 = cpvrotate(joint->anchr1, a->rot); joint->r2 = cpvrotate(joint->anchr2, b->rot); cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1)); cpFloat dist = cpvlength(delta); cpFloat pdist = 0.0f; if(dist > joint->max) { pdist = dist - joint->max; joint->n = cpvnormalize_safe(delta); } else if(dist < joint->min) { pdist = joint->min - dist; joint->n = cpvneg(cpvnormalize_safe(delta)); } else { joint->n = cpvzero; joint->jnAcc = 0.0f; } // calculate mass normal joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n); // calculate bias velocity cpFloat maxBias = joint->constraint.maxBias; joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias); } static void applyCachedImpulse(cpSlideJoint *joint, cpFloat dt_coef) { cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpVect j = cpvmult(joint->n, joint->jnAcc*dt_coef); apply_impulses(a, b, joint->r1, joint->r2, j); } static void applyImpulse(cpSlideJoint *joint, cpFloat dt) { if(cpveql(joint->n, cpvzero)) return; // early exit cpBody *a = joint->constraint.a; cpBody *b = joint->constraint.b; cpVect n = joint->n; cpVect r1 = joint->r1; cpVect r2 = joint->r2; // compute relative velocity cpVect vr = relative_velocity(a, b, r1, r2); cpFloat vrn = cpvdot(vr, n); // compute normal impulse cpFloat jn = (joint->bias - vrn)*joint->nMass; cpFloat jnOld = joint->jnAcc; joint->jnAcc = cpfclamp(jnOld + jn, -joint->constraint.maxForce*dt, 0.0f); jn = joint->jnAcc - jnOld; // apply impulse apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn)); } static cpFloat getImpulse(cpConstraint *joint) { return cpfabs(((cpSlideJoint *)joint)->jnAcc); } static const cpConstraintClass klass = { (cpConstraintPreStepImpl)preStep, (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse, (cpConstraintApplyImpulseImpl)applyImpulse, (cpConstraintGetImpulseImpl)getImpulse, }; CP_DefineClassGetter(cpSlideJoint) cpSlideJoint * cpSlideJointAlloc(void) { return (cpSlideJoint *)cpcalloc(1, sizeof(cpSlideJoint)); } cpSlideJoint * cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max) { cpConstraintInit((cpConstraint *)joint, &klass, a, b); joint->anchr1 = anchr1; joint->anchr2 = anchr2; joint->min = min; joint->max = max; joint->jnAcc = 0.0f; return joint; } cpConstraint * cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max) { return (cpConstraint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max); } Chipmunk-6.1.5/msvc/glut/000755 000765 000000 00000000000 12151675775 016167 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/readme.txt000644 000765 000000 00000001170 12151675775 017211 0ustar00slembckewheel000000 000000 This subdirectory contains project and solution files for building the Chipmunk Physics library and its demo suite with Microsoft Visual C++ 2010. The demo suite uses the external GLUT (OpenGL Utility Toolkit) library, included in the glut subdirectory. Here's how the Chipmunk and C runtime libraries are linked for each of the available configurations: Chipmunk C Runtime Debug Static Dynamic Debug DLL Dynamic Dynamic Debug SCRT Static Static Release Static Dynamic Release DLL Dynamic Dynamic Release SCRT Static Static Chipmunk-6.1.5/msvc/vc10/000755 000765 000000 00000000000 12151675775 015765 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/vc10/chipmunk/000755 000765 000000 00000000000 12151675775 017603 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/vc10/demo/000755 000765 000000 00000000000 12151675775 016711 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/vc10/demo/demo.sln000644 000765 000000 00000005463 12151675775 020363 0ustar00slembckewheel000000 000000  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual C++ Express 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo", "demo.vcxproj", "{659CE82A-959E-46C0-ACCC-A3BE0A0CB860}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chipmunk", "..\chipmunk\chipmunk.vcxproj", "{C1ACE86E-5A14-490A-9678-104BA2546723}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug DLL|Win32 = Debug DLL|Win32 Debug SCRT|Win32 = Debug SCRT|Win32 Debug|Win32 = Debug|Win32 Release DLL|Win32 = Release DLL|Win32 Release SCRT|Win32 = Release SCRT|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Debug DLL|Win32.Build.0 = Debug DLL|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Debug SCRT|Win32.ActiveCfg = Debug SCRT|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Debug SCRT|Win32.Build.0 = Debug SCRT|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Debug|Win32.ActiveCfg = Debug|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Debug|Win32.Build.0 = Debug|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Release DLL|Win32.Build.0 = Release DLL|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Release SCRT|Win32.ActiveCfg = Release SCRT|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Release SCRT|Win32.Build.0 = Release SCRT|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Release|Win32.ActiveCfg = Release|Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860}.Release|Win32.Build.0 = Release|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Debug DLL|Win32.ActiveCfg = Debug DLL|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Debug DLL|Win32.Build.0 = Debug DLL|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Debug SCRT|Win32.ActiveCfg = Debug SCRT|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Debug SCRT|Win32.Build.0 = Debug SCRT|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Debug|Win32.ActiveCfg = Debug|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Debug|Win32.Build.0 = Debug|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Release DLL|Win32.ActiveCfg = Release DLL|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Release DLL|Win32.Build.0 = Release DLL|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Release SCRT|Win32.ActiveCfg = Release SCRT|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Release SCRT|Win32.Build.0 = Release SCRT|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Release|Win32.ActiveCfg = Release|Win32 {C1ACE86E-5A14-490A-9678-104BA2546723}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal Chipmunk-6.1.5/msvc/vc10/demo/demo.vcxproj000644 000765 000000 00000025717 12151675775 021266 0ustar00slembckewheel000000 000000  Debug SCRT Win32 Debug DLL Win32 Debug Win32 Release SCRT Win32 Release DLL Win32 Release Win32 {659CE82A-959E-46C0-ACCC-A3BE0A0CB860} Win32Proj demo true true true false true false true false true true $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ true $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ true $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ false $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ false $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ false $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\..\..\include\chipmunk;..\..\glut\include CompileAsCpp Console true ..\..\glut\lib Level3 Disabled _CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\..\..\include\chipmunk;..\..\glut\include MultiThreadedDebug CompileAsCpp Console true ..\..\glut\lib Level3 Disabled _CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\..\..\include\chipmunk;..\..\glut\include CompileAsCpp Console true ..\..\glut\lib Level3 MaxSpeed true _CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\..\..\include\chipmunk;..\..\glut\include CompileAsCpp Console true true ..\..\glut\lib true Level3 MaxSpeed true _CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\..\..\include\chipmunk;..\..\glut\include MultiThreaded CompileAsCpp Console true true ..\..\glut\lib true Level3 MaxSpeed true _CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\..\..\include\chipmunk;..\..\glut\include CompileAsCpp Console true true ..\..\glut\lib true {c1ace86e-5a14-490a-9678-104ba2546723} Chipmunk-6.1.5/msvc/vc10/demo/demo.vcxproj.filters000644 000765 000000 00000006551 12151675775 022730 0ustar00slembckewheel000000 000000  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files Chipmunk-6.1.5/msvc/vc10/demo/demo.vcxproj.user000644 000765 000000 00000003245 12151675775 022233 0ustar00slembckewheel000000 000000  PATH=%PATH%;..\chipmunk\$(PlatformName)\$(Configuration);..\..\glut\runtime WindowsLocalDebugger PATH=%PATH%;..\chipmunk\$(PlatformName)\$(Configuration);..\..\glut\runtime WindowsLocalDebugger PATH=%PATH%;..\..\glut\runtime WindowsLocalDebugger PATH=%PATH%;..\..\glut\runtime WindowsLocalDebugger PATH=%PATH%;..\..\glut\runtime WindowsLocalDebugger PATH=%PATH%;..\..\glut\runtime WindowsLocalDebugger Chipmunk-6.1.5/msvc/vc10/chipmunk/chipmunk.def000644 000765 000000 00000005265 12151675775 022111 0ustar00slembckewheel000000 000000 LIBRARY chipmunk EXPORTS cpArbiterGetContactPointSet cpArbiterGetCount cpArbiterGetDepth cpArbiterGetNormal cpArbiterGetPoint cpArbiterIgnore cpArbiterIsFirstContact cpArbiterTotalImpulse cpArbiterTotalImpulseWithFriction cpArbiterTotalKE cpAreaForPoly cpBBTreeAlloc cpBBTreeInit cpBBTreeNew cpBBTreeOptimize cpBBTreeSetVelocityFunc cpBBWrapVect cpBodyActivate cpBodyActivateStatic cpBodyAlloc cpBodyDestroy cpBodyEachArbiter cpBodyFree cpBodyGetVelAtWorldPoint cpBodyInit cpBodyInitStatic cpBodyNew cpBodyNewStatic cpBodySanityCheck cpBodySetAngle cpBodySetMass cpBodySetMoment cpBodySetPos cpBodySleep cpBodySleepWithGroup cpBodyUpdatePosition cpBodyUpdateVelocity cpBoxShapeInit cpBoxShapeInit2 cpBoxShapeNew cpBoxShapeNew2 cpCentroidForPoly cpCircleShapeAlloc cpCircleShapeInit cpCircleShapeNew cpConstraintFree cpConvexHull cpDampedRotarySpringNew cpDampedSpringGetClass cpDampedSpringNew cpGearJointNew cpGrooveJointGetClass cpGrooveJointNew cpMessage cpMomentForBox cpMomentForBox2 cpMomentForCircle cpMomentForPoly cpMomentForSegment cpPinJointGetClass cpPinJointNew cpPivotJointGetClass cpPivotJointNew cpPivotJointNew2 cpPolyShapeAlloc cpPolyShapeGetNumVerts cpPolyShapeGetVert cpPolyShapeInit cpPolyShapeNew cpPolyShapeSetVerts cpPolyValidate cpRatchetJointNew cpResetShapeIdCounter cpRotaryLimitJointNew cpSegmentShapeAlloc cpSegmentShapeInit cpSegmentShapeNew cpSegmentShapeSetNeighbors cpShapeCacheBB cpShapeDestroy cpShapeFree cpShapeNearestPointQuery cpShapePointQuery cpShapeSegmentQuery cpShapeSetBody cpShapeUpdate cpSimpleMotorGetClass cpSimpleMotorNew cpSlideJointGetClass cpSlideJointNew cpSpaceActivateShapesTouchingShape cpSpaceAddBody cpSpaceAddCollisionHandler cpSpaceAddConstraint cpSpaceAddPostStepCallback cpSpaceAddShape cpSpaceAddStaticShape cpSpaceAlloc cpSpaceBBQuery cpSpaceContainsBody cpSpaceContainsConstraint cpSpaceContainsShape cpSpaceDestroy cpSpaceEachBody cpSpaceEachConstraint cpSpaceEachShape cpSpaceFree cpSpaceInit cpSpaceNearestPointQuery cpSpaceNearestPointQueryNearest cpSpaceNew cpSpacePointQuery cpSpacePointQueryFirst cpSpaceReindexShape cpSpaceReindexShapesForBody cpSpaceReindexStatic cpSpaceRemoveBody cpSpaceRemoveCollisionHandler cpSpaceRemoveConstraint cpSpaceRemoveShape cpSpaceRemoveStaticShape cpSpaceSegmentQuery cpSpaceSegmentQueryFirst cpSpaceSetDefaultCollisionHandler cpSpaceShapeQuery cpSpaceStep cpSpaceUseSpatialHash cpSpaceHashAlloc cpSpaceHashInit cpSpaceHashNew cpSpaceHashResize cpSpatialIndexCollideStatic cpSpatialIndexFree cpSweep1DAlloc cpSweep1DInit cpSweep1DNew cpvslerp cpvslerpconst cpvstr Chipmunk-6.1.5/msvc/vc10/chipmunk/chipmunk.vcxproj000644 000765 000000 00000034506 12151675775 023046 0ustar00slembckewheel000000 000000  Debug SCRT Win32 Debug DLL Win32 Debug Win32 Release SCRT Win32 Release DLL Win32 Release Win32 {C1ACE86E-5A14-490A-9678-104BA2546723} Win32Proj chipmunk StaticLibrary true StaticLibrary true DynamicLibrary true StaticLibrary false true StaticLibrary false true DynamicLibrary false true $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ $(PlatformName)\$(Configuration)\ Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\include\chipmunk CompileAsCpp Windows true Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\include\chipmunk MultiThreadedDebug CompileAsCpp Windows true Level3 Disabled _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\include\chipmunk CompileAsCpp Windows true chipmunk.def Level3 MaxSpeed true _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\include\chipmunk CompileAsCpp Windows true true true Level3 MaxSpeed true _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\include\chipmunk MultiThreaded CompileAsCpp Windows true true true Level3 MaxSpeed true _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\include\chipmunk CompileAsCpp Windows true true true chipmunk.def Chipmunk-6.1.5/msvc/vc10/chipmunk/chipmunk.vcxproj.filters000644 000765 000000 00000016152 12151675775 024512 0ustar00slembckewheel000000 000000  {93995380-89BD-4b04-88EB-625FBE52EBFB} {4FC737F1-C7A5-4376-A066-2A32D752A2FF} {2af6495e-94a8-4200-8b69-e531cfdb9518} {23a179d1-3a41-426c-8528-edba78d4969c} include include include include include include include include include include include include\constraints include\constraints include\constraints include\constraints include\constraints include\constraints include\constraints include\constraints include\constraints include\constraints include\constraints include\constraints src include src src src src src src src src src src src src src\constraints src\constraints src\constraints src\constraints src\constraints src\constraints src\constraints src\constraints src\constraints src\constraints src\constraints src src src src src src Chipmunk-6.1.5/msvc/vc10/chipmunk/chipmunk.vcxproj.user000644 000765 000000 00000000215 12151675775 024011 0ustar00slembckewheel000000 000000  Chipmunk-6.1.5/msvc/glut/include/000755 000765 000000 00000000000 12151675775 017612 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/glut/lib/000755 000765 000000 00000000000 12151675775 016735 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/glut/runtime/000755 000765 000000 00000000000 12151675775 017652 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/glut/runtime/glut32.dll000644 000765 000000 00000720000 12151675775 021466 0ustar00slembckewheel000000 000000 MZÿÿ¸@øº´ Í!¸LÍ!This program cannot be run in DOS mode. $Œ¡À]íÏ“]íÏ“]íÏ“&ñÓ\íÏ“2òÄ“\íÏ“ÞñÁ“@íÏ“2òÅ“8íÏ“?òÜ“PíÏ“]íΓëíÏ“[ÎÚ“líÏ“šëÉ“\íÏ“¢ÍË“\íÏ“Rich]íÏ“PELóOê;à! p@“€Àpò ¬ãŒp(€2€¼.textfnp `.rdatav€€€@@.data”eP@À.rsrc(pP@@.relocê9€@`@BU‹ìƒì ‹EPèƒÄ‰Eà‹Mà‹U ;Q|‹Eà‹H‹UàJ9M |éR‹Eà‹M +H‹Uà‹B ‹ ˆ‰Mäƒ}ä„3UôRhð ÿÄEüPhñ ÿÄMìQhò ÿÄUèRhó ÿÄEøPhô ÿÄMðQhõ ÿÄjhð ÿÈjhñ ÿÈjhò ÿÈjhó ÿÈjhô ÿÈjhõ ÿÈ‹Uä‹BPj‹Mä‹QR‹Eä‹H Q‹Uä‹BP‹Mä‹QR‹Eä‹QÿÌ‹UôRhð ÿÈ‹EüPhñ ÿÈ‹MìQhò ÿÈ‹UèRhó ÿÈ‹EøPhô ÿÈ‹MðQhõ ÿÈ‹å]ÂÌÌU‹ìƒì‹EPèÀƒÄ‰Eø‹Mø‹U ;Q|‹Eø‹H‹UøJ9M |3Àë*‹Eø‹M +H‹Uø‹B ‹ ˆ‰Müƒ}üt ‹UüÙBèñßë3À‹å]ÂÌÌÌÌÌÌÌÌÌÌÌU‹ìƒì‹EPèÀƒÄ‰EðÇEøë ‹M ƒÁ‰M ‹U 3ÀŠ…ÀtT‹M 3ÒŠ‰Uü‹Eð‹Mü;H|=‹Uð‹B‹MðA9Eü},‹Uð‹Eü+B‹Mð‹Q ‹‚‰Eôƒ}ôtÛEø‹MôØAè[߉Eøë˜‹Eø‹å]ÂÌU‹ìƒìLV¡@N‹ @N‹P,;Q u¡@N‹H ‰Mì‹@N‹B‰EðëE‹ @N‹Q$‹B‰Eì‹ @N‹Q$‹B‰Eð‹ @N‹Q$‹E;B(u‹MQhôèÐ’ƒÄéƒ}ìuhÌ踒ƒÄéè}}ƒ}}‹URh¨è“’ƒÄéËEìƒxŽî‹MðQèƒÄ‰Eä‹Uì‹Bƒè‹Mì‰A‹Uì‹B ƒè‰Eèë ‹Mèƒé‰Mèƒ}èŒ;‹Uè;Uuëã‹EèkÀ ‹Mì‹QÙÜxÌßàöÄ… ‹Eè‰Eô‹MèkÉ ‹Uì‹B‹UèkÒ ‹uä‹v‹‰‹MèkÉ ‹Uì‹BÙpÌØ èãÝf‰Eø‹MèkÉ ‹Uì‹B‹UèkÒ ‹uä‹v‹D‰D‹MèkÉ ‹Uì‹BÙpÌØLè¤Ýf‰Eú‹MèkÉ ‹Uì‹B‹UèkÒ ‹uä‹v‹D‰D‹MèkÉ ‹Uì‹BÙpÌØLèeÝf‰EüÆEþ‹ @N‹Q RÿÜ…Àt¡@N‹H‰ ÜQë ÇÜQUôR‹Eä‹HQ‹ÐLRè<×ƒÄ é²þÿÿ‹Eä‰Eì‹ @N‹@N‹A,;B u‹ @N‹Uì‰Q ¡@N‹Mì‹Q‰Pë¡@N‹H$‹Uì‰Q¡@N‹H$‹Uì‹B‰A‹Mì‹QR¡@N‹H,Q‹ÐLRèc×ƒÄ ‹E‰EôÙE ÜhÌßàöÄAuÇEÜÇEàð?ë2ÙE ÜxÌßàöÄtÇEÔÇEØëÙE Ý]Ô‹MÔ‰MÜ‹U؉UàÝEÜÙ] ‹EkÀ ‹Mì‹Q‹M ‰ ÙpÌØM èÜf‰EøÙEÜhÌßàöÄAuÇEÌÇEÐð?ë2ÙEÜxÌßàöÄtÇEÄÇEÈëÙEÝ]Ä‹UĉUÌ‹EȉEÐÝEÌÙ]‹MkÉ ‹Uì‹B‹U‰TÙpÌØMè¡Ûf‰EúÙEÜhÌßàöÄAuÇE¼ÇEÀð?ë2ÙEÜxÌßàöÄtÇE´ÇE¸ëÙEÝ]´‹E´‰E¼‹M¸‰MÀÝE¼Ù]‹UkÒ ‹Eì‹H‹E‰DÙpÌØMè$Ûf‰EüÆEþ‹ @N‹Q RÿÜ…Àt¡@N‹H‰ ÜQë ÇÜQUôR‹Eì‹HQ‹ÐLRèûÔƒÄ ^‹å]ÂÌU‹ìƒì¡@N‹ @N‹P,;Q u¡@N‹H ‰Mø‹@N‹B‰EüëH‹ @N‹Q$‹B‰Eø‹ @N‹Q$‹B‰Eü‹ @N‹Q$‹E;B(u‹MQh€èQŽƒÄÙ€ÌëWƒ}øuhXè6ŽƒÄÙ€Ìë<}}ƒ}}‹URh4莃ÄÙ€Ìë‹EkÀ ‹Mø‹QЋE Ù‚‹å]ÂÌÌÌÌÌÌÌÌÌU‹ìƒì‹E‹ DN‹Tü‰Uü¡@N‹ @N‹P,;Q u"¡@N‹H ‰Mð‹@N‹B‰Eø‹Mü‹Q ‰UôëG¡@N‹H$‹Q‰Uð¡@N‹H$‹Q‰Uø‹Eüƒx$u‹MQh8èbƒÄ騋Uü‹B$‹H‰Môƒ}ðuhüè>ƒÄé´ƒ}ôu‹URh¸è"ƒÄ阋Eô;Eðué‹‹MðQèԃċUô‹BƒÀ‹Mô‰A‹@N¡@N‹J,;H u‹@N‹Eô‰B ‹ @N‹Uô‹B‰Aë!‹ @N‹Q$‹Eô‰B‹ @N‹Q$‹Eô‹H‰J‹Uô‹BP‹ @N‹Q,R¡ÐLPèUÓƒÄ ‹å]ÂÌÌÌÌÌÌÌÌÌÌÌÌU‹ììjè“ØƒÄ‰…üÿÿƒ½üÿÿu hdè䌃ÄÇ…üÿÿ‹…üÿÿÇ‹üÿÿÇA ‹•üÿÿÇB‹…üÿÿ‹H kÉ Qè2؃Ä‹•üÿÿ‰B‹…üÿÿƒxu hdè}ŒƒÄ‹üÿÿ‹Q ƒê‰•üûÿÿë‹…üûÿÿƒè‰…üûÿÿƒ½üûÿÿ|O‹üûÿÿkÉ ‹•üÿÿ‹BÇ€¿‹üûÿÿkÉ ‹•üÿÿ‹BÇD€¿‹üûÿÿkÉ ‹•üÿÿ‹BÇD€¿ë™‹MQ‹ÐLRè/¸ƒÄ‰…øûÿÿƒ½øûÿÿÿt‹…üÿÿ‹øûÿÿ;H |,j‹•üÿÿ‹P‹ øQQ‹ÐLRè>σÄ‹üÿÿ‰Aë"jj‹øQR¡ÐLPèσÄ‹üÿÿ‰A‹•üÿÿ¡XL‰B‹üÿÿ‰ XL‹…üÿÿ‹å]ÃÌÌÌÌÌÌÌÌÌÌU‹ì‹E‹HစÉu ‹U3ÀŠBƒøu ‹MQè7ƒÄ‹U ‰‹E ‹‹U‹A‰ë‹M Ç‹UÇ]ÃÌÌÌÌÌÌÌÌÌÌÌÌU‹ì‹EPèÔýÿÿƒÄ]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒì‹E‹Hƒé‹U‰J‹Eƒxug‹ XL‰MøÇEüXLƒ}øt)‹Uø;Uu ‹Eü‹M‹Q‰ë‹EøƒÀ‰Eü‹Mø‹Q‰UøëÑ‹E‹HQÿ$€‹U‹BPè'׃Ä‹MQè׃Ä‹å]ÃÌÌÌÌÌÌÌU‹ìƒì ‹E‹H<‰Müƒ}ü|Bƒ}üs<‹Uüƒ<Õ|u‹Eü‹ ÅxQjÿä‹Uü‰Õ|‹Eü‹ Å|‰Møé‹‹Uü‰Uôƒ}ôdtƒ}ôet`ƒ}ôftcëq‹EƒxXt"‹M‹QX‰U‹Eƒx‹Eƒxht9‹MQè[ƒÄ‹U‹B8P‹M‹Q4R‹Eÿ¬ƒÄ‹MÇAh‹UüƒÊ‰Uü‹Eƒx$„|‹M‹Q$ƒz,„l‹E‹‰M¸‹Uƒz$t‹E‹H$‹Q‰U°ëÇE°‹E°‰E¼‹Müá…É„Šƒ=8Mt'‹Uƒzlt‹Eü%=u‹M‹QRÿ€ëZ‹E‹M‹Q‰P(‹E‹M‹Q ‰P,‹E‹M‹Q‰P0‹Eü%£„L‹MQèZƒÄ‹UÇBl‹Eÿ¨Ç„L‹Müá…É„’‹U¸¡DN‹ ‰Mƒ}t~‹Uƒz$tu‹E‹H$‹Q;U¼ug‹E‹H$ƒy,t[‹U‹B$‹M‹P‰Q(‹E‹H$‹U‹A‰B,‹M‹Q$‹E‹J ‰H0‹Uü≄L‹EPèoYƒÄ‹M‹Q$ÿR,Ç„Lësƒ=8Mt2‹Eƒx$u)‹Mƒylt ‹Uüâúu‹E‹HQÿ€ë8‹Uü≄L‹EPèYƒÄ‹MÇAl‹Uÿ’¨Ç„L‹E‹Mü ˆ€‰Mü‹Uüƒâ@…Òt‹EPèÂXƒÄÿÀ‹MüစÉt‹URè£XƒÄè+U‹E‹ˆ€á?þÿÿ‹U‰Š€‹Eƒ¸€t‹Eë$‹MÁ„9 hLu ÇhL‹U‹‚„‹å]ÃùM.N}NdNINÌÌÌÌÌÌU‹ìƒì Wj ‹EP莪ƒÄ‰Eüƒ}üu ‹M¾…Òu3Àéƒ=˜Luhÿ¼£˜L¡˜L‰Eø‹MQ‹UøR賩ƒÄ‰Eüƒ}üuëR‹}ƒÉÿ3Àò®÷уÁÿ‹EüÁ‰Eô‹Mü;Møt ‹Uü3ÀŠBÿƒø u‹Mô3ÒŠƒú t ‹Eô3ÉŠ…Éu¸ë ‹Uô‰Uøë“3À_‹å]ÂÌÌÌÌÌÌÌÌÌÌU‹ìQ‹E‰Eüƒ}üf‡³‹Uü3ÉŠŠ}Tÿ$T¡@N‹M ‰ˆü鎋@N‹E ‰‚éz‹ @N‹U ‰‘éf¡@N‹M ‰ˆéS‹@N‹E ‰‚ é?‹ @N‹U ‰‘é+¡@N‹M ‰ˆé‹@N‹E ‰‚é‹ @N‹U ‰‘éð¡@N‹M ‰ˆ éÝ‹@N‹E ‰‚$éÉ‹ @N‹U ‰‘(鵡@N‹M ‰ˆ,颋@N‹E ‰‚0鎋 @N‹U ‰‘4ë}¡@N‹M ‰ˆ8ëm‹@N‹E ‰‚<ë\‹ @N‹U ‰‘@ëK¡@N‹M ‰ˆDë;‹@N‹E ‰‚Hë*‹ @N‹Q$‹E ‰B0ë‹ |L‹U ‰Q,ë ¡R‹M ‰H‹å]ÂvR‰RR±RÄRØRìRÿRS'S:SNSbSuS‰SšSªS»SÌSÜSíSþS TT ÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹E‰Eüƒ}üf‡n‹Uü3ÉŠŠÚVÿ$zV¡@N‹€üéN‹ @N‹é=‹@N‹‚é,¡@N‹€é‹ @N‹ é ‹@N‹‚éú¡@N‹€éê‹ @N‹éÙ‹@N‹‚éÈ¡@N‹€ 鸋 @N‹$é§‹@N‹‚(é–¡@N‹€,醋 @N‹0ëx‹@N‹‚4ëj¡@N‹€8ë]‹ @N‹<ëO‹@N‹‚@ëA¡@N‹€Dë4‹ @N‹Hë&‹@N‹B$‹@0ë‹ |L‹A,ë ‹tL‹Bë3À‹å]ÂU&U7UHUXUiUzUŠU›U¬U¼UÍUÞUîUüU VV%V3V@VNV\VgVrV ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒ=¨Ltëo¡@NÇ€”‹ @Nǘ‹@N¡ôQ‰‚œ‹ @N‹üQ‰‘ ¡@N‹ˆƒÉ‹@N‰Šh¡@NPèÖïÿÿƒÄ]ÃÌU‹ìƒ= Ltjjÿd‚Ç LǨL]ÃÌÌÌÌU‹ìƒ=¨Luh˜èºMƒÄ롨LP‹ ¨LQèÓ`ƒÄǨL]ÃÌÌÌÌU‹ìƒìèUEüP‹MQèXƒÄ‰Eø‹UüR‹EøP‹ ”Q‹œLRèƒÄ£¤L‹EøP賚ƒÄ‹å]ÂÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ììœVWƒ=”|éÁǔDždÿÿÿ…lÿÿÿP‹dÿÿÿQjÿ`‚…Àt5}Ørƒ}ätƒ}ä¸ë7‹ @N‹øë)¡$Më"¡(Më¡,Më‹URhpèÂ%ƒÄƒÈÿ‹å]ÂooyŠ˜¦­´»ÂÉÖë€òùÝÌÌU‹ìQƒ=4Mt¡MëOÇ4Mj+ÿX‚£`ƒ=Muƒ=Muƒ= Mu ÇEüëÇEü‹Eü£M¡M‹å]ÃÌÌÌÌÌÌÌÌÌU‹ìQƒ}tMƒ} ~G¡@NƒxHu+jjj‹ @N‹Q Rÿ°‚‰Eüƒ}üu ‹E Pjÿ¬‚‹ @N‹U ‰‘øë@¡@Nƒ¸ôt#‹ @Nƒ¹ø~‹@NƒzHujÿ¨‚¡@NÇ€ø‹ @N‹U‰‘ô‹å]ÂÌÌÌÌU‹ìƒìP¡@Nƒ¸ô„—ÇEÌ4ÇEÐÿMÌQjÿ¤‚‰Eȃ}Èut‹UÔ‰UÄ‹E؉EÀ‹M܉M¼‹U¼êÿ‰U¸ÛE¸Ü5Ð0èõoP‹EÀ-ÿ‰E´ÛE´Ü5Ð0èÛoP‹MÄéÿ‰M°ÛE°Ü5Ð0èÀoP‹UìR¡@NÿôƒÄ‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQƒ}u¡@Nƒ¸Ðu ÇEüëÇEü‹MüQjè8ƒÄ‹@N‹E‰‚À‹å]ÂÌÌÌÌÌU‹ìQƒ}u¡@Nƒ¸Àu ÇEüëÇEü‹MüQjèM8ƒÄ‹@N‹E‰‚Ћå]ÂÌÌÌÌÌU‹ì¡@N‹M‰ˆŒ]ÂÌÌÌÌÌÌÌÌÌÌÌU‹ì]ÂÌÌÌÌÌÌÌÌÌU‹ìQƒ}u¡@Nƒ¸Ôu ÇEüëÇEü‹MüQjèÍ7ƒÄ‹@N‹E‰‚Ä‹å]ÂÌÌÌÌÌU‹ìQƒ}u¡@Nƒ¸Äu ÇEüëÇEü‹MüQjè}7ƒÄ‹@N‹E‰‚Ô‹å]ÂÌÌÌÌÌU‹ìƒì4ƒ=ÆEÜ‹EüƒÀ‰Eüë/ÆEã ‹MüƒÁ‰Müë ‹UüƒÂ‰Uü‹EüŠˆMäë ÆEÞ‹UüƒÂ‰Uü‹EüƒÀ‰EüéáþÿÿMÌQ‹ÜQRÿ€‰Eȃ}È~qj(èP-ƒÄ‰Eô‹EôPj(‹MÈQ‹ÜQRÿ€ƒ}øt‹Eô‹Hƒá…Éu‹UôRèQ.ƒÄ3Àë-‹Eô3ÉŠHƒùu‹Uô3ÀŠB ƒø|‹MôQè'.ƒÄ3Àë‹Eô_‹å]äñÃÇÃÝÃæÃôÃÄÄ(Ä7ÄFÄUÄdÄwÄwÄwÄwÄÌÌÌÌÌÌÌU‹ì‹E£èQ]ÂÌU‹ì‹E£èQ]ÂÌU‹ì‹E£|L]ÃÌÌÌU‹ì¡RP貃Äÿ4€ƒ=èQt;‹ LNQèäãÿÿƒÄ‹RRèµÿÿÿƒÄÇR‹EP‹M QjÿèQƒÄ ÇRƒ=äQtD‹äQƒzu8¡LNPè‹ãÿÿƒÄ‹ äQ‹QRèYÿÿÿƒÄ¡äQ‹H Q‹äQ‹BÿPƒÄÇLN]ÃÌÌU‹ì‹Eƒxt‹M‹QRèèÿÿÿƒÄ‹EÇ@‹MÇA ‹UÇB]ÃÌÌÌÌÌU‹ì‹E£R‹M ‰ LNÇäQƒ=èQt+‹URèÀþÿÿƒÄ‹E PèÔâÿÿƒÄ‹MQ‹URjÿèQƒÄ ‹EP‹MQ‹URè ƒÄ ]ÃÌÌÌÌÌÌÌÌU‹ìj¡@N‹H Qj‹UR‹E P3Ƀ=àQ”Á÷ÙɃáQ‹U‹BPÿ8‚]ÃÌÌÌÌÌU‹ìƒì ‹E‹H‰Mø‹U‹B ‰Eüƒ}ütW‹Mü‹Q;U u‹EüëI‹Eüƒxt*‹M Q‹Uü‹B ‹ XN‹Rè°ÿÿÿƒÄ‰Eôƒ}ôt‹Eôë‹Eøƒè‰Eø‹Mü‹Q ‰Uüë£3À‹å]ÃÌÌÌÌÌU‹ìƒ}| ‹E;\N~3Àë ‹M‹XN‹DŠü]ÃÌÌÌÌÌÌÌÌÌU‹ìƒìƒ=Rtèl觉Eøj0èà)ƒÄ‰Eüƒ}üu hdè7ÞÿÿƒÄ‹Eü‹Mø‰‹UüÇB‹EüÇ@‹Mü‹U‰Q‹EüÇ@ ‹MüÇA‹UüÇB‹EüÇ@ ÿ4‚‹Mü‰A‹Uø¡XN‹Mü‰ ‹UüRèäüÿÿƒÄ‹EøƒÀ‹å]ÂÌÌÌÌÌU‹ìQÇEüë ‹EüƒÀ‰Eü‹Mü; \N}‹Uü¡XNƒ<u‹Eüëzë׋ \NƒÁ‰ \Nƒ=XNt‹\NÁâR¡XNPè+ƒÄ£XNëjèÏ(ƒÄ£XNƒ=XNu hdè!ÝÿÿƒÄ‹ \N‹XNÇDŠü¡\Nƒè‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìhØèCÜÿÿƒÄh„èÖÜÿÿƒÄ]ÃÌU‹ì‹E £øL‹MQèLþÿÿ]ÂÌÌÌÌÌÌÌÌU‹ìƒì ‹EPèþÿÿƒÄ‰Eüƒ=Rtèÿÿÿ‹Mü‹QRÿ0‚‹E‹ XNÇDü‹Uü‹B ‰Eøƒ}øt,‹Mø‹Q ‰Uô‹Eø‹HQè)ƒÄ‹UøRè )ƒÄ‹Eô‰Eøë΋ |L;Müu Ç|L‹UüRèã(ƒÄ‹å]ÂÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒ=|Lt ¡|L‹ƒÀë3À]ÃÌÌÌÌU‹ìQƒ}| ‹E;\N~h¸è!ÛÿÿƒÄë1‹M‹XN‹DŠü‰Eüƒ}üuh¸èüÚÿÿƒÄë ‹MüQè®úÿÿƒÄ‹å]ÂÌÌÌÌÌU‹ìQƒ=Rtè~þÿÿj$èú&ƒÄ‰Eüƒ}üu hdèQÛÿÿƒÄ‹Eü‹ |L‰Hj‹U R‹EP‹MüQè?ƒÄ‹|L‹BƒÀ‹ |L‰A‹Uü¡|L‹H ‰J ‹|L‹Eü‰B ‹å]ÂÌÌÌÌÌÌÌU‹ìQW‹E‹H‰Mü‹U RèÙÙÿÿƒÄ‹M‰A‹Uƒzu hdè½ÚÿÿƒÄ‹E‹M‰H‹} ƒÉÿ3Àò®÷уÁÿ‹U‰J‹E‹M‰H ‹U¡€‰B‹ €ƒÁ‰ €ƒ}t‹U R‹E‹Qj‹Uü‹BPÿ,‚ë‹M Q‹U‹BPj‹Mü‹QRÿ,‚_‹å]ÃÌÌÌÌÌÌÌÌÌU‹ìƒìƒ=Rtè,ýÿÿj$è¨%ƒÄ‰Eøƒ}øu hdèÿÙÿÿƒÄ¡|L‹HƒÁ‹|L‰J‹Eø‹ |L‰H‹U Rè3ûÿÿƒÄ‰Eüƒ}üt ‹Eø‹Mü‹Q‰j‹E ƒèP‹MQ‹UøRè¶þÿÿƒÄ¡|L‹HƒÁ‹|L‰J‹Eø‹ |L‹Q ‰P ¡|L‹Mø‰H ‹å]ÂÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒìWƒ=Rtè[üÿÿ¡|L‹H‰Mø‹|L‹B ‰Eüƒ}ü„ý‹Mø;M…Ú‹Uüƒzt‹Eü‹H‹Qƒê‹Eü‹H‰Q‹Uü‹BPèÁ%ƒÄ‹M Qè-£ƒÄ‹Uü‰B‹Eüƒxu hèÌØÿÿƒÄ‹MüÇA‹} ƒÉÿ3Àò®÷уÁÿ‹Uü‰J‹Eü‹M‰H ‹Uü¡€‰B‹ €ƒÁ‰ €h‹UøƒêR¡|L‹HQÿ$‚‹U R‹Eü‹HQh‹UøƒêR¡|L‹HQÿ(‚ë(‹Uøƒê‰Uø‹Eü‹H ‰Müéùþÿÿ‹URhàè×ÿÿƒÄ_‹å] ÌÌÌÌÌU‹ìƒì Wƒ=Rtè ûÿÿ¡|L‹H‰Mô‹|L‹B ‰Eüƒ}ü„!‹Mô;M…þ‹Uüƒzu‹Eü‹H‹QƒÂ‹Eü‹H‰Q‹Uü‹BPèq$ƒÄ‹M QèÝ¡ƒÄ‹Uü‰B‹Eüƒxu hè|×ÿÿƒÄ‹MüÇA‹} ƒÉÿ3Àò®÷уÁÿ‹Uü‰J‹Eƒè‹Mü‰A ‹Uü¡€‰B‹ €ƒÁ‰ €‹URè‹øÿÿƒÄ‰Eøƒ}øt ‹Eü‹Mø‹Q‰h‹EôƒèP‹ |L‹QRÿ$‚‹E P‹Mü‹Rh‹EôƒèP‹ |L‹QRÿ(‚ë(‹Eôƒè‰Eô‹Mü‹Q ‰UüéÕþÿÿ‹EPhàè ÖÿÿƒÄ_‹å] ÌU‹ìƒì ƒ=Rtèœùÿÿ¡|L‹H‰Mø‹|LƒÂ ‰Uô¡|L‹H ‰Müƒ}ü„€‹Uø;UuX¡|L‹Hƒé‹|L‰J‹Eô‹Mü‹Q ‰h‹EøƒèP‹ |L‹QRÿ$‚‹Eü‹HQèÞ"ƒÄ‹UüRèÒ"ƒÄë1‹Eøƒè‰Eø‹MüƒÁ ‰Mô‹Uü‹B ‰Eüévÿÿÿ‹MQhàè2ÕÿÿƒÄ‹å]ÂÌÌÌÌÌÌÌÌÌU‹ì¡@N;¨LuhèÕÿÿƒÄëHƒ=Rtè£øÿÿ‹M‹@Nƒ|ŠL}¡@N‹HtƒÁ‹@N‰Jt¡|L‹ƒÁ‹U¡@N‰LL]ÂÌÌÌÌÌU‹ìƒ=RtèOøÿÿ‹E‹ @Nƒ|L~%‹@N‹Btƒè‹ @N‰At‹U¡@NÇDL]ÂÌÌÌÌÌÌU‹ìƒìEøPÿ…Àt\MðQÿ ‹UôR‹EðP‹MüQ‹UøRèm1‹M‰ßmøßmðÞùØ PÜØ PÜ‹U‹iÀèiÀè‰EèÚeèè ‹M‰Aë,ÿ´‚‰Eì‹Eì3Ò¹è÷ñ‹U‰‹Eì3Ò¹è÷ñ‹E‰P3À‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹E‰Eüƒ}üwI‹Müÿ$ŒÒ¸Ø ëG¸ ë@¸XÌë9¸(§ë2¸ˆ­ë+¸@Üë$¸êë¸8 ë¸À0ëhdèíÓÿÿƒÄ3À‹å]Ã:ÒAÒHÒOÒVÒ]ÒdÒkÒrÒU‹ì3À]ÃÌÌÌÌÌÌÌÌÌU‹ìƒì‹E ‹‰Mð‹U‹‰Eô‹M ‹‹E‰Uø‹M‹‹E‰Uüj‹M÷ÙÉá1?ÁÏÉQUðRÿ€‚ƒ}ð} ‹E Çë‹M ‹Uð‰ƒ}ô} ‹EÇë‹M‹Uô‰‹Eø+Eð‹M‰‹Uü+Uô‹E‰‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹E ‰Eüƒ}ü w/ƒ}ü „‘‹Müƒé‰Müƒ}ü‡á‹Eü3ÒŠ¾Øÿ$•šØ}üwv}ü„i}üw5}ü„ø‹Müƒé$‰Mü}üᇋEü3ÒŠæØÿ$•ÎØ‹Müé‰Mü}üñ‡b‹Eü3ÒŠàÙÿ$•ÈÙ}üwa}ü„}üw,}ü„W}ü„n}ü„æé}ü„<}ü„Ïéæ‹Müé ‰Müƒ}ü‡Ð‹Eü3ÒŠÚÚÿ$•ÒÚ‹MQ‹URè3ƒÄ÷ØÀ÷ØH鸋EPè+ƒÄ3À饋MQèHƒÄ3Àé’‹URèuƒÄ3Àé‹EÁè%ÿÿ¿ÈQ¿UR‹EP‹MQ誃Ä3ÀéT‹UÁêâÿÿâÿÿR‹EP‹MáÿÿQ‹URèƒÄ3Àé ‹EP‹MQèσÄ3Àé ‹UR‹EPèhƒÄ3Àéò‹MQ‹URèуÄ3ÀéÛ‹EÁè%ÿÿ%ÿÿP¿MQj‹UR‹EPè2 ƒÄ3À鬋MÁéáÿÿáÿÿQ¿URj‹EP‹MQè ƒÄ3Àé{‹UÁêâÿÿâÿÿR¿EPj‹MQ‹URèЃÄ3ÀéJ‹EÁè%ÿÿ%ÿÿP¿MQj‹UR‹EP衃Ä3Àé‹MQ‹UÁêâÿÿ¿ÂP¿MQj‹URèó ƒÄ3Àéí‹EP‹MÁéáÿÿ¿ÑR¿EPj‹MQè5ƒÄ3Àé¿‹UR‹EÁè%ÿÿ¿ÈQ¿URj‹EPè(ƒÄ3Àé’‹MQ‹UÁêâÿÿ¿ÂP¿MQ‹URèƒÄ3Àéf‹EP‹MÁéáÿÿ¿ÑR¿EP‹MQèЃÄ3Àé:‹UR‹EÁè%ÿÿ¿ÈQ¿UR‹EPèŃÄ3Àé‹MQ‹UÁêâÿÿ¿ÂP¿MQ‹UR蹃Ä3Àéã‹EPèvƒÄéÒ‹MQè…ƒÄéÁ‹UÁêâÿÿâÿÿR‹EP‹MáÿÿQ‹URèsƒÄ3Àé‹EP‹MQ較Ä3Àëy‹UâÿÿƒútëS‹EÁè%ÿÿ%ÿÿP‹MáÿÿQ‹UR‹EPèƒÄë<‹M;Muë‹UR赃Äë$‹EPèƒÄë‹MQ‹UR‹E P‹MQÿ ‚‹å]ÂÀÔïÔÕ@ÕtÕ‹ÕÕÜÔ~Ø¢Õ¹ÕèÕÖJÖ~ØØ…×yÖ×§Ö~ØpØ~ØÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ì¸]ÃÌÌÌÌÌÌU‹ìƒ=øLt jÿøLƒÄ‹EPÿL‚]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹EPèSÍÿÿƒÄ‰Eüƒ}üt ‹MüƒytjjÿŒ‹Uü‹BPÿ¸‹å]ÃÌÌÌU‹ìƒìD‹EPèÍÿÿƒÄ‰EüM¼Q‹URÿ‚E¼P‹MQÿ‚ƒ}üt‹Uü‹B ;Euh‹MüQè lÿÿƒÄ‹å]ÃÌÌÌÌÌÌÌÌÌU‹ìQ‹EPè³ÌÿÿƒÄ‰Eüƒ}üti‹Mü‹Q4;Uu ‹Eü‹H8;MtS‹Uü‹E‰B4‹Mü‹U‰Q8‹EüPè†ÍÿÿƒÄÿ4€‹MQ‹UR‹Eüÿ¬ƒÄ‹MüÇAhh‹UüRè‘kÿÿƒÄ‹å]ÃÌÌÌÌÌÌÌÌÌÌU‹ìƒì‹EPè!ÌÿÿƒÄ‰Eüƒ}üt3Ƀ}”Á‰Mø‹UøR‹EüPè,ƒÄƒ} tjjh‹MQÿH‚‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹E‹M ‰HD‹U‹E ;B@t1‹Mƒ¹Èt%‹U‹E ‰B@‹MQèªÌÿÿƒÄ‹U R‹EÿȃÄ‹M‹Q\‰Uüƒ}üt‹E P‹MüQè›ÿÿÿƒÄ‹Uü‹B`‰Eüëß‹å]ÃÌÌÌÌÌÌÌÌÌU‹ìƒì‹EPèAËÿÿƒÄ‰Eüƒ}ü„†‹MüÇAH‹Uüƒº¼t‹EüPè"ÌÿÿƒÄj‹Müÿ‘¼ƒÄ‹UüƒºôtJƒ=@NtA¡@Nƒ¸ø~3jjj‹ @N‹Q Rÿ°‚‰Eøƒ}øu¡@N‹ˆøQjÿ¬‚‹å]ÃÌÌÌÌÌÌÌU‹ìQ‹EPè“ÊÿÿƒÄ‰Eüƒ}üt[‹MüÇAH‹Uüƒº¼t‹EüPèxËÿÿƒÄj‹Müÿ‘¼ƒÄ‹Uüƒºôtƒ=@Nt¡@Nƒ¸ø~jÿ¨‚‹å]ÃÌÌÌÌÌÌÌÌU‹ìƒì‹EPèÊÿÿƒÄ‰Eüƒ}üteÇEðÇEìÇEøÇEôjjð‹MQÿl‚PUìRÿ€‚‹Eô+Eì‹M ‰A‹Uø+Uð‹E ‰P‹M ‹ôQ‰Q ‹E ‹ üQ‰H$‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒì‹EPèÉÿÿƒÄ‰Eüƒ}ü„d‹MüQ‹URèdƒÄ‰Eüƒ}t+‹EÁèƒàƒè÷ØÀ@‰Eì‹Müƒ¹Œt ƒ}ìté UðRÿìEðP‹Mü‹Q Rÿ‚è£d‹E PèïƒÄ‰Eøƒ}ø}nƒ}t4‹Müƒ¹Ðt&‹UüRèèÉÿÿƒÄ‹EôP‹MðQ‹Uø÷ÚR‹EüÿÐƒÄ ë2‹Müƒ¹Ôt&‹UüRè´ÉÿÿƒÄ‹EôP‹MðQ‹Uø÷ÚR‹EüÿÔƒÄ ënƒ}ø~hƒ}t2‹Müƒ¹Àt$‹UüRètÉÿÿƒÄ‹EôP‹MðQŠUøR‹EüÿÀƒÄ ë0‹Müƒ¹Ät$‹UüRèBÉÿÿƒÄ‹EôP‹MðQŠUøR‹EüÿÄƒÄ Çdÿÿÿÿ‹å]ÃÌÌÌÌÌÌÌÌÌU‹ìƒì‹E ƒx\tcMøQÿìUøR‹EPÿ‚‹MüQ‹UøR‹EPÿ‚‰Eôƒ}ôt0‹Mô;Mt(‹UôRè­ÇÿÿƒÄ‰Eðƒ}ðt‹EðP‹MôQè”ÿÿÿƒÄ‰E ‹E ‹å]ÃÌÌÌÌÌÌÌU‹ìQÇEüjÿ ‚¿À%ÿ…Àt ‹MüƒÉ‰Müjÿ ‚¿Ðâÿ…Òt‹Eü ‰Eüjÿ ‚¿Èáÿ…Ét ‹UüƒÊ‰Uü‹Eü‹å]ÃÌÌÌÌÌÌU‹ìì…ÿÿÿPÿ‚jüþÿÿQ•ÿÿÿRj‹EPÿ‚ƒøu ‹…üþÿÿ%ÿÿëƒ}.u¸ë ‹MQèƒÄ‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹E‰Eü‹Müƒé!‰Müƒ}üZ‡¬‹Eü3ÒŠ'ãÿ$•ÏâƒÈÿ锸þÿÿÿ銸ýÿÿÿ逸üÿÿÿëy¸ûÿÿÿër¸úÿÿÿëk¸ùÿÿÿëd¸øÿÿÿë]¸÷ÿÿÿëV¸öÿÿÿëO¸õÿÿÿëH¸ôÿÿÿëA¸œÿÿÿë:¸›ÿÿÿë3¸šÿÿÿë,¸™ÿÿÿë%¸˜ÿÿÿ븗ÿÿÿ븖ÿÿÿ븕ÿÿÿë ¸”ÿÿÿë3À‹å]æâ­â»â´âŠâ‘â˜âŸâÂâ/â7âAâKâRâYâ`âgânâuâ|âƒâÉâ ÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìj‹EP‹MQ‹URè ƒÄ]ÃÌÌÌÌÌU‹ìƒì‹EPèáÄÿÿƒÄ‰Eüƒ=RtFƒ}uéMðQÿìUðR‹EPÿ‚ÇäQ‹MôQ‹UðR‹EPè”áÿÿƒÄ éÙ‹MQÿD‚ƒ}ü„Å‹U‹Eü‹LLQè˜ãÿÿƒÄ‰Eøƒ}øtc‹U ‰Uè‹E‰EìMèQ‹Uü‹B Pÿx‚ƒ}u ÇEäë 3Ƀ}•Á‰Mä‹Uä‰àQ‹EP‹M Q‹UìR‹EèP‹MüQ‹UøRèþáÿÿƒÄëF‹Eüƒ¸°t:èhüÿÿ£d‹MüQèêÄÿÿƒÄ‹UR‹E Pj‹MQ‹Uüÿ’°ƒÄÇdÿÿÿÿ‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìj‹EP‹MQ‹URèšþÿÿƒÄ]ÃÌÌÌÌÌU‹ìj‹EP‹MQ‹URèzþÿÿƒÄ]ÃÌÌÌÌÌU‹ìj‹EP‹M Q‹URè ƒÄ]ÃÌÌÌÌÌU‹ìƒì ‹EPè1ÃÿÿƒÄ‰Eüƒ=Rt@MôQÿìUôR‹EPÿ‚ƒ}uërÇäQ‹MøQ‹UôR‹EPèçßÿÿƒÄ ëRÿüƒ}ütF‹Müƒ¹°t:èEûÿÿ£d‹UüRèÇÃÿÿƒÄ‹EP‹M Qj‹UR‹Eüÿ°ƒÄÇdÿÿÿÿ‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌU‹ìj‹EP‹M Q‹URè*ÿÿÿƒÄ]ÃÌÌÌÌÌU‹ìj‹EP‹M Q‹URè ÿÿÿƒÄ]ÃÌÌÌÌÌU‹ìƒì ‹EPè1ÂÿÿƒÄ‰Eüƒ=Rt颃}ü„˜‹Mƒá…Éu‹Uƒâ…Òu‹Eƒà…Àu ÇEôëÇEô‹Mô‰Mø‹Uüƒº´t&ƒ}øt ‹EüPèÔÂÿÿƒÄ‹MQ‹U R‹Eüÿ´ƒÄ‹Müƒ¹¸t&ƒ}øu ‹UüRè¢ÂÿÿƒÄ‹EP‹M Q‹Uüÿ’¸ƒÄ‹å]ÃÌÌÌÌÌÌÌU‹ìjjhUNEM‹EPÿø3À]ÃÌÌÌÌÌÌU‹ìhUNEM‹EPÿô3À]ÃÌÌÌÌÌÌÌÌÌÌU‹ìƒìƒ=RtD‹E P‹ RQèÁßÿÿƒÄ£äQUøRÿìEøP‹MQÿ‚‹UüR‹EøP‹MQèàÝÿÿƒÄ ‹å]ÃÌÌÌÌÌÌÌÌÌU‹ìƒ=tLtè/_ÿÿ]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹EPè£ÀÿÿƒÄ‰Eüƒ}üt ‹MüQè4ÿÿƒÄ3À‹å]ÃÌÌÌÌÌU‹ìQ‹EPèsÀÿÿƒÄ‰Eüƒ}ütF‹Müƒy t=‹Uü‹B ‹HQÿ(€j‹Uü‹B ‹HQ‹Uü‹BPÿ,€‹Mü‹QRÿ0€¸ë3À‹å]ÃÌÌÌÌÌÌÌÌÌÌÌU‹ìƒìP‹EPèÀÿÿƒÄ‰Eü‹Müƒ¹ô„“ÇEÈ4ÇEÌÿUÈRjÿ¤‚‹EЉEÄ‹MÔ‰MÀ‹U؉U¼‹E¼-ÿ‰E¸ÛE¸Ü5Ð0èâP‹MÀéÿ‰M´ÛE´Ü5Ð0èÇP‹UÄêÿ‰U°ÛE°Ü5Ð0è¬P‹EèP‹Müÿ‘ôƒÄ¸ë3À‹å]ÃÌÌU‹ìƒì WÇEôjjj¡ÜQPÿ€‰Eøƒ}ø~+‹MøkÉ(Qè~ƒÄ‰Eô‹MøkÉ(3À‹}ô‹ÑÁéó«‹ÊƒáóªÇEüë ‹EüƒÀ‰Eü‹Mü;Mø}$‹UükÒ(‹EôÂPj(‹MüƒÁQ‹ÜQRÿ€ëË‹E‹Mø‰‹Eô_‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒìDW¹ 3À}Ôó«EÔPj(‹ ÜQQÿ €P‹ÜQRÿ€‹EØ%€…Àu‹MÜáÿƒùt3À雋MÝáÿºÓâ‰UЋEÐ …Q苃ĉEÌ‹UÐ •3À‹}Ì‹ÑÁéó«‹Êƒáóª‹EÌfÇ‹MÌf‹UÐf‰Q‹ẼÀPhj‹ ÜQQÿ €‹UÜâÿ…Ò…Û‹MÞáÿ¸Óàƒè‰E¼‹MàáÿºÓâƒê‰UÀ‹Mâáÿ¸Óàƒè‰EÈÇEÄë ‹MăÁ‰MÄ‹UÄ;UÐ}‹Mßáÿ‹EÄÓø#E¼iÀÿ™÷}¼‹MÄ‹ÜDŠ‹Mááÿ‹EÄÓø#EÀiÀÿ™÷}À‹MÄ‹ÜDŠ‹Mãáÿ‹EÄÓø#EÈiÀÿ™÷}È‹MÄ‹ÜDŠ‹EÄ‹MÌÆDépÿÿÿ‹UÌRÿ€‰Eü‹EÌPèrƒÄj‹MüQ‹ÜQRÿ,€¡ÜQPÿ0€‹Eü_‹å]ÃÌÌÌÌÌÌÌÌÌÌÌU‹ìQ‹E3Éf‹H‹Á™âÿÂÁøˆEü‹U3Àf‹B™âÿÂÁøˆEý‹E3Éf‹H‹Á™âÿÂÁøˆEþÆEÿUüRj‹E‹Q‹U Rÿ€ƒ=ÜQt)‹E Pÿ(€j‹M Q‹ÜQRÿ,€¡ÜQPÿ0€‹å]ÃU‹ìQ‹E Pÿ‚‰Eüj‹MQ‹UüRÿ,€‹EüPÿ0€‹å]ÃÌU‹ìƒì‹E‰Eø‹M‰MüUøR‹E Pÿx‚‹M‹Uø‰‹E ‹Mü‰¸‹å]ÃÌÌÌÌÌÌÌU‹ìƒìEðP‹M Qÿ|‚ÇEèÇEìUèR‹E Pÿx‚‹M‹U艋E‹M쉋U‹Eø‰‹M ‹Uü‰¸‹å]ÃÌÌÌÌÌÌÌU‹ìƒì ÿ˜‚‰Eü‹EüPÿ‚‰Eôj‹MôQÿ€‰Eø‹UôR‹EüPÿ\‚‹Eø‹å]ÃU‹ìƒì ÿ˜‚‰Eü‹EüPÿ‚‰Eøj‹MøQÿ€‰Eô‹UøR‹EüPÿ\‚‹Eô‹å]ÃU‹ìƒì‹E$‰Eø‹M(‰MüUøR‹EPÿx‚‹MüQ‹UøRÿð‹å]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌÌU‹ìƒìjjjjEäPÿˆ‚‹å]ÃÌÌÌÌU‹ìƒìÇEìƒ}t ‹E¾…Éu‹EìéL‹U¾ƒø=u ‹MƒÁ‰M‹U‰Uä‹E侃ù+tG‹U侃ø-t<‹M侃úxt1EüP‹MäQèƒÄ‰Eð‹Uä;Uüu3Àéï‹Eü‰Eä‹MìƒÉ‰Mì‹U侃øxt ‹M侃úXu:‹EäƒÀ‰EäMüQ‹UäRèÃĉEè‹Eä;Eüu3À韋Mü‰Mä‹UìƒÊ‰Uì‹E侃ù+t‹U侃ø-…‹M侃ú-u>‹EäƒÀ‰EäMüQ‹UäRèdƒÄ÷؉Eø‹Eä;Eüu3Àé>‹Mü‰Mä‹UìƒÊ‰Uìë1‹EäƒÀ‰EäMüQ‹UäRè&ƒÄ‰Eø‹Eä;Eüu3Àé‹Mü‰Mä‹UìƒÊ‰Uì‹E侃ù+t‹U侃ø-…€‹M侃ú-u>‹EäƒÀ‰EäMüQ‹UäRèǃÄ÷؉Eô‹Eä;Eüu3Àé¡‹Mü‰Mä‹UìƒÊ ‰Uìë.‹EäƒÀ‰EäMüQ‹UäR艃ĉEô‹Eä;Eüu3Àëh‹Mü‰Mä‹UìƒÊ‰Uì‹Eä¾…Ét3ÀëK‹Uìƒâ…Òt‹E ‹Mø‰‹Uìƒâ…Òt‹E‹Mô‰‹Uìƒâ…Òt‹E‹Mð‰‹Uìƒâ…Òt‹E‹M艋Eì‹å]ÃÌÌÌÌÌÌÌÌÌÌÌU‹ìƒìÇEüÇEø‹E¾ƒù+u ‹UƒÂ‰Uë‹E¾ƒù-u‹UƒÂ‰UÇEøÿÿÿÿë ‹EƒÀ‰E‹M¾ƒú0| ‹E¾ƒù9‹UükÒ ‹E¾T ЉUüëÌ‹E ‹M‰ƒ}ø|‹Eüë‹Eü÷Ø‹å]ÃÌÿ%L€ÿ%<€ÿ%@€ÿ%D€ÿ%H€ÿ%P€èè£dNèÃÛâÃøŒ Ç6£Ç œÇÜÇ„£ÃU‹ìƒÄô›Ù}þ›f‹Eþ€Ì f‰EüÙmüß}ôÙmþ‹Eô‹UøÉÃÿ5ÄNÿt$èYYÃ|$àw"ÿt$è…ÀYu9D$tÿt$èÉ…ÀYuÞ3ÀÃU‹ìjÿhXÜh° d¡Pd‰%ƒì SVW¡dUƒøuC‹u;5\U‡“j è¼,YƒeüVè¤Y‰EäƒMüÿè ‹Eä…Àtmé†j èò,YÃøuZ‹E…Àtpƒæðëj^‰u;5D>w.j èf,YÇEü‹ÆÁèPèé'Y‰EäƒMüÿè ‹Eä…Àu-Vë‹uj è“,YËE…ÀujXƒÀ$ðPjÿ5`UÿH‹Mðd‰ _^[ÉÃU‹ìjÿhpÜh° d¡Pd‰%ƒìSVW‹u…ö„¬¡dUƒøu;j èÄ+YƒeüVèXY‰Eä…Àt VPètYYƒMüÿèƒ}äëQj èó+YÃøuSj è„+YÇEüEàPEØPVèh&ƒÄ ‰EÜ…ÀtPÿuàÿuØè©&ƒÄ ƒMüÿè ƒ}Üuÿuë j è›+YÃVjÿ5`UÿD‹Mðd‰ _^[ÉÃU‹ìjÿhˆÜh° d¡Pd‰%ƒì(SVW‹]3ÿ;ßuÿu è©ýÿÿYéæ‹u ;÷u SèÐþÿÿYéÑ¡dUƒø…9‰}܃þà‡ñj è¬*Y‰}üSèAY‰EØ;Ç„¤;5\UwLVSPè. ƒÄ …Àt‰]Üë8VègY‰EÜ;Çt*‹CüH‰Eà;Ær‹ÆPSÿuÜè¥,Sèî‰EØSPèƒÄ9}ÜuK;÷uj^‰u ƒÆƒæð‰u VWÿ5`UÿH‰EÜ;Çt#‹CüH‰Eà;Ær‹ÆPSÿuÜèN,SÿuØè¿ƒÄƒMüÿèZ9}Øu";÷uj^ƒÆƒæð‰u VSWÿ5`Uÿ@‰EÜ‹EÜ;Ç…½9=ÄN„±VègY…À…Ýþÿÿ雋u ‹]3ÿj èé)YÃø…Gƒþàw;÷vƒÆƒæðëj^‰u ‰}܃þà‡ój èS)YÇEüEÔPEÈPSè7$ƒÄ ‹ø‰}Ð…ÿ„ª;5D>s\‹ÞÁëSWÿuÔÿuÈèÕ'ƒÄ…Àt‹E‰EÜë8Sè”$Y‰EÜ…Àt*¶Áà‰EÌ;Ær‹ÆPÿuÿuÜè++WÿuÔÿuÈè $ƒÄ‹]ƒ}ÜuSVjÿ5`UÿH‰EÜ…Àt=¶Áà‰EÌ;Ær‹ÆPSÿuÜèä*WÿuÔÿuÈèÙ#ƒÄëVSjÿ5`Uÿ@‰E܃Müÿè&‹EÜ;Çuf9=ÄNt^VèY…À…ãþÿÿëK‹u ‹]j è›(Y3ÿÃ3Àƒþàw;÷uj^ƒÆƒæðVSWÿ5`Uÿ@;Çu9=ÄNt VèÃY…ÀuÆ3À‹Mðd‰ _^[ÉÃU‹ìƒì SV‹u Wèä-j‰E Y3À}àjó«_г¶Ê‹Á#ÏÁèÒãDàF„Òuå‹U…Òu‹E ‹PŠj¶ð‹Î[#ÏÓãÁîŠL5à„Ùt„ÀtBëà‹ÚŠ„Àt¶ð‹Îj#ÏXÓàÁîŠL5à„ÁuBëà€"B‹E _^‰P‹Ã+Â÷ØÀ#Ã[ÉÃjÿt$ÿt$ÿt$èƒÄÃU‹ìƒì SƒeøVW‹}Šw‰uüƒ=œB~¶ÃjPèÕ/YYë‹ @¶ÃŠAƒà…ÀtŠFëЀû-‰uüuƒMë€û+uŠF‰uü‹E…ÀŒ‰ƒø„€ƒø$wj…ÀYu$€û0t ÇE ë2Šƒàt }ø€w …Àu,9uøv'èý,öEÇ"tƒMøÿë‹E$öØÀ÷ØƉEø…Ût‹Eü‰öEt‹Eø÷؉Eø‹Eøë ‹E …Àt‰83À_^[ÉÃÌÌÌÌÌÌÌÌÌÌÌU‹ìV3ÀPPPPPPPP‹U IŠ ÀtB«$ëó‹uŠ Àt F£$sóFÿƒÄ ^Éá<…ÀtÿÐhhèûhhèìƒÄÃjjÿt$ è$ƒÄ Ãjjÿt$ èƒÄ ÃjjjèƒÄ ÃWèŸj_9=¨Nuÿt$ÿ4Pÿ8ƒ|$ S‹\$‰=¤Nˆ Nu<¡e…Àt"‹ ŒeVqü;ðr‹…ÀtÿЃî;5esí^h$hèCYYh,h(è2YY…Û[tè_Ãÿt$‰=¨Nÿ<_Ãj èÜ#YÃj è4$YÃV‹t$;t$ s ‹…ÀtÿЃÆëí^ÃÌÌÌÌÌÌÌ‹L$WSVŠ‹|$„ÒtiŠq„ötO‹÷‹L$ŠF8Ðt„Àt ŠF8Ðt „Àuõ^[_3ÀÊF8ðuë~ÿŠa„ät(ŠƒÆ8àuÄŠA„ÀtŠfÿƒÁ8àtßë±3À^[_ŠÂé#Gÿ^[_ËÇ^[_ÃBÿ[ä$d$3ÀŠD$S‹ØÁà‹T$÷ÂtŠ B8ÙtÑ„ÉtQ÷Âuí ØW‹ÃÁãV Ø‹ ¿ÿþþ~‹Á‹÷3Ëðùƒñÿƒðÿ3Ï3ƃÂáu%tÓ%uæ€uÄ^_[3ÀËBü8Øt6„Àtï8Üt'„ätçÁè8Øt„ÀtÜ8Üt„ätÔë–^_Bÿ[ÃBþ^_[ÃBý^_[ÃBü^_[ÃVè{þÿÿÿ5eè™+‹eY‹ Œe‹ñ+òƒÆ;Æs=Rè{+ƒÀPÿ5eè ÷ÿÿƒÄ …Àu3öë,‹ Œe+ e£eÁù ˆ‰ Œe‹D$‰ƒŒe‹ðèþÿÿ‹Æ^Ãÿt$èyÿÿÿ÷ØÀY÷ØHÃh€èôÿÿ…ÀY£eu jè©¡eYƒ ¡e£ŒeÃÌÌÌÌÌU‹ìW‹}3ÀƒÉÿò®A÷ÙOŠE ýò®G8t3Àë‹Çü_ÉÃÌÌÌÌÌÌÌÌÌU‹ìWVS‹Mã&‹Ù‹}‹÷3Àò®÷ÙË‹þ‹u ó¦ŠFÿ3É:GÿwtII÷Ñ‹Á[^_ÉÃVj è0!ÿt$ èj ‹ðè!ƒÄ ‹Æ^Ã=„eSV‹5ˆNWte…öu95NtYèï+…ÀuP‹5ˆN…ötF‹\$…Ût>SèX+Y‹ø‹…Àt/PèI+;ÇYv‹€<8=uWSPèè*ƒÄ …ÀtƒÆëÓ‹D8ë3À_^[ÃÌÌÌÌÌÌÌÌÌ̃ìÝ$èM.è ƒÄÃT$èø-R›Ù<$tPf<$tÙ-8ÝÙþ›ßàžzƒ=`N…'.º Pé$.Û-:ÝÙÉÙõ›ßàžzøÝÙÙþëÍèŠ-ë©ÿÿuòƒ|$uëÝØÛ-°B¸ƒ=`N…Ò-º PèË.ZÃÌ̃ìÝ$è-è ƒÄÃT$èH-R›Ù<$tPf<$tÙ-8ÝÙÿ›ßàžzƒ=`N…w-º `ét-Û-:ÝÙÉÙõ›ßàžzøÝÙÙÿëÍèÚ,ë©ÿÿuòƒ|$uëÝØÛ-°B¸ƒ=`N…"-º `è.ZÃÌ̃ìÝ$èí,è ƒÄÃT$è˜,R›Ù<$‹D$ tQf<$tèP,©€uÙúƒ=`N…Ã,º péÀ,©ðu,©ÿÿu%ƒ|$uëÌè%,ë"©ÿÿuòƒ|$uë%€t°ÝØÛ-°B¸ƒ=`N…f,º pè_-ZÃV‹t$ WVèrÿNYx‹ŠD$ ¶øˆÿëVÿt$èn-Y‹øYVè›Y‹Ç_^Ãÿt$ÿt$è¸ÿÿÿYYÃSV‹t$ WVè&VèS.ÿt$ ‹øÿt$ Vèú.VW‹ØèÇ.VèSƒÄ ‹Ã_^[ÃSV‹t$ WVèëVè.‹øD$ Pÿt$ Vè¾.VW‹Øè‹.VèƒÄ ‹Ã_^[á€eVj…À^u¸ë;Æ}‹Æ£€ejPè™8Y£pU…ÀYu!jV‰5€eè€8Y£pU…ÀYujèRY3ɸx‹pU‰ƒÀ ƒÁ=ø|ê3ɺˆ‹ñ‹ÁÁþƒà‹4µ@TÀ‹†ƒøÿt…Àuƒ ÿƒÂ Aúè|Ñ^Ãè[:€= NtéB9ËD$¹x;Ár=Øw+ÁÁøƒÀPèÖYÃÀ Pÿ0ËD$ƒø} ƒÀPè·YËD$ƒÀ Pÿ0ËD$¹x;Ár=Øw+ÁÁøƒÀPèåYÃÀ Pÿ,ËD$ƒø} ƒÀPèÆYËD$ƒÀ Pÿ,Ãj èF<jèG:YYjè•÷ÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌWVS3ÿ‹D$ À}G‹T$÷Ø÷ڃ؉D$‰T$‹D$ À}G‹T$÷Ø÷ڃ؉D$‰T$ Àu‹L$‹D$3Ò÷ñ‹Ø‹D$÷ñ‹ÓëA‹Ø‹L$‹T$‹D$ÑëÑÙÑêÑØ Ûuô÷ñ‹ð÷d$‹È‹D$÷æÑr;T$wr;D$vN3Ò‹ÆOu÷Ú÷؃Ú[^_‹D$ƒø…ˆÿ$j£lNè¹…ÀYt<¡lN3ÉŠ mN%ÿÁ-lN£tN‰ xNÁàÁ£pNè´ …Àu èÕ3Àërÿ(£hUèd?£´Nè4è=èJ<èöÿÿÿ°Në>3É;Áu,9 °N~½ÿ °N9 ¤Nuè9öÿÿèƒ5èŸ èpë ƒøuQè%!YjX U‹ìS‹]V‹u W‹}…öu ƒ=°Në&ƒþtƒþu"¡lU…Àt WVSÿÐ…Àt WVSèçþÿÿ…Àu3ÀëNWVSèá?ƒþ‰E u …Àu7WPSèÃþÿÿ…ötƒþu&WVSè²þÿÿ…Àu!E ƒ} t¡lU…ÀtWVSÿЉE ‹E _^[] ¡¼Nƒøt …Àuƒ=ÀNuè´9ÿt$èä9hÿÿYYÃhhè?YYÃU‹ìƒìݨÜÝ]øÝ ÜÝ]ðÝEðÜuøÜMøÜmðÝ]èÝEèÜhÌßàžvjXÉÃ3ÀÉÃhÌÜÿ…Àth°ÜPÿ …ÀtjÿÐÃé™ÿÿÿV‹t$¾PèF@ƒøeYt,Fƒ=œB~¾jPè "YY뾋 @ŠAƒà…ÀuÔŠ  BŠˆFŠˆŠÁŠF„Éuó^ËD$Š BŠ„Ét :ÊtŠH@„ÉuôŠ@„Ét*Š„Ét €ùet€ùEt@ëí‹ÈH€80tú8uHŠ@A„ÒˆuöËD$ÝÜxÌßàžrjXÃ3ÀÃU‹ìQQƒ}ÿutEøPèID‹E YY‹Mø‰‹Mü‰HÉÃEPè[D‹E YY‹M‰ÉÃU‹ìƒì(EØVPEðP‹EQQÝÝ$èÕD‹uEðP‹U FP3Àƒ}ð-”À3É…öŸÁÐÊQè6DEðjPÿuVÿu è ‹E ƒÄ0^ÉÃU‹ìS3Û8]V‹uW‹}t3À9] ŸÀP3Àƒ>-”ÀÇPèvYYƒ>-‹ÇuÆ-G9] ~ŠPHˆ‹ÁŠ  Bˆ3É8]hØÜ”ÁÈM Qè;E9]YY‹ÈtÆE‹F A€80t<‹^Ky÷ÛÆ-Aƒûd|‹Ãjd™^÷þ‹Ã™÷þ‹ÚAƒû |‹Ãj ™^÷þ‹Ã™÷þ‹ÚY‹Ç_^[]ÃU‹ìƒì(EØVPEðP‹EQQÝÝ$è²C‹uEðP‹EôÆP3Àƒ}ð-”ÀE PèCEðjPVÿu è ‹E ƒÄ,^ÉÃU‹ìSV‹u‹]W‹FH€}t;E u3Ƀ>-”ÁÈË‹ÁÆ0€`ƒ>-‹ûuÆ-{‹F…ÀjWè?YÆ0YGëøƒ} ~DjWè'  BYˆ‹vGY…ö}+€}t÷Þë÷Þ9u |‰u ÿu Wèùÿu j0WèáDƒÄ_‹Ã^[]ÃU‹ìƒì(SVEØWPEðP‹EQQÝÝ$è´B‹Eô‹]pÿ3Àƒ}ð-”ÀE ‹øEðPSWèB‹EôƒÄH;ðœÁƒøü|&;Ã}"„Ét ŠG„Àuù GþEðjPSÿu èåþÿÿƒÄëEðjPÿuSÿu è·ýÿÿƒÄ_^[ÉÃU‹ìƒ}et2ƒ}Et,ƒ}fuÿuÿu ÿuèNþÿÿƒÄ ]Ãÿuÿuÿu ÿuè4ÿÿÿëÿuÿuÿu ÿuèýÿÿƒÄ]ÃW‹|$ …ÿtV‹t$ VèÏ@PV÷Vè4DƒÄ^_áÈN…Àtÿt$ÿÐ…ÀYtjXÃ3ÀÃV‹t$jƒ&ÿf8MZu‹H<…Ét ÁŠHˆŠ@ˆF^ÃU‹ì¸,èG…hÿÿÿSPÇ…hÿÿÿ”ÿ…Àtƒ½xÿÿÿuƒ½lÿÿÿrjXé…ÔíÿÿhPhøÜÿ…À„Ð3ÛÔíÿÿ8ÔíÿÿtŠj,PèÚðÿÿY;ÃYt0@‹È8t€9;uˆëA8uòj SPèìÿÿƒÄ ƒøtƒøtƒøtEüPè˜þÿÿ€}üYÀƒÀ[ÉÃ3Àj9D$h”ÀPÿø€…À£`Ut6è“þÿÿƒø£dUu høèÌYë ƒøuè …Àuÿ5`Uÿü€3ÀÃjXádUVƒøWufS3Û9TUU‹-D~@¡XU‹=ô€p h@hÿ6ÿ×h€jÿ6ÿ×ÿvjÿ5`UÿÕƒÆC;TU|Îÿ5XUjÿ5`UÿÕ][ë'ƒøu"¿ ‹÷‹F…Àth€jPÿô€‹6;÷uåÿ5`Uÿü€_^Ãh@jÿ5`UÿH…À£XUuËL$ƒ%PUƒ%TUj£LU‰ \UÇDUXáTU €¡XU ˆ;Ás‹T$+P úrƒÀëè3ÀÃU‹ìƒì‹MSV‹u ‹AW‹þƒÆü+y Áï‹ÏiÉŒD‰Mð‹IöÁ‰Mü…æ‹11‰Uô‹Vü‰Uø‹Uôö‰] u~ÁúJƒú?vj?Z‹K;KuLƒú s»€‹ÊÓëL÷Ó!\¸Dþ u(‹M!ë!JເÓëL÷Ó!œ¸Äþ u‹M!Y‹Mü‹] ë‹Mü‹S‹[Mô‰Z‹U ‰Mü‹Z‹R‰S‹ÑÁúJƒú?vj?Z‹]øƒã‰]ô…”+uø‹]øÁûj?‰u K^;Þv‹ÞMø‹Ñ‰MüÁúJ;Öv‹Ö;Útc‹M ‹q;qu@ƒû s¾€‹ËÓî÷Ö!t¸DþLu&‹M!1ëKྀÓî÷Ö!´¸ÄþLu‹M!q‹M ‹q‹I‰N‹M ‹q‹I‰N‹u ë‹]ƒ}ôu;Ú„‹Mð‹\Ñ щ^‰N‰q‹N‰q‹N;Nu`ŠLƒú ˆMþÁˆLs%€}u»€‹ÊÓë‹M »€‹ÊÓëD¸D ë)€}uJເÓë‹M YJ຀Óê„¸Ä ‹Eü‰‰D0ü‹Eðÿ…÷¡PU…À„Ü‹ HU‹5ô€ÁáH »€h@SQÿÖ‹ HU¡PUº€Óê P¡PU‹ HU‹@ƒ¤ˆÄ¡PU‹@þHC¡PU‹H€yCu ƒ`þ¡PUƒxÿuiSjÿp ÿÖ¡PUÿpjÿ5`UÿD¡TU‹XU€Áà‹È¡PU+ÈLìQHQPè2>‹EƒÄ ÿ TU;PUvƒm¡XU£LU‹E‰=HU£PU_^[ÉÃU‹ìƒì¡TU‹XUSV€W<‚‹E‰}üHƒáð‰MðÁùIƒù }ƒÎÿÓîƒMøÿ‰uôëƒÁàƒÈÿ3öÓè‰uô‰Eø¡LU‹Ø;߉]s‹K‹;#Mø#þ Ïu ƒÃ;]ü‰]rç;]üuy‹Ú;؉]s‹K‹;#Mø#þ ÏuƒÃëæ;ØuY;]üsƒ{uƒÃ‰]ëí;]üu&‹Ú;؉]s ƒ{uƒÃëî;Øuè8‹Ø…Û‰]tSèÚY‹K‰‹Cƒ8ÿu3Àé‰LU‹C‹ƒúÿ‰Uüt‹ŒÄ‹|D#Mø#þ Ïu7‹Ä‹pD#Uø#uôƒeüHD Ö‹uôu‹‘„ÿEü#UøƒÁ‹þ#9 ×té‹Uü‹Ê3ÿiÉŒD‰Mô‹LD#Îu ‹ŒÄj #Mø_…É|ÑáGë÷‹Mô‹Tù‹ +Mð‹ñ‰MøÁþNƒþ?~j?^;÷„ ‹J;Juaƒÿ }+»€‹ÏÓë‹Mü|8÷Ó‰]ì#\ˆD‰\ˆDþu8‹]‹Mì! ë1OເÓë‹Mü|8ŒˆÄ÷Ó!þ‰]ìu ‹]‹Mì!Kë‹]‹J‹zƒ}ø‰y‹J‹z‰y„”‹Mô‹|ñ ñ‰z‰J‰Q‹J‰Q‹J;JudŠLƒþ ˆM })þÁ€} ˆLu ¿€‹ÎÓï ;¿€‹ÎÓï‹Mü |ˆDë/þÁ€} ˆLu Nà¿€Óï {‹Mü¼ˆÄNྀÓî 7‹Mø…Ét ‰ ‰Lüë‹Mø‹uðÑN‰ ‰L2ü‹uô‹…Éy‰>u;PUu‹Mü; HUuƒ%PU‹Mü‰B_^[ÉáTU‹ DUVW3ÿ;Áu0D‰PÁàPÿ5XUWÿ5`Uÿ@;ÇtaƒDU£XU¡TU‹ XUhÄAj€ÿ5`U4ÿH;ljFt*jh hWÿð€;ljF uÿvWÿ5`UÿD3ÀëƒNÿ‰>‰~ÿTU‹Fƒÿ‹Æ_^ÃU‹ìQ‹MSVW‹q‹A3Û…À|ÑàCë÷‹Ãj?iÀZ„0D‰Eü‰@‰@ƒÀJuô‹ûjÁçy hh€Wÿð€…ÀuƒÈÿé“—p;úwu‹F£@>þ t ‹F‹Vj‰‹‹N‰Hÿ5`UÿD^à 0ÿ^ÃU‹ìQSV‹5$Wƒ~ÿ„”ƒeü¾ »ð??ðu9‹Ãh@FhPÿô€…Àtƒÿÿ ÌN‹F …Àt;Çv‰~ ÿEüÿMt ëƒï…Û}²ƒ}ü‹Î‹vt,ƒyÿu&jA Zƒ8ÿu BƒÀú|ïúuQèÿÿÿY;5$t ƒ}Pÿÿÿ_^[ÉËD$º V‹Ê;Av;Ar‹ ;Êt7ëî¨u1‹ðºæÿ;òr ‹t$ ‰‹t$‹Èfáð+Á‰+Â^ÁøDÃ3À^ËD$‹L$+HÁù DÈ‹L$ ¶€!8ðÇ@ñuÿÌNƒ=ÌN ujè¤þÿÿYÃU‹ìQQSV‹5@>W‹Vƒúÿ„Ÿ‹~Ž ‹Ç+ƃèÁøÁà Â;ù‰Eüs:‹‹];Ë|9_vSQPè¹ƒÄ …Àuu‹Eü‰_ƒÇŽ ;ù‰EürÈë‹]‹F‹N~‰Eø;ø‰Müs3‹;Ã|9_vSPÿuüèjƒÄ …Àu&‰_EüƒÇ;}ørÒë‹]‹6;5@>téCÿÿÿ‰5@>)‰~é(¸ ‹øƒÿtƒ u ‹?;ø„×ëè‹_ ƒeü‹ó‹Ã+÷ƒîÁþÁæ wƒ;ÿuƒ}ü} ƒÀÿEüƒ8ÿtï‹EüjÁà hPV‰Eøÿð€;Æ…¸jÿuøVè¦1‹UüƒÄ …Ò‹Ë~0F‰Uü€ˆôÿP‰Püºð‰‰ÇAñƒÁÿMüuÖ‰=@>‡ ;Ès ƒ9ÿtƒÁëò;ÈÀ#Á‰G ‹EˆF‰_))FL†‰ë4è4ûÿÿ…Àt)‹HˆYT£@>‰ºð+Ó‰Q¶Ó)Pë3À_^[ÉÃU‹ìQ‹M‹USV‹qW‹9™ø;ò‰}ü‹Ç‰]r!ˆ;Ãs)Që ƒaA‰GéÎ÷€>t‹Æ4;ósCŠ„Ûu0jX^€;uCFë÷;òsN;Eüu‰që )u 9U ‚™‹}ü‹Ãë¶óÆ4;ur½q;÷s~;EsvŠ„Àu@j^X€;u%C@ë÷;]s +ò‰‰që ƒaq‰1ˆƒÀë6;Âs)E 9U r4‹óë®¶Àðë§;]s +‰‰Aë ƒaA‰ˆFkÉÁà+Áë3À_^[ÉÃU‹ìQ‹US‹] V¶ W‹}ƒeü‹Ã+GÁø ;M|Çv‹E+ȈÇGñë`se‹E4ƒø;ÆrU;Æs €8u@ëô;ÆuBŠEˆ‹;Ðw+;ðv'ƒø;ðs3À‰38u@€<tù‰Cë ƒcC‰+MÇEü‹Eü_^[ÉÃV‹5Ä€ÿ5Œ>ÿÖÿ5|>ÿÖÿ5l>ÿÖÿ5L>ÿÖ^ÃVW‹=À€¾H>‹…Àt+þŒ>t#þ|>tþl>tþL>t Pÿ×ÿ6è,ÔÿÿYƒÆþ?|Äÿ5l>ÿ×ÿ5|>ÿ×ÿ5Œ>ÿ×ÿ5L>ÿ×_^ÃU‹ì‹EVƒ<…H>4…H>u>Wjè£Òÿÿ‹øY…ÿujèÂåÿÿYjèÊÿÿÿƒ>YWu ÿÄ€‰>ëè±ÓÿÿYjè Y_ÿ6ÿ0^]ÃU‹ì‹Eÿ4…H>ÿ,]ÃÌÌU‹ìSVWUjjhÐÿuè^]_^[‹å]ËL$÷A¸t‹D$‹T$‰¸ÃSVW‹D$PjþhØdÿ5d‰%‹D$ ‹X‹p ƒþÿt.;t$$t(4v‹ ³‰L$‰H ƒ|³uh‹D³è@ÿT³ëÃdƒÄ _^[Ã3Àd‹ yØu‹Q ‹R 9Qu¸ÃSQ»?ë SQ»?‹M‰K‰C‰k Y[ÂÌÌVC20XC00U‹ìƒìSVWUü‹] ‹E÷@…‚‰Eø‹E‰EüEø‰Cü‹s ‹{ƒþÿta vƒ|tEVUkÿT]^‹] Àt3x<‹{Sè©þÿÿƒÄkVSèÞþÿÿƒÄ vj‹Dèaÿÿÿ‹‰C ÿT‹{ v‹4롸ë¸ëUkjÿSèžþÿÿƒÄ]¸]_^[‹å]ÃU‹L$‹)‹AP‹APèyþÿÿƒÄ]ÂÌÌÌÌÌÌÌÌU‹ìWV‹u ‹M‹}‹Á‹ÑÆ;þv;ø‚x÷ÇuÁéƒâƒùr)ó¥ÿ$•Ø"‹Çºƒér ƒàÈÿ$…ð!ÿ$è"ÿ$l"","P"#ÑŠˆŠFˆGŠFÁéˆGƒÆƒÇƒùrÌó¥ÿ$•Ø"I#ÑŠˆŠFÁéˆGƒÆƒÇƒùr¦ó¥ÿ$•Ø"#ÑŠˆFÁéGƒùrŒó¥ÿ$•Ø"IÏ"¼"´"¬"¤"œ"”"Œ"‹DŽä‰Dä‹DŽè‰Dè‹DŽì‰Dì‹DŽð‰Dð‹DŽô‰Dô‹DŽø‰Dø‹DŽü‰Düðøÿ$•Ø"‹ÿè"ð"ü"#‹E^_Éʈ‹E^_ÉʈŠFˆG‹E^_ÉÃIŠˆŠFˆGŠFˆG‹E^_ÉÃt1ü|9ü÷Çu$Áéƒâƒùr ýó¥üÿ$•p$‹ÿ÷Ùÿ$ $I‹Çºƒùr ƒà+Èÿ$…x#ÿ$p$ˆ#¨#Ð#ŠF#шGNÁéOƒùr¶ýó¥üÿ$•p$IŠF#шGŠFÁéˆGƒîƒïƒùrŒýó¥üÿ$•p$ŠF#шGŠFˆGŠFÁéˆGƒîƒïƒù‚Zÿÿÿýó¥üÿ$•p$I$$,$4$<$D$L$T$g$‹DމD‹DމD‹DމD‹DމD‹DŽ ‰D ‹DމD‹DމDðøÿ$•p$‹ÿ€$ˆ$˜$¬$‹E^_ÉÊFˆG‹E^_ÉÃIŠFˆGŠFˆG‹E^_ÉÊFˆGŠFˆGŠFˆG‹E^_ÉÃVèàùÿÿÿ°€ƒøÿ£ ?t:jtjèh‹ðY…öYt)Vÿ5 ?ÿ´€…ÀtVè4Yÿ¸€ƒNÿj‰X^Ã3À^Ãè¶ùÿÿ¡ ?ƒøÿtPÿ¬€ƒ ?ÿËD$Ç@PÐCÇ@ÃVWÿ €ÿ5 ?‹øÿ¤€‹ð…öu?jtjèÝ‹ðY…öYt&Vÿ5 ?ÿ´€…ÀtVè©ÿÿÿYÿ¸€ƒNÿ‰ëjèŒßÿÿYWÿ¨€‹Æ_^á ?ƒøÿ„‘V‹t$…öu Pÿ¤€‹ð…ötl‹F$…ÀtPè[ÍÿÿY‹F(…ÀtPèMÍÿÿY‹F0…ÀtPè?ÍÿÿY‹F8…ÀtPè1ÍÿÿY‹F@…ÀtPè#ÍÿÿY‹FD…ÀtPèÍÿÿY‹FP=ÐCtPèÍÿÿYVèýÌÿÿYjÿ5 ?ÿ´€^ÃVèv‹L$3ö‰¸(?;t"ƒÀF=@|ñƒùr"ƒù$wèBÇ ^Ãè5‹ õ,?^‰Ãù¼rùÊw èÇ^ÃèÇ^ÃèþÿÿƒÀÃèxþÿÿƒÀ ÃS3Û9lPu‹D$ƒøa|YƒøzTƒè [ÃV¾,TWVÿ9(T‹=œ€tVÿ×jè&øÿÿYj[ÿt$è…ÛY‰D$t jèjøÿÿYëVÿ׋D$_^[ÃU‹ìQƒ=lPSu‹EƒøaŒ¯ƒøz¦ƒè éž‹]û}(ƒ=œB~ jSè…YYë ¡@ŠXƒà…Àu‹Ãëk‹@‹ÃÁø¶ÈöDJ€t€e ˆEˆ] jë €e ˆ]jXMüjjjQPEPhÿ5lPè°)ƒÄ …Àt©ƒøu¶Eüë ¶Eý¶MüÁà Á[ÉÃU‹ìQ‹EHùw ‹ @·AëR‹ÈV‹5@Áù¶ÑöDV€^t€eþˆMüˆEýjë €eýˆEüjXM jjjQPEüPjèO+ƒÄ…ÀuÉ÷E #E ÉÃU‹ìjÿhÝh° d¡Pd‰%ƒìSVW¡dUƒøuFj è†öÿÿYƒeü‹uVèäÿÿY‰Eä…Àt ‹vüƒî ‰uàë‹uàƒMüÿè ƒ}äëU‹uàj èªöÿÿYÃøuFj è;öÿÿYÇEüEÜPEÔPÿuèñÿÿƒÄ ‰EØ…Àt ¶0Áæ‰uàë‹uàƒMüÿè-ƒ}Øuÿujÿ5`Uÿ”€‹ð‹Æ‹Mðd‰ _^[ÉËuàj è/öÿÿYÃU‹ìƒ}u3À]Ãÿ5 Rÿuÿu ÿuÿujÿ5$Tèl+ƒÄ…Àu¸ÿÿÿ]ÃÀþ]ÃÌÌÌÌÌÌÌÌÌÌÌÌÌ‹L$÷ÁtŠA„Àt@÷Áuñ‹ºÿþþ~Ѓðÿ3ƒÁ©tè‹Aü„Àt2„ät$©ÿt©ÿtëÍAÿ‹L$+ÁÃAþ‹L$+ÁÃAý‹L$+ÁÃAü‹L$+ÁÃQSUV‹5NW3ÿ‹;ÇtN‹€WWWWjÿPWjÿÓ‹è;ït>Uè—Çÿÿ;ÇY‰D$t/WWUPjÿÿ6WjÿÓ…ÀtWÿt$è1‹FƒÆY;ÇYu¸3À_^][YÃÈÿëõÌÌÌÌÌÌÌ€zuf‹\ÿÿÿ€Ï€çþ³?ëf»?f‰^ÿÿÿÙ­^ÿÿÿ»ÌBÙ剕lÿÿÿ›Ý½`ÿÿÿÆ…pÿÿÿ›ŠaÿÿÿÐáÐùÐÁŠÁ$×¾Àá‹Ú؃Ãÿ#€zuf‹\ÿÿÿ€Ï€çþ³?ëf»?f‰^ÿÿÿÙ­^ÿÿÿ»ÌBÙ剕lÿÿÿ›Ý½`ÿÿÿÆ…pÿÿÿÙÉŠaÿÿÿÙå›Ý½`ÿÿÿÙÉŠ­aÿÿÿÐåÐýÐÅŠÅ$׊àÐáÐùÐÁŠÁ$×ÐäÐä ľÀá‹Ú؃Ãÿ#èÁÙÉÝØÃè·ëöÝØÝØÙîÃÝØÝØÙèÃÛ½bÿÿÿÛ­bÿÿÿö…iÿÿÿ@tÆ…pÿÿÿÃÆ…pÿÿÿÜÄBÃÙÉÛ½bÿÿÿÛ­bÿÿÿö…iÿÿÿ@t Æ…pÿÿÿëÆ…pÿÿÿÞÁÃÛ½bÿÿÿÛ­bÿÿÿö…iÿÿÿ@t ÙÉÛ½bÿÿÿÛ­bÿÿÿö…iÿÿÿ@t Æ…pÿÿÿëÆ…pÿÿÿÞÁÃÝØÝØÛ-°B€½pÿÿÿÆ…pÿÿÿ Éà ÉtÙàÃÌÌÌÌÌÌÙÀÙüÜáÙÉÙàÙðÙèÞÁÙýÝÙËT$âƒÊf‰T$Ùl$ét¸ÃÜ0ݸËB%ð=ðtÝËBƒì ÿ‰D$‹B‹ ¤È Áá ‰D$‰ $Û,$ƒÄ ©‹BËD$%ð=ðtËD$Ãf<$tÙ,$ZÃf‹$f=tfƒà t›ßàfƒà t ¸èÙZÃÙ,$ZÃìÝ$‹D$ƒÄ%ðëƒìÝ$‹D$ƒÄ%ðt==ðt_f‹$f=t*fƒà u!›ßàfƒà t¸ƒútè{ZÃè]ZÃÙ,$ZÃÝ\ÝÙÉÙýÝÙÙÀÙáÜLÝ›ßàž¸sÇÜ lÝë¿ÝTÝÙÉÙýÝÙÙÀÙáÜDÝ›ßàž¸vžÜ dÝë–ÌÌÌÌU‹ìƒÄà‰Eà‹E‰Eð‹E‰Eôë U‹ìƒÄà‰EàÝ]ø‰Mä‹E‹M‰Eè‰MìEMàPQRèž/ƒÄ ÝEøf}tÙmÉÃU‹ìSV‹u ‹F ‹^¨‚„ö¨@…î¨tƒf¨„Þ‹N$þ‰‰F ‹F ƒfƒe $ï f© ‰F u"þ˜tþ¸u Sè3…ÀYuVè²2Yf÷F Wtg‹F‹>+øH‰‹NI…ÿ‰N~WPSè™0ƒÄ ‰E ë6ƒûÿt‹Ë‹ÃÁùƒà‹ @TÀë¸èBö@ t jjSè†/ƒÄ ‹FŠMˆëjE_WPSèC0ƒÄ ‰E 9} _tƒN ë‹E%ÿë ‰F ƒÈÿ^[]ÃV‹t$ÿvèB2…ÀYtwþ˜u3Àë þ¸ucjXÿ¬Nf÷F uRƒ<…0OSW<…0O»u Sè3Âÿÿ…ÀY‰uFj‰F‰X‰F‰Fë ‹?‰^‰~‰>‰^fN jX_[^Ã3À^Ã|$Vt ‹t$ öF tVè €f îƒfƒ&ƒfY^ÃU‹ììHSVW‹} 3öŠG„Û‰uô‰uì‰} „ô‹Mð3Òë‹Mð‹uÐ3Ò9UìŒÜ€û |€ûx¾ÃŠ€T݃àë3À¾„ÆtÝÁøƒø‰EЇšÿ$…S7ƒMðÿ‰ỦU؉Uà‰Uä‰Uü‰UÜéx¾Ãƒè t;ƒèt-ƒètHHtƒè…YƒMüéPƒMüéGƒMüé>€Mü€é5ƒMüé,€û*u#EPèõ…ÀY‰EàƒMü÷؉Eàé‹Eà¾Ë€DAÐëé‰Uðéí€û*uEPè¶…ÀY‰EðÓƒMðÿéʉ¾ËDAЉEð鸀ûIt.€ûht €ûlt€ûw… €Mýé—ƒMü鎃Mü é…€?6u€4uGG€Mý€‰} él‰UЋ @‰UܶÃöDA€tEìPÿu¾ÃPèŠƒÄ G‰} EìPÿu¾ÃPèfƒÄ é%¾Ãƒøgƒøe–ƒøXë„xƒèC„ŸHHtpHHtlƒè …éf÷Eü0u€Mý‹uðƒþÿu¾ÿÿÿEPèœf÷EüY‹È‰Mø„þ…Éu ‹ äB‰MøÇEÜ‹Á‹ÖN…Ò„Ôfƒ8„Ê@@ëçÇÈà ƒMü@½¸ýÿÿ;ʉ}øÏÇEðéÑf÷Eü0u€Mýf÷EüEPt;è0P…¸ýÿÿPèè.ƒÄ ‰Eô…À}2ÇEØë)ƒèZt2ƒè tÅH„èéèØYˆ…¸ýÿÿÇEô…¸ýÿÿ‰EøéçEPè³…ÀYt3‹H…Ét,öEýt¿Ñè‰Mø‰EôÇEÜ鵃e܉Mø¿é£¡àB‰EøPéŽu €ûguÇEð‹EÿũÀ‰Eÿuð‹Hø‰M¸‹@ü‰E¼¾ÃP…¸ýÿÿPE¸Pÿ‹uüƒÄæ€tƒ}ðu…¸ýÿÿPÿY€ûgu…öu…¸ýÿÿPÿY€½¸ýÿÿ-u €Mý½¹ýÿÿ‰}øWè‰õÿÿYéüƒèi„у脞H„„HtQƒè„ýýÿÿHH„±ƒè…ÉÇEÔ'ë<+ÁÑøé´…Éu ‹ àB‰Mø‹Á‹ÖN…Òt€8t@ëñ+ÁéÇEðÇEÔöEü€ÇEôt]ŠEÔÆEê0QÇEäˆEëëHöEü€ÇEôt;€Mýë5EPèöEü Yt f‹Mìf‰ë‹Mì‰ÇEØé#ƒMü@ÇEô öEý€t EPèíYëAöEü t!öEü@EPt èÈY¿À™ë%è¼Y·ÀëòöEü@EPtè§YëàèŸY3ÒöEü@t…Ò|…Às÷؃ҋð÷Ú€Mý‹úë‹ð‹úöEý€uƒçƒ}ð} ÇEðëƒeü÷‹Æ ÇuƒeäE·‰Eø‹EðÿMð…À‹Æ Çt;‹Eô™RPWV‰EÀ‰UÄèG-ÿuċ؃Ã0ÿuÀWVèÅ,ƒû9‹ð‹ú~]Ô‹EøÿMøˆëµE·+EøÿEøöEý‰Eôt‹Mø€90u…Àu ÿMø@‹MøÆ0‰Eôƒ}Ø…ô‹]üöÃ@t&öÇtÆEê-ëöÃtÆEê+ë öÃt ÆEê ÇEä‹uà+uä+uôöà uEìPÿuVj èƒÄEìPEêÿuÿuäPè2ƒÄöÃtöÃuEìPÿuVj0èåƒÄƒ}ÜtAƒ}ô~;‹Eô‹]øxÿf‹CPEÈPCè +Y…ÀY~2MìQÿuPEÈPèØƒÄ‹ÇO…ÀuÐëEìPÿuÿuôÿuøèºƒÄöEütEìPÿuVj èqƒÄ‹} ŠG„Û‰} …ùÿÿ‹Eì_^[ÉÃÑ1§0Â01E1M1‚12U‹ì‹M ÿIx‹ŠEˆÿ¶Àë QÿuèÎöÿÿYYƒøÿ‹Euƒÿ]Ãÿ]ÃVW‹|$‹ÇO…À~!‹t$Vÿt$ÿt$è¬ÿÿÿƒÄ ƒ>ÿt‹ÇO…Àã_^ÃS‹\$ ‹ÃKVW…À~&‹|$‹t$¾WFÿt$PèuÿÿÿƒÄ ƒ?ÿt‹ÃK…Àâ_^[ËD$ƒ‹‹@üËD$ƒ‹‹Aø‹QüËD$ƒ‹f‹@üÃU‹ìƒìHSVWh€è´¹ÿÿ‹ðY…öujèÓÌÿÿY‰5@TÇ@U †€;ðs€fƒÿƒfÆF ¡@TƒÆ$€ëÞE¸Pÿ€€fƒ}ê„Ñ‹Eì…À„Æ‹8X;‰Eü¸;ø|‹ø9=@U}V¾DTh€è ¹ÿÿ…ÀYt<ƒ@U ‰ˆ€;Ás€`ƒÿƒ`Æ@ ‹ƒÀ$Á€ëàƒÆ9=@U|·ë‹=@U3ö…ÿ~L‹Eü‹ƒùÿt8Ѝt2¨u Qÿ„€…Àt#‹Î‹ÆÁùƒà‹ @TÀ‹Mü‹ ‰Š ˆHƒEüFC;÷|´3Û‹ @TÛƒ<ÿ4uM…ÛÆFujöXë ‹ÃH÷ØÀƒÀõPÿˆ€‹øƒÿÿtWÿ„€…Àt %ÿ‰>ƒøu€N@ëƒøu €Në€N€Cƒû|—ÿ5@UÿŒ€_^[ÉÃSVW¾@T‹…Àt7‹ø€;øs!_ ƒ{ütSÿÀ€‹ƒÇ$€ƒÃ$;ørâÿ6è¹ÿÿƒ&YƒÆþ@U|¸_^[ÃU‹ìjÿhèÝh° d¡Pd‰%ƒìSVW‹u¯u ‰u ‰uäƒþàw3Û;óuj^ƒÆƒæð‰u ë3Û‰]àƒþà‡¨¡dUƒøuA‹}ä;=\Uw|j èäÿÿY‰]üWèjÕÿÿY‰EàƒMüÿè9]àt^ÿuäëH3Û‹u j èµäÿÿYÃøuA;5D>w9j è>äÿÿYÇEü‹ÆÁèPèÁßÿÿY‰EàƒMüÿèL9]àtVSÿuàèŸƒÄ 9]àu>Vjÿ5`UÿH‰Eà9]àu'9ÄNtVè¤ÎÿÿY…À…0ÿÿÿë3Û‹u j è,äÿÿYËEà‹Mðd‰ _^[ÉÃSWj3Ûè¬ãÿÿYj_9=€e~]V¡pU‹÷Áæ‹…ÀtAö@ ƒt Pèç'ƒøÿYtCƒÿ|)¡pU‹ƒÀ PÿÀ€¡pUÿ4èT·ÿÿ¡pUYƒ$G;=€e|¥^jèãÿÿY‹Ã_[ÃV‹t$Vè#…ÀYtƒÈÿ^ÃöF @tÿvèõ'÷ØY^ÀÃ3À^ÃSV‹t$ 3ÛW‹F ‹Èƒá€ùu7f©t1‹F‹>+ø…ÿ~&WPÿvè-#ƒÄ ;Çu‹F ¨€t$ý‰F ëƒN ƒËÿ‹Fƒf‰_‹Ã^[ÃjèYÃSVWj3Û3ÿè•âÿÿ3öY95€e~t¡pU‹°…Àt_ö@ ƒtYPVè¨Åÿÿ¡pUYY‹°‹H öÁƒt0ƒ|$uPèÿÿÿƒøÿYtCëƒ|$uöÁtPèÿÿÿƒøÿYu ø¡pUÿ4°VèªÅÿÿYYF;5€e|Œjèpâÿÿƒ|$Y‹Ãt‹Ç_^[ÃU‹ìƒì ‹EƒeüHSVHWtgHHtFƒètAƒèt<ƒèt*ƒètHtƒÈÿéF‹@O¿@OëB‹1uÿBëWèÞÿÿ@PWVèkƒÄ_^[]ÃU‹ìƒì(VEWPEôPèGYEØYuôPjjƒì ‹ü¥¥f¥è³ ‹u‹}‰F¾EÚ‰¿E؉FEÜPWèÃƒÄ ‰~ ‹Æ_^ÉÃU‹ìQ‹U SVWf‹B¿ÿ‹È%€Áé#ωE ‹B‹·Ù¾€%ÿÿ…Û‰uüt;ßt¹<ë(¿ÿë!3Û;Ãu;Óu‹E‰X‰f‰XëK¹<‰]ü‹ÊÁéÁà È‹E MüÁâ ‰H‰…Îu‹É‹ÚÁë Ù ‰‰XÇÿÿ‹Ëëß‹M Ïf‰H_^[ÉÃÌW‹|$ëj¤$‹ÿ‹L$W÷ÁtŠA„Àt;÷Áuñ‹ºÿþþ~Ѓðÿ3ƒÁ©tè‹Aü„Àt#„ät©ÿt©ÿtëÍyÿë yþëyýëyü‹L$ ÷ÁtŠA„ÒtdˆG÷Áuî뉃Ǻÿþþ~‹Ѓðÿ3‹ƒÁ©tá„Òt4„öt'÷Âÿt÷Âÿtëlj‹D$_Ãf‰‹D$ÆG_Ãf‰‹D$_È‹D$_ËT$ ‹L$…ÒtG3ÀŠD$W‹ùƒúr-÷Ùƒát+шGIuú‹ÈÁàÁ‹ÈÁàÁ‹ÊƒâÁétó«…ÒtˆGJuú‹D$_ËD$ÃÌÌÌÌÌÌÌÌU‹ìWV‹u ‹M‹}‹Á‹ÑÆ;þv;ø‚x÷ÇuÁéƒâƒùr)ó¥ÿ$•xO‹Çºƒér ƒàÈÿ$…Nÿ$ˆOÿ$ O NÌNðN#ÑŠˆŠFˆGŠFÁéˆGƒÆƒÇƒùrÌó¥ÿ$•xOI#ÑŠˆŠFÁéˆGƒÆƒÇƒùr¦ó¥ÿ$•xO#ÑŠˆFÁéGƒùrŒó¥ÿ$•xOIoO\OTOLODOEäPj^VhôàVÿX€…Àt‹ÆëEäPVhðàVSÿ\€…À„ÎjX£ˆPƒøu$‹E;Ãu¡lPÿuÿuÿu ÿuPÿ\€韃ø…”9]u¡|P‰ESSÿuÿu ‹E ÷ØÀƒà@Pÿuÿh€‰Eà;Ãtc‰]ü<‹ÇƒÀ$üèÉüÿÿ‰eè‹ô‰uÜWSVèùÿÿƒÄ ë jXËeè3Û3öƒMüÿ;ót)ÿuàVÿuÿu jÿuÿh€;ÃtÿuPVÿuÿX€ë3ÀeÌ‹Mðd‰ _^[ÉÃU‹ìjÿh áh° d¡Pd‰%ƒì0SVW‰eè3Û9ŒPj_u@W¸ôàPWPSSÿÌ€…Àt‰=ŒPë#W¸ðàPWPSSÿÈ€…À„ÇŒP‹u;ó~VÿuèúYY‹ð‰u9]~ÿuÿuèãYY‰E¡ŒPƒøuÿuÿuVÿuÿu ÿuÿÈ€é§;Ç…9] u¡|P‰E ;ót 9]…˜;uujXéx9}~‹Çél;÷AEÄPÿu ÿ˜€…À„Q;ó~,ƒ}Är"EÊ8]ÊtŠP:Ót‹MŠ :r:Êv­@@8uæjë¥9]~1ƒ}Är¥EÊ8]ÊtŠP:Ót–‹MŠ :r:ʆxÿÿÿ@@8uâézÿÿÿSSVÿuj ÿu ÿh€‰Eä;Äω]üÀƒÀ$üè»úÿÿ‰eè‹Ä‰E܃MüÿëjXËeè3Û‰]܃Müÿ‹uj_9]Ü„“ÿuäÿuÜVÿuWÿu ‹5h€ÿÖ…ÀtySSÿuÿuj ÿu ÿÖ‹ð‰uà;óta‰}ü6ƒÀ$üèLúÿÿ‰eè‹ü‰}؃MüÿëjXËeè3Û3ÿƒMüÿ‹uà;ût-VWÿuÿujÿu ÿh€…ÀtVWÿuäÿuÜÿu ÿuÿÌ€ë3Àe´‹Mðd‰ _^[ÉËT$‹D$…ÒVJÿt €8t@‹ñI…öuó€8^u+D$ËÂÃU‹ìƒìSVWjè|Çÿÿÿuè•‹ØY; RY‰]u3öép…Û„V3Ò¸pE9ttƒÀ0B=`F|ñEèPSÿ˜€j^;Æ…!j@ƒ%$TY3À¿ S9uè󫪉 R†ë€}M҄¯¶Aÿ¶Ò;‡”€ˆ!S@ëîƒeüj@Y3À¿ S4Ró«Á檞€E€;‹Ët,ŠQ„Òt%¶¶ú;Çw‹UüŠ’hE!S@;ÇvõAA€9uÔÿEüƒÃƒ}ürÁ‹EÇRP£ RèζtE¿R¥¥Y£$T¥ëRAA€yÿ…Gÿÿÿ‹Æ€ˆ!S@=ÿrñSè•Y£$T‰5Rëƒ%R3À¿R«««ëƒ=Ptè™è½éŒþÿÿƒÎÿjèHÆÿÿY‹Æ_^[ÉËD$ƒ%PƒøþuÇPÿ%Ô€ƒøýuÇPÿ%Ѐƒøüu¡|PÇPËD$-¤t"ƒètƒè t Ht3ÀøøøøÃWj@Y3À¿ Só«ª3À¿R£ R£R£$T«««_ÃU‹ììEìVPÿ5 Rÿ˜€ƒø…3À¾ˆ„ìþÿÿ@;ÆrôŠEòÆ…ìþÿÿ „Àt7SWUó¶ ¶À;Áw+ȼìþÿÿA¸ ‹ÙÁéó«‹ËƒáóªBBŠBÿ„ÀuÐ_[j…ìúÿÿÿ5$Tÿ5 RP…ìþÿÿVPjèùÿÿj…ìýÿÿÿ5 RVP…ìþÿÿVPVÿ5$TèÕöÿÿj…ìüÿÿÿ5 RVP…ìþÿÿVPhÿ5$Tè­öÿÿƒÄ\3Àìúÿÿf‹öÂt€ˆ!SŠ”ìýÿÿˆ RëöÂt€ˆ!S Š”ìüÿÿë〠 R@AA;Ær¿ëI3À¾ƒøArƒøZw€ˆ!SŠÈ€Á ˆˆ Rëƒøarƒøzw€ˆ!S ŠÈ€é ëà€  R@;Ær¾^ÉÃ=ˆeujýèüÿÿYLjeÃU‹ìQQSVW3ÿ9}tUj=ÿuè]‹ðY;÷Y‰uøt@9ut;¡ˆN3Û8^”Ã;ŒNu Pè›Y£ˆN;ÇuT9} t9=Ntè3Îÿÿ…Àt>ƒÈÿ_^[ÉÃ;ß… jèà•ÿÿ;ÇY£ˆNt߉89=NujèÅ•ÿÿ;ÇY£Ntĉ8+u‹=ˆN‰}üVÿuèЋðY…öY|Cƒ?t>…Ût2ÿ4·<·è–ÿÿYƒ?t ‹GF‰ƒÇëð‹ÆÁàPÿuü茗ÿÿY…ÀYt<ë5‹E‰·ë2…Ûuz…ö}÷ÞµPWèd—ÿÿY…ÀY„@ÿÿÿ‹M‰ °ƒd°£ˆNƒ} tFÿuèÖÌÿÿ@@Pè•ÿÿ‹ðY…öYt.ÿuVèÝïÿÿ‹ÆY+EYEø€ @÷ÛÛ÷Ó#ØSVÿØ€Vè–ÿÿY3ÀéàþÿÿV‹5ˆNW‹…Àt-‹|$WPÿt$è(ÌÿÿƒÄ …Àu ‹Š8<=t„Àt‹FƒÆ…Àu׋Æ+ˆNÁø÷Ø_^ËÆ+ˆNÁøëðW‹|$3É…ÿu3À_Ã?Gt ‹AƒÀ…ÒuöSUVPèK”ÿÿ‹ðY…ö‹îuj èh§ÿÿY‹‹ß…ÀtPƒÃèÛ‰‹YƒÆëéƒ&‹Å^][_ÃU‹ìƒìX‹ESV‹u ·‹WH‰Mt+Ht$HtHtHtHHtHunjëÇëbjë jëjëj[~QWSèRƒÄ …ÀuA‹Eƒøtƒøt ƒøtƒeàþë‹MàÝFƒáãÝ]ЃÉ‰MàNWQPESPE¨PèZƒÄhÿÿÿuè\ƒ>YYtƒ=8Gu Vè&…ÀYuÿ6èòY_^[ÉÃV‹t$;5@Us@‹Î‹ÆÁùƒà‹ @TÀöDt%WVè?ÿt$ÿt$Vè(V‹øèˆƒÄ‹Ç_^Ãè´ÇÿÿÇ è²Çÿÿƒ ƒÈÿ^ÃV‹t$WV軃øÿYu èŠÇÿÿÇ ë-ÿt$jÿt$PÿÜ€‹øƒÿÿuÿ €ë3À…Àt PèãÆÿÿYƒÈÿë‹ÎƒæÁù‹Æ‹ @TÀ€dýD‹Ç_^ÃV‹t$;5@Us@‹Î‹ÆÁùƒà‹ @TÀöDt%WVègÿt$ÿt$Vè(V‹øè°ƒÄ‹Ç_^ÃèÜÆÿÿÇ èÚÆÿÿƒ ƒÈÿ^ÃU‹ììSVW3ÿ9}‰}ø‰}ðu3Àéf‹EÁø…@T‹Eƒà4À‹ÁæöD0 tjWÿuèÛþÿÿƒÄ ‹Æö@€„Á‹E 9}‰Eü‰}†ê…ìûÿÿ‹Mü+M ;Ms)‹MüÿEüŠ €ù uÿEðÆ @ˆ@‹È•ìûÿÿ+Êù|Ì‹ø…ìûÿÿ+øEôjP…ìûÿÿWP‹ÿ40ÿ|€…ÀtC‹EôEø;Ç| ‹Eü+E ;ErŠ3ÿ‹Eø;Ç…9}tbj^9uuLèÄÅÿÿÇ èÂÅÿÿ‰0ëAÿ €‰EëÇMôWQÿuÿu ÿ0ÿ|€…Àt ‹Eô‰}‰Eøë§ÿ €‰EëœÿuèÅÿÿYƒÈÿë,‹öD0@t ‹E €8„ªþÿÿèUÅÿÿÇèSÅÿÿ‰8ëÒ+Eð_^[ÉÃÿ¬NhèmÿÿY‹L$…À‰At ƒI ÇAëƒI A‰AÇA‹Aƒa‰ËD$;@Ur3ÀËȃàÁùÀ‹ @TŠDƒà@ÃU‹ìSV¾,TWVÿ‹=œ€3Û9(TtVÿ×jè!½ÿÿYj[ÿu ÿuèY‰E …ÛYt jèc½ÿÿYëVÿ׋E _^[]ÃU‹ì‹E…Àu]Ã=lPuf‹M fùÿw9jˆX]ÃMƒeQjÿ5œBPE jPh ÿ5|Pÿ€…Àtƒ}tèÄÿÿÇ*ƒÈÿ]ÃÌÌÌÌÌÌÌÌÌÌÌSV‹D$ Àu‹L$‹D$3Ò÷ñ‹Ø‹D$ ÷ñ‹ÓëA‹È‹\$‹T$‹D$ ÑéÑÛÑêÑØ Éuô÷ó‹ð÷d$‹È‹D$÷æÑr;T$wr;D$ vN3Ò‹Æ^[ÂÌÌÌÌÌÌÌÌS‹D$ Àu‹L$‹D$ 3Ò÷ñ‹D$÷ñ‹Â3ÒëP‹È‹\$‹T$ ‹D$ÑéÑÛÑêÑØ Éuô÷ó‹È÷d$‘÷d$Ñr;T$ wr;D$v+D$T$+D$T$ ÷Ú÷؃Ú[ÂV‹t$WƒÏÿöF @tƒf ëV舞ÿÿVèV‹øèÌžÿÿƒÄ ‹Ç_^ÃV‹t$WƒÏÿöF ƒt4VèMØÿÿV‹øèšÿvè²ƒÄ …À}ƒÏÿë‹F…Àt Pè)ÿÿƒfYƒf ‹Ç_^ÃS‹\$;@UVWsr‹ÃÁø<…@T‹Ãƒà4À‹ÁæöD0tRSèÕ‹YöD0t)SèƒYPÿà€…Àu ÿ €‹ðë3ö…ötèEÂÿÿ‰0è5ÂÿÿÇ ƒÎÿSèíY‹ÆëèÂÿÿÇ ƒÈÿ_^[ÃS3Û9”PVWuBhháÿ‹ø;ûtg‹5 h\áWÿÖ…À£”PtPhLáWÿÖh8áW£˜PÿÖ£œP¡˜P…ÀtÿЋ؅Ût¡œP…ÀtSÿЋØÿt$ÿt$ÿt$Sÿ”P_^[Ã3ÀëøÌÌ‹L$ W…ÉtzVS‹Ù‹t$÷Æ‹|$uÁéuoë!ŠFˆGIt%„Àt)÷Æuë‹ÙÁéuQƒãt ŠFˆG„Àt/Kuó‹D$[^_Ã÷ÇtˆGI„Š÷Çuî‹ÙÁéulˆGKuú[^‹D$_ɃÇIt¯ºÿþþ~‹Ѓðÿ3‹ƒÆ©tÞ„Òt,„öt÷Âÿt ÷ÂÿuƉëâÿÿ‰ëâÿ‰ë3Ò‰ƒÇ3ÀIt 3À‰ƒÇIuøƒãu…‹D$[^_ËT$V‹t$ 3À 2;Êr;ÎsjX‹T$^‰ ÃV‹t$W‹|$Vÿ7ÿ6èËÿÿÿƒÄ …ÀtFPjÿ0è·ÿÿÿƒÄ …ÀtÿFFPÿwÿ0èŸÿÿÿƒÄ …ÀtÿFFPÿwÿ0è‡ÿÿÿƒÄ _^ËD$VW‹0‹x‹Îö‰04?Áé ñ‹H‹×‰pÁêÑá Ê_‰H^ËD$VW‹P‹H‹ò‹ùÁæÑé ΉH‹ÁçÑéÑê Ï_‰P‰^ÃU‹ìƒì‹E S‹]3Ò;ÂVÇEüN@‰‰S‰SvQW‰E‹ó}ð¥¥S¥èpÿÿÿSèjÿÿÿEðPSèÿÿÿSèZÿÿÿ‹Eƒeôƒeø¾‰EðEðPSèáþÿÿƒÄÿEÿMu¶3Ò_9Su(‹K‹ÁÁè‰C‹‹ðÁîÁá ñÁàEüðÿ‰s‰ëÓ¾€…suSèôþÿÿEüÿÿYëëf‹Eü^f‰C [ÉÃU‹ìƒì\SVW‹}E¤j‰Eô3ÀZ‰E؉Uè‰Eü‰Eð‰E܉Eà‰EÔ‰EЉEä‰Eø‰Eì‰}Š€ù t€ù t €ù t€ù uGëçj^ŠGƒø ‡wÿ$…€l€û1| €û9jé: BujéF¾Ãƒè+tHHtƒè…ÔéjÇEØ€X맃eØjX란û1‰Uð|€û9~®: B„¼€û+t1€û-t,€û0tR€ûCމ€ûE~€ûcŽ{€ûerjéÈOj éÀ€û1| €û9ŽVÿÿÿ: B„Yÿÿÿ€û0…µ‹Âéÿÿÿ‰Uð9œB~¶ÃVPèã¾ÿÿYYjZë‹ @¶ÃŠA#Æ…Àtƒ}üs‹EôÿEü€ë0ÿEôˆëÿEøŠGë·: Bug‹ÆéÂþÿÿƒ}ü‰Uð‰UÜu €û0uÿMøŠGëó9œB~¶ÃVPèr¾ÿÿYYjZë‹ @¶ÃŠA#Æ…Àtƒ}üs‹EôÿEü€ë0ÿEôÿMøˆŠGë¹€û+„ ÿÿÿ€û-„ÿÿÿéÕþÿÿ9œB‰UÜ~¶ÃVPè¾ÿÿYYjZë‹ @¶ÃŠA#Æ…À„ª‹ÆëWOþ€û1‰M|€û9~D¾Ãƒè+ttHHtdƒè…jëe‰Uà€û0uŠGëö€û1Œò€û9éë €û1|€û9 j XOé¸ýÿÿ€û0uDëÁƒ} t*¾ÃOÿƒè+‰MtHH…´ƒMèÿjXé‰ýÿÿjXéýÿÿj OXƒø „•éoýÿÿ‹}éˆÇEà3öƒ=œB~¶ÃjPè%½ÿÿYYë‹ @¶ÃŠAƒà…Àt¾Ë¶tAÐþPŠGë¾¾Q‰uäƒ=œB~¶ÃjPèÛ¼ÿÿYYë‹ @¶ÃŠAƒà…ÀtŠGëÐOë‹ù‹E ƒ}ð‰8„ÙjX9Eüv€}»|þE»‰Eü‹EôHÿEøë‹Eôƒ}ü†¥H€8uÿMüÿEøëòEÀPE¤ÿuüPèjûÿÿ‹Eä3ÉƒÄ 9Mè}÷ØEø9MàuE9MÜu+E=P~0ÇEÔ‹]‹u‹E‹Uƒ}Ôt`3Û¸ÿ¾€3ÒÇEìë^=°ëÿÿ} ÇEÐëÇÿuPEÀPè´‹UÀ‹]‹uÆ‹EÊƒÄ ëµ3Ò3À3ö3Ûë«3Ò3À3ö3ÛÇEìëƒ}Ðt3Ò3À3ö3ÛÇEì‹M EØ_‰q‰Yf‰A ‹Eì^f‰[ÉÃIh˜hïhitiëi!jkjJjÏj¹j…jU‹ìƒì‹ES‹]V‹È¾ÿá€#Æf…ÉWÆEäÌÆEåÌÆEæÌÆEçÌÆEèÌÆEéÌÆEêÌÆEëÌÆEìÌÆEíÌÆEîûÆEï?ÇEü‹ÐtÆC-ëÆC ‹} f…Òu…ÿu9}ufƒ#ÆC ÆCÆC0éþf;Öuz¸€fÇ;øuƒ}t÷Ç@uhŒáëFf…ÉtÿÀu ƒ}u.h„áë;øu#ƒ}uh|áCPèJßÿÿYÆCYƒeüénhtáCPè-ßÿÿYÆCYëá·Â‹Ï‹ðÁéiÀMÁîfƒeðj Nf‰UúkÉM‰}ö´ í¼ì‹EÁþ‰Eò¿Æ÷ØPEðPè× ƒÄ f}úÿ?rEäFPEðPèž YYöEf‰3t‹}¿Æø…ÿéñþÿÿ‹}ƒÿ~j_·uúîþ?fƒeúÇEEðPè]øÿÿÿMYuñ…ö}÷Þæÿ~ EðPènøÿÿNYuóOC…ɉE~P‰Muð}¥¥EðP¥èøÿÿEðPèøÿÿEPEðPè¦÷ÿÿEðPèû÷ÿÿŠEû‹M€eûƒÄ0ÿEÿMˆu¶‹EŠHÿHH€ù5K|0;Ár€89uÆ0Hëñ;Ás@fÿþ*Ã,ˆC¾À€d‹Eü_^[ÉÃ;Ár €80uHëô;ÁsÙfƒ#ÆC ÆCÆ0€cjXëÓÌÌÌÌÌÌÌÌÌÌÌÌÌ‹T$‹L$÷Âu<‹:u. Àt&:au% ätÁè:Au Àt:auƒÁƒÂ äuÒ‹ÿ3ÀÃÀÑà@Ëÿ÷ÂtŠB:uéA Àtà÷Ât¨f‹ƒÂ:uÒ ÀtÊ:auÉ ätÁƒÁëŒÌÌÌÌÌÌÌÌÌÌÌÌU‹ìV3ÀPPPPPPPP‹U IŠ ÀtB«$ëó‹uƒÉÿAŠ ÀtF£$sò‹ÁƒÄ ^ÉÃU‹ìƒ=RSVuÿu ÿuèé‹ÿÿYYëvjèþ®ÿÿ‹uYf¶f…ÛtJ¶Ãö€!StŠFF„Àt·Ë¶ÀÁá È9M të·Ã9E tFëÆjè¯ÿÿY3Àë%jè¯ÿÿYFÿëjè¯ÿÿ‹E Y·Ë+Á÷ØÀ÷Ð#Æ^[]ÃV‹t$…ötVèü¸ÿÿ@Pè8ÿÿY…ÀYt VPèÜÿÿYY^Ã3À^ÃU‹ì‹M3ÀSV‰A‹MWj‰A‹M[‰A ŠMöÁt ‹EÇEÀ XöÁt‹EÇE“ÀƒH„Ët‹EÇE‘ÀƒHöÁt‹EÇEŽÀƒHöÁt‹EÇEÀƒH‹u ‹Ej‹‹P÷Ñ#˃âïÁá Ê_‰H‹‹E÷Ñ‹PƒáÑáƒâ÷ ʉH‹‹E÷Ñ‹PÑéƒáƒâû ʉH‹‹E÷Ñ‹PÁé#σâý ʉH‹‹E÷Ñ‹PÁé#˃âþ ʉHèú„Ãt‹MƒI ¨t‹MƒI ¨t‹MƒI ¨t‹M y ¨ t‹E X ‹¹ #Át4=t=t ;Áu(‹Eƒë ‹E‹ƒáþ Ïë ‹E‹ƒáý ˉë‹Eƒ ü‹¹#Át =t ;Áu"‹Eƒ ãë‹E‹ƒáçƒÉë ‹E‹ƒáëƒÉ‰‹E‹Máÿ‹Ááâþÿ ʉ‹E X ‹E‹H ƒáã ωH ‹EÝ‹EÝX‹E XP‹E‹HPƒáã Ï‹}‰HP‹EÝÝX@èøEPSjÿuÿ䀋Eö@tƒ&þö@tƒ&ûö@tƒ&÷ö@tƒ&ï„Xtƒ&ß‹ºÿóÿÿƒáƒét%ItIt Iu€N ë‹€åû€Íë‹€å÷€Í‰ë!‹ÁéƒáƒétItIu!ë‹#Ê€Íë‹#ʀ͉Ý@@Ý_^[]ÃU‹ìƒì ‹ESW‹øƒçj¨[t„]tSè`Yƒç÷éʨtöEtjèFYƒçû鰄ÄÒöE„Èjè$Y¸ ‹M#È„ˆùtXùt(;È…‹M ÝÜxÌÝ`HßàžwÙàÝ]ôÝEôën‹M ÝÜxÌßàžvÝPHëÝ`HÙàÝ]ôÝEôëF‹M ÝÜxÌßàžvÝ`HëÝPHÙàÝ]ôÝEôë‹M ÝÜxÌÝPHßàžwÙàÝ]ôÝEô݃çþéÖ¨„ÎöE„ÄV3ö¨t‹ó‹E ÝÝ]ôÝEôÜxÌßàž„ÝEôEüPQQÝ$èb‹EüƒÄ Ý]ôˆúÿÿùÎûÿÿ} Ùî‹óÝ]ôëTÝEôÜxÌßàžs‹Óë3ÒŠEúƒà f‰Eú¸üÿÿ;È}+Á„]ôt…öu‹óÑmô„]øt€M÷€ÑmøHuã…ÒtÝEôÙàÝ]ôÝEô‹E Ýë‹ó…ö^tjè‘YƒçýöEtöE t j èzYƒçï3À…ÿ_[”ÀÉËD$ƒøt~ƒøè±ÿÿÇ"Ãèù°ÿÿÇ!Ã3ÀÃU‹ìQ›Ý}þ¿EþÉÃU‹ìQÝ}þÛâ¿EþÉÃU‹ìQ›Ù}ü‹E ‹È#E÷Ñ#Mü ȉM Ùm ¿EüÉÃU‹ìQQŠMöÁt Û- Pˆˆ @A°¡> ˆ˜¨Èˆ @AØ¡þþA¢pˆˆp€¿ ÀA ¢ < >ø€€€ @A@¢""<"ˆˆøˆˆ @A¸¢UªUªUªUªUªUª @Aà¢8|þ|8€¿A£È‚£ð¢È¢ ¢x¢P¢(¢¢è¡À¡˜¡x¡X¡8¡¡ð Р°  p P (  àŸÀŸ˜ŸxŸXŸ8ŸŸðžè‚О¨žˆžhžHž žžà¸pP0ðœÈœ œxœPœ(œœØ›°›ˆ›`›8››øšК°šˆš`š8ššè™À™˜™p™H™ ™ø˜И¨˜€˜X˜0˜˜à—¸——h—@——ð–È– –x–P–(––Ø•°••p•P•0••è”À” ”x”X”0””è“À“˜“x“X“8““ø’Ø’¸’˜’x’X’8’’ø‘Ø‘°‘ˆ‘`‘ƒ(ƒ@‘‘øÐ°ˆ`8ðаpH(èŽÈŽ¨ŽˆŽhŽ@Ž ŽŽàÀ xP(ØŒ°ŒˆŒ`Œ8ŒŒè‹À‹˜‹p‹H‹ ‹øŠЊ¨Š€ŠXŠ0ŠŠà‰¸‰‰h‰H‰ ‰øˆЈ¨ˆ€ˆXˆ0ˆˆà‡¸‡‡h‡@‡‡ø†؆°†ˆ†`†8††è…À…˜…p…H… …ø„Є¨„€„`„@„„ðƒȃ ƒxƒPƒ0(£A8§AX§Ax§A˜§x„tŒ„„„„„((€¿@@A¸§€€€¼Â‚‚‚¼€€ €¿@@Aà§x„tŒ„„„„„0€¿@@A¨z„„„„„„(( €¿A0¨z„„„„„„D8 €¿AX¨z„„„„„„0 €¿A€¨z„„„„„„  €¿A¨¨€|¢¢’ŠŠ| €¿€?AШ8þ8 €¿Aø¨|‚‚‚‚‚|(( €¿A ©|‚‚‚‚‚|P( €¿AH©|‚‚‚‚‚|D8 €¿Ap©|‚‚‚‚‚|0 €¿A˜©|‚‚‚‚‚|  €¿AÀ©‚‚‚‚‚¼P( €¿Aè©|‚‚‚‚‚|P0H €¿Aªø àPP ÀA8ªø à` ÀA`ªø à` ÀAˆªø à0@ ÀA°ª|€€þ‚‚|(( €¿Aت|€€þ‚‚|D8 €¿A«|€€þ‚‚|0 €¿A(«|€€þ‚‚|  €¿AP«0H|‚€€€‚| €¿@@Ax«n’|’l€¿A «z†‚~|$ €¿AÀ«z†‚~|(( €¿Aè«z†‚~|P( €¿A¬z†‚~|D8 €¿A8¬z†‚~|0 €¿A`¬z†‚~|  €¿Aˆ¬€¼Â‚‚ü‚‚| €¿€?A°¬€€€ü‚‚‚ü€€ €¿Aج(D‚‚0 €¿A­|‚‚‚‚‚‚‚(( €¿A(­|‚‚‚‚‚‚‚D8 €¿AP­|‚‚‚‚‚‚‚0 €¿Ax­|‚‚‚‚‚‚‚  €¿A ­€|¢¢’’ŠŠ†| €¿€?AÈ­‚D((D‚€¿€¿Að­|‚‚‚‚‚‚|(( €¿A®|‚‚‚‚‚‚|P( €¿A8®|‚‚‚‚‚‚|D8 €¿A`®|‚‚‚‚‚‚|0 €¿Aˆ®|‚‚‚‚‚‚|  €¿A°®‚†Š’’¢Â‚P( €¿AØ®üBBBBòBBBü €¿A¯ø øPP ÀA(¯ø øˆp ÀAP¯ø ø` ÀAx¯ø ø0@ ÀA ¯þ@@@x@@þ(( €¿Aȯþ@@@x@@þD8 €¿Að¯þ@@@x@@þ0 €¿A°þ@@@x@@þ  €¿A@°0H|‚€€€€€€‚| €¿@@Ah°žün €¿A°‚‚‚þ‚‚D8( €¿A¸°‚‚‚þ‚‚D8(( €¿Aà°‚‚‚þ‚‚D8P( €¿A±‚‚‚þ‚‚D8D8 €¿A0±‚‚‚þ‚‚D80 €¿AX±‚‚‚þ‚‚D8  €¿A€±|‚‚€@  €¿A¨± f’ ` €¿Aб òL@@À@ €¿Aø± æB@@À@ €¿A ²H$$H€¿€¿AH²øpˆˆp€¿ ÀAh²à@@@À@€¿€ÀAˆ²`0À@@A¨²ÀÀ€À€ÀAȲ zŠŠŠ~ €¿Aè²€€ºÆ‚‚‚‚‚ €¿@A³À @ÀÁA8³` `€¿€ÀAX³ð€``€¿€ÀAx³þþ €¿€¿A˜³``@ÀÀÀAÀ³ü€¿ÁAà³ Pˆˆ €¿@AàÆ> ˆ˜¨Èˆ €¿@AÇþþ€¿A0ÇpˆˆpÀÀÀAPÇ < >ø€€€ €¿@ApÇ""<"<x€€x €¿@A˜Ç€€à€ð €¿@AÀÇ>ˆˆøˆˆ €¿@AèÇUªUªUªUªUªUªUª@@AÈ8|þ|8€¿A8È@§@È ÈøÇÐǨǀÇXÇ8ÇÇðÆÈƠƀÆ`Æ8ÆÆàÅÀŠŀÅ`Å8ÅÅàĸÄÄhÄ@Ä ÄÄØÃ`§¸ÃÃpÃPÃ(ÃÃØÂ¸ÂÂhÂHÂ(ÂÂèÁÈÁ ÁxÁPÁ(ÁÁØÀ°ÀˆÀ`À8ÀÀð¿È¿ ¿€¿X¿0¿¿à¾¸¾¾h¾@¾¾ð½Ƚ ½x½P½(½½ؼ°¼ˆ¼`¼8¼¼è»À»˜»p»H» »øºк¨º€º`º@º ººع¸¹¹p¹H¹ ¹ø¸и¨¸€¸X¸8¸¸ø·з¨·ˆ·h·@· ··à¶À¶˜¶x¶P¶(¶¶€§ §àµ¸µ˜µpµPµ(µµØ´¸´´p´P´0´´è³ȳ¨³€³`³@³ ³ø²в°²²p²P²0²²à±¸±±h±@±±ð°Ȱ °x°P°(°°د°¯ˆ¯`¯8¯¯è®À®˜®p®H® ®ø­Ø­°­ˆ­`­8­­è¬À¬˜¬p¬H¬ ¬ø«Ы¨«ˆ«`«8««èªÀª˜ªpªHª ªø©Щ¨©€©X©0©©à¨¸¨¨h¨@¨¨ð§ȧlXÈð?ÿG€¿€@@`  P @ @ˆÌ€€°ÈˆˆÈ°€€ @À@°Ì€@@`    @ @ØÌpP @ÍpP   @ Íp@   @HÍp @  @pÍpˆÈ¨˜tÀ@˜Í ø €¿À@¸ÍpˆˆˆˆpPÀ@ØÍpˆˆˆˆpP( À@øÍpˆˆˆˆpP  À@ Îpˆˆˆˆp  À@HÎpˆˆˆˆp @ À@pÎà P  @˜Îpˆˆˆˆx`P À@ÀÎ@@@@@@ @èÎ@@@@@@ @ €?@Ï€€€€€€€@ @0Ï@@@@@@@€ €?@XÏ`€ð`P @€Ï`€ð`P   @ Ï`€ð`@   @ÈÏ`€ð` @  @ðÏ` `€€`@ @Ðl’~ìA8Ðhpà P   @XÐhpàP @€Ðhpà P  @ ÐhpàP   @ÈÐhpà   @ðÐhpà @  @Ñ  ` @@Ñ€€ðˆˆð€€€¿à@`Ñ((DD‚ à@€Ñx„„„„„„„H €¿A¨Ñx„„„„„„„( €¿AÐÑx„„„„„„„  €¿AøÑx„„„„„„„  €¿A Ò€xĤ¤””Œx €¿€?AHÒˆP Pˆ€¿À@pÒx„„„„„„xH €¿AÒx„„„„„„xP( €¿A¸Òx„„„„„„x( €¿AàÒx„„„„„„x €¿AÓx„„„„„„x  €¿A0ÓŒŒ””¤¤ÄÄP( €¿AXÓxDBBòBDxA€Ó@@@@@@@@  @@ Ó@@@@@@@@ @ @@ÈÓ€€€€€€€€€@ €¿@@ðÓ@@@@@@@@@€ @@Ôø€€€ø€€øP €¿à@@Ôø€€ø€€€øP  €¿à@hÔø€€€ø€€ø  €¿à@Ôø€€€ø€€ø @ €¿à@¸Ô0x„€€€€„x €¿@AàÔ€ˆxH/€(€  AÕ‚‚|D((( à@0Õ‚‚|D((( à@XÕ‚‚|D((( à@€Õ‚‚|D((( à@¨Õ‚‚|D(( à@ÐÕ‚‚|D((  à@øÕ`€@ €¿@À@ Ö!€ È$Dâ A@Ö' HDÄBAhÖ!€ HDÄB AˆÖ P(P À@°Öàà à@À€@ÐÖ@@À@@À@@ðÖÀ@@@@×À@À@@0×(((((hèèè| @À@P×€€ð@ @x×€@ÀÀ@@˜×À @à@À@@¸×à@ `@À@@Ø×ø ø À@ø×``@À€@ØààÀ@@8Ø8Dª²ºD8€¿AXØà@À€@xØø€¿Àà@˜Ø(P P(À@¸Øà  à@À€@ØØ8Dš¢šD8€¿AøØ àÀ@@ÙpˆpȘpÀˆp @À@8Ù€€€€€€€€ €¿@@@`Ù ø øPPˆˆÀ@ˆÙ``€¿ @¨Ù°H@@à@H0À@ÈÙ@p¨  ¨p€?À@èÙ€€€€€€€€¿@@@Ú@@(Ú˜d@Àà@HÚ€@@@@ @@@€ @@@hÚ€€€€€€€€€€ €¿@@@Ú @@@@€@@@  @@@¸Úð€@ ð @àÚ€@@`  @ @ÛˆˆP PˆÀ@ Û((TT’’A@Û PPˆˆÀ@`Ûp @€Û`@@@@à@@€@ Û``` @ÀÛ€€€€À €@àÛh˜ˆˆ˜h@À@Ü€€°ÈˆˆÈ°@À@ ÜpˆˆˆˆpÀ@@܈ˆˆˆÈ°À@`Ü’’’’’ìA€Ü€€€€€€€€@ Ü À €€ @ÀÜ€€€€€€€€ €?@àÜ€€€€€€€@݈ˆˆˆÈ°€€À@(Ýph˜ˆˆ˜h@À@HÝ@@@@@à@0€@hÝ`€ð` @ˆÝh˜ˆˆ˜hÀ@¨Ý`€€` @ÈݰȈˆÈ°€€À@èÝhpà @Þ€€@ À@@(Þü@À@HÞˆPP @ÀÀ@hÞÀ@@@@@@@@À @@@ˆÞ @@@@€€@@°ÞÀ€€€€€€€€À €¿@@@ÐÞø€@ ø€¿à@øÞ((DD‚à@߈ˆPP Pˆˆ€¿à@8ß"""UIIˆ€ˆ€ AXß((DDD‚‚à@€ßx„„„„„„„€¿A ß ø @Àßpˆˆp€ˆp€¿à@à߈ˆˆˆðˆˆð€¿à@à|Œ”„„„„x €¿€?A à€€€€ðˆˆð€¿à@Hàx„„„„„„x€¿AhàŒŒ””¤¤ÄÄ€¿Aˆà’’’ªªÆÆ‚€¿A¨àð€€€€€€€€¿À@Èàˆˆà ˆ€¿à@èà` @က€€€€€€€¿@@(á„„„„ü„„„€¿AHátŒ„Œ€€„x€¿Ahက€€ð€€ø€¿À@ˆáø€€€ø€€ø€¿à@¨áðˆ„„„„ˆð€¿AÈáx„€€€€„x€¿Aèáðˆˆˆðˆˆð€¿à@â‚‚|D((à@(â>@›¤€¤€¢@’@M@ € @0AHâ@@@ `€¿À@xâ€@ @€€¿€¿À@˜âððÀ @¸â @€@ €¿€¿À@Øâ€@@@@@@øâ€€€¿@@ãpˆh˜ˆˆpÀ@8ãpˆˆˆpˆˆpÀ@Xã@@ øÀ@xãpˆˆÈ°€ˆpÀ@˜ãpˆð€€øÀ@¸ãøPP0À@Øãpˆ0ˆpÀ@øãø€@0ˆpÀ@ä@@@@@@À@€¿À@8äpˆˆˆˆˆˆpÀ@X䀀@@@@ @@x䀀¿@@˜äø€¿@Àà@¸ä€@@@@@Øä ø €¿À@øä @  À€@å€@@ @@€ €¿@€@8å @@€€€€@@  @€@`å€@@€¿ À@@ˆåd˜˜¤`PP €¿A¨å&)h”dAÈå p¨(p ¨p  €?À@èåPPø(|((À@æ  €¿ÀÀ€@0怀€€€€€€¿@@Pæ@@pæxæXæ8ææøåÐå°ååpåHå ååàäÀä ä€ä`ä@ä ääàãÀã ã€ã`ã@ã ããàâÀâ â€â`â0ââðáÐá°áápáPá0ááðàÐà°ààpàPà0ààèßÈߨ߈ßhß@ß ßßàÞ¸Þ˜ÞpÞPÞ0ÞÞðÝÐݰÝÝpÝPÝ0ÝÝðÜÈܨ܈ÜhÜHÜ(ÜÜèÛÈÛ¨ÛˆÛhÛHÛ(ÛÛèÚÈÚ ÚxÚPÚ0ÚÚðÙÐÙ°ÙÙpÙHÙ ÙÙàØÀؠ؀Ø`Ø@Ø ØØà×À× ×€×`×8××øÖØÖ¸Ö˜ÖpÖPÖ(ÖÖàÕ¸ÕÕhÕ@ÕÕðÔÈÔ ÔxÔPÔ(ÔÔØÓ°ÓˆÓhÓ@ÓÓðÒÈÒ ÒxÒXÒ0ÒÒàѸÑÑhÑHÑ(ÑÑØÐ°ÐˆÐhÐ@Ð ÐÐØÏ°ÏˆÏhÏ@ÏÏðÎÐΨ΀ÎXÎ0ÎÎàÍÀ̀͠ÍXÍ0ÍÍèÌÀ̘Ìlà æÀ 0PPHˆˆP €¿@@à@ ꀀ€°ÈˆˆˆÈ°€€ €¿@@à@Hê€@ PPˆˆˆ  €¿@@à@pêh˜ˆˆˆˆˆP €¿à@˜êh˜ˆˆˆˆˆP  €¿à@Àêh˜ˆˆˆˆˆ  €¿à@èêh˜ˆˆˆˆˆ @ €¿à@ë¸DdTLD:à@8ë ø €¿€¿à@XëpˆˆˆˆˆpP €¿à@xëpˆˆˆˆˆpP( €¿à@ ëpˆˆˆˆˆpP  €¿à@Èëpˆˆˆˆˆp  €¿à@ðëpˆˆˆˆˆp @ €¿à@숈ˆˆˆÈ°P( €¿à@@ìpˆˆˆˆxP0h €¿à@hì@@@@@@@  @@ì@@@@@@@ @ @@¸ì€€€€€€€€@ €¿@@àì@@@@@@@@€ @@ípˆ€øˆˆpP €¿à@0ípˆ€øˆˆpP  €¿à@Xípˆ€øˆˆp  €¿à@€ípˆ€øˆˆp @ €¿à@¨í` pˆ€€€ˆp €¿@@à@Ðíwˆ€ˆ€€ˆ€w €¿0Aøítˆˆxˆp0H0 €¿à@ îtˆˆxˆpP €¿à@HîtˆˆxˆpP( €¿à@pîtˆˆxˆpP  €¿à@˜îtˆˆxˆp  €¿à@Àîtˆˆxˆp  €¿à@èî°ˆˆˆ°ˆˆˆp €¿à@ø„„„ø€€ €¿A8ï(DD‚‚ €¿A`ïx„„„„„„„„H €¿Aˆïx„„„„„„„„( €¿A°ïx„„„„„„„„ €¿AØïx„„„„„„„„  €¿Að€^!P€H€D€D€B€!€@ €? A(ðˆP Pˆ€¿€¿à@XðA”€”€˜€”€œ€A> €¿0A€öð@À @°öü€¿ÀAÐö(P P(€¿€¿à@ðöà  à€¿€À @÷>Aœ€¢€ €¢€œ€A> €¿0A0÷ Á@@`÷pˆ0Hˆˆ`€ˆp @@À@€÷€€€€€€€€ €¿@@@¨÷ ø ø Pˆˆ €¿à@Ð÷„xHHx„€¿à@ø÷°H ð@@H0 €¿à@ø@pÈ   ¨p €¿€?à@@ø€€€€€€€€€ €¿@@@@hø€@ø˜d@Àà@°øÀ  À @@€@Ðø€€€€€€€€€€€€ €¿@@@@øø0@@@@@€@@@@0 @@€@ ùð€@@ ð€¿À@Hù€@ PPˆˆˆ €¿@@à@hù„„H00H„À@ù""UIIˆ€ˆ€ A°ù PPˆˆˆ€¿à@Øùh˜ˆˆˆˆˆ€¿à@øù`@@@@@à@@ @@ú``€`€¿À@@ú€€€€€À €¿€@`úh˜ˆˆˆ˜h €¿@@à@€ú€€€°ÈˆˆˆÈ° €¿@@à@¨úpˆˆˆˆˆp€¿à@ÐúˆˆˆˆˆÈ°€¿à@ðú’’’’’Ú¤€¿Aû€€€€€€€€€ €¿@@0ûˆ ÀÀ €€ €¿À@Xû€@@@@@@@@@@ @@@@€û€€€€€€€€ €¿@@¨ûˆˆˆˆˆÈ°€€ €¿à@Ðûpˆh˜ˆˆˆ˜h €¿@@à@øû@@@@@@à@0 @@ üpˆ€øˆˆp€¿à@Hüh˜ˆˆˆ˜h €¿à@hüpˆ€€€ˆp€¿à@ü°ÈˆˆˆÈ°€€ €¿à@°ütˆˆxˆp€¿à@ØüÀ€@ÀÀ@@øüþ@à@ýˆP  ÀÀ@8ýÀ@@@@@@@@@@À @@@@Xý @@€€ €@€ýÀ€€€€€€€€€€À €¿@@@@¨ýþ€@ þ €¿AÐý(DD‚‚ €¿Aøý‚DD((DD‚ €¿A þ"""UUIˆ€ˆ€ˆ€ €¿0AHþ((DDD‚‚ €¿Axþx„„„„„„„„ €¿A þþ à@Èþx„„`€„x €¿Aðþ„„„ˆø„„„ø €¿Aÿ=B…‰B< €¿ A@ÿ€€€€ø„„„ø €¿Ahÿ@›¦€¢@¢@’@M@`€ €¿€?@A𠈈p €¿à@ À0 0À€¿€¿à@Høø€¿Àà@h 0À0 €¿à@ˆ€@@@@@@¨€€€¿@@Èpˆxˆˆˆp €¿à@èpˆˆˆˆpˆˆp €¿à@@@ ø €¿à@8pˆˆˆÈ°€ˆp €¿à@`pˆˆð€€ø €¿à@ˆüˆH(( à@°pˆˆ0ˆp €¿à@Øø€€@ ˆp €¿à@ à  €¿à@(pˆˆˆˆˆˆˆp €¿à@P€€@@@  €@x€€¿@@ ø€¿@ÀAÀ€@@€¿@€@à ø €¿€¿à@ @ €¿ÀÀ @ €@@ @@€ @@€@@ @@€€€€€€@@  €¿@@€@h€@À€¿ÀÀ@@rŒ„ŠP0HH0 €¿A°#€€h””b €¿0AØ p¨¨(p ¨p  €¿€?à@PPPü(ü((à@0   €¿ÀÀ @P€€€€€€€€ €¿@@p€@˜ €X8ðÀ˜xP(èȨˆ`8èÀ˜pH øÐ°pP0ذˆ`8èÀ˜pH øÿÈÿ ÿxÿPÿ(ÿÿØþ°þˆþ`þ0þþàý¸ýýhý@ý ýýàüÀü˜üxüPü0üüàû¸ûûhû@ûûøúØú¸úúhúHú(úúàùÀù˜ùxùPù0ùùàø¸ø˜øxøPø(øøà÷¸÷÷h÷H÷÷øöØö¸ö˜öhöHö(ööèõÈõ¨õ€õXõ8õõøôØô¸ôˆôXô(ôôØó°óˆó`ó8óóàò¸òòhò@òòðñÈñ ñxñPñ(ññØð°ðˆð`ð@ððèïÀï˜ïpïHï ïøîÐî¨î€îXî0îîàí¸ííhí@ííðìÈì ìxìPì(ììØë°ëˆë`ë@ë ëøêÐê¨ê€êXê0ê¬à ¸pp<$fffÃÃÃff€¿€@ AH ÀÀÀÀÞÿãÁ€Á€Á€Á€ãÿÞÀÀÀÀ €¿€@0Ax pp<$fffÃÃà €¿€@ A¸ sûÇÃÃÃÃÃÃÃff €¿ Aè sûÇÃÃÃÃÃÃÃf<€¿ A sûÇÃÃÃÃÃÃà €¿ A8 sûÇÃÃÃÃÃÃà 0€¿ A` ΀1€xÀlÀfÀcÀ1€?À` 0Aˆ ÿÿ€¿€¿ A¸ >cÁ€Á€Á€Á€c>66 €¿0AØ >cÁ€Á€Á€Á€c>&- €¿0A >cÁ€Á€Á€Á€c>3 €¿0AH >cÁ€Á€Á€Á€c>  €¿0A€ >cÁ€Á€Á€Á€c> 0 €¿0A¸ ÃÃÃÃÃÃÃãßÎLZ2€¿ Að >cÁ€Á€Á€Á€c>L86` €¿0A ``````````ØØ €@P 0000000000Ìx0€?€@x ``````````À`0€@  ``````````0`À€@È <ãÀÀÿÃÃ~<66 €¿ Að <ãÀÀÿÃÃ~<f<€¿ A<ãÀÀÿÃÃ~< €¿ A@<ãÀÀÿÃÃ~<0`€¿ Ahxl 8>cÀÀÀÀc>€¿€@ AuàïøÇÆæøÆïð}à €¿pA¸vîÆÆæ~Æî|8ll8€¿AèvîÆÆæ~Æî|ll €¿AvîÆÆæ~Æî|LZ2€¿A8vîÆÆæ~Æî|f<€¿A`vîÆÆæ~Æî|0 €¿AˆvîÆÆæ~Æî|0`€¿A°ÜÞÆÆÆÆÜÜÆÆÆÆ|8€¿AØÀÀÀÿÿ€ÁÀÀÀÀÀÁÀÿ€ÿÀÀÀ €¿@A€0À0À````À0À0€ €¿`A8À`ÀÀ`À`À`À`À`À`À`À`À`À`À`€€ €¿PAxÀ`ÀÀ`À`À`À`À`À`À`À`À`À`À`€ €¿PA¸À`ÀÀ`À`À`À`À`À`À`À`À`À`À`  €¿PAøÀ`ÀÀ`À`À`À`À`À`À`À`À`À`À`  €¿PA8ÇÀÿðx88ln g cŒaÌpÜ0x88üÌpAxÀÀa€3 3a€ÀÀ A°€?àpp`0à8ÀÀÀÀà8`0pp?à€ € € €¿pAà€?àpp`0à8ÀÀÀÀà8`0pp?à€ € @@ €¿pA €?àpp`0à8ÀÀÀÀà8`0pp?à€ À€ €¿pA`€?àpp`0à8ÀÀÀÀà8`0pp?à€€À €¿pA €?àpp`0à8ÀÀÀÀà8`0pp?à€ €¿pAàÀ`ÀàÁàÁàÃ`Æ`Æ`Ì`Ì`Ø`Ø`ð`à`à`€ € €¿PA €À`à```0`0ü0ü0`0`0```àÀ€ PA`00000000000000ÌÌÀ@˜00000000000000Ìx0À@ÈÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ`0ÀÀ@ø000000000000000`ÀÀ@(ÿ€ÿ€ÀÀÀÀÿÿÀÀÀÀÿ€ÿ€33 €¿0AXÿ€ÿ€ÀÀÀÀÿÿÀÀÀÀÿ€ÿ€3 €¿0A˜ÿ€ÿ€ÀÀÀÀÿÿÀÀÀÀÿ€ÿ€  €¿0AØÿ€ÿ€ÀÀÀÀÿÿÀÀÀÀÿ€ÿ€ 0 €¿0A€?àpp`0àÀÀÀÀà`0pp?à€ €¿€@`AXÁÿÁÿa€a€€?€1þ1þ€€ € €ÿÿ€¿A˜À0À0````à?À0À0À€€€€ @AÐÀ0À0````à?À0À0À€€€€ @AÀ0À0````à?À0À0À€€€ € @APÀ0À0````à?À0À0À€€€ @AÀ0À0````à?À0À0À€€€ @AÐÀ0À0````à?À0À0À€€  @A|þÆÆàp8€¿€@ AP üØxs8ù™ˆ0À0À˜`ø0p0 pAx0ø0ø` 0 f˜bøcpa€a€àÀà``` €¿pA°0000ø ° ðfpb0ca€a€àÀà``` €¿pAèØl66lØ€¿€¿A øp؈ˆØp€¿ÀÀà@@`````àà`€¿ ÀÀ@`ðØp`€@ @€ÀÀ€¿€À€@ 2ròòòòr?€¿€@ AÀÀÀÀÀÛÿçÃÃÃÃÃÃÀ¿€@ AðÀ`00Á€@pø˜00˜øp ÀÀ@8øø`0˜øp ÀÀ@Xÿÿÿÿ €¿ Axp؈Øp€¿Áà@ ø@Á @À€0`@HPˆˆ‰ˆˆHˆHO@0`€ €¿`Aàøø€¿€Àà@€€€ÿ€ÿ€ €¿@À0A86lØØl6€¿€¿A`øhØH8Èp€¿ÀÀà@€€0`@GˆˆˆˆG@0`€ €¿pA ØØ0ÁÀ@Ø<~ÃÃ>sãÃÇn|ðÃÃ~<€¿€@ AøÀÀÀÀÀÀÀÀÀÀÀÀÀ€¿@@€@(ÿÿkÈÈÈÈk>€¿@ AØÀÀÀÀÀÀÀÀ@@ÀÀÀ€@À@ @(Ì~3€¿€À AHÀ`000000 00000`À€@À@hÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ€¿€@€@˜ 000000`À`00000 €@À@ÈþþÀ`0 þþ €¿Aøpp<$fffÃÃÀ¿€@ A Ãçf<üÀÆ~< €¿AÀÀÀÀÀÀÀàØØ €¿À@@€€€€=€€c€Á€Á€Á€Á€c€€=€ €¿€@0AhÀÀÀÀÞÿãÁ€Á€Á€Á€ãÿÞ €¿€@0A >cÁ€Á€Á€Á€c> €¿0AØÃÃÃÃÃÃÃãßÎ €¿ AÆ0Æ0Æ0Æ0Æ0Æ0Æ0ç0ÞðÌ` €¿`A0ÀÀÀÀÀÀÀÀÀÀÀÀÀÀ€¿€@`ÇÆÎÌØøðØÌÆÀÀÀÀ€¿Aˆàð00000000000000€?€@€@°ÀÀÀÀÀÀÀÀÀÀÀÀ€¿€@àÃÃÃÃÃÃÃãßÎÀÀÀÀ€¿ A c€=€€c€Á€Á€Á€Á€a€€=€ €¿€@0A0 00000000üü00<À@h <ãÀÀÿÃÃ~< €¿ A =€€c€Á€Á€Á€Á€c€€=€€€€€ €¿0A¸ >cÀÀÀÀc> €¿ Að ÞÿãÁ€Á€Á€Á€ãÿÞÀÀÀÀ €¿0A!vîÆÆæ~Æî| €¿AP!ÀÀ€€@€¿Á€@x!ÿÀÿÀ €@ A˜!‚Æl8€¿ÁA¸!ðð00000000000000ðð€@ @Ø!00 ``@@ÀÀ @"ððÀÀÀÀÀÀÀÀÀÀÀÀÀÀðð€¿€@ @0"ÿÀÿÀÀ`0 €ÀÿÀÿÀ €¿@A`"€0À0À````À0À0 €¿`A˜"À`àà`ÀqÀ1€1€qÀ`ÀààÀ` €¿PAÐ"84,6l6lffffbFcÆÃÃÁƒÁƒÁƒ€¿A#€€€0À0À0À``````À0À0 €¿`A@#À`ÀÀ`À`À`À`À`À`À`À`À`À`À` €¿PAx# ÿÀÿÀ €¿@A°#?ÀààÀ``àÀ|àÀ`ààÀ €¿PAè#ÀÀÀÀÀÀÀÀÁ€Á€ÿÿ€ÁÀÀÀÀÀÁÀÿ€ÿ €¿@A $0°?àpða°á¸ÀÀÀÀà8`0pp?à€ €¿€?pAX$ÀÀÀÀÀÀÿÿ€ÁÀÀÀÀÀÁÀÿ€ÿ €¿@A$€?àpp`0à8ÀÀÀÀà8`0pp?à€ €¿pAÈ$À`ÀàÁàÁàÃ`Æ`Æ`Ì`Ì`Ø`ð`ð`à`À` €¿PA%à à njČÌÌÌÌØlØlð<ð<ààÀ À €¿€A8%ÿÿÀÀÀÀÀÀÀÀÀÀÀÀ€¿ Ap%ÀpÀàÁÀÀÇÎüøÜÎÇÀÁÀÀà €¿PA˜%<~çÃÀ¿ AÐ%ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ@ø%À`À`À`À`À`À`ÿàÿàÀ`À`À`À`À`À` €¿PA &°?ðpp`0à0ÁðÁðÀÀà0`0pp?à€ €¿`AX&ÀÀÀÀÀÀÿÿÀÀÀÀÿ€ÿ€ €¿0A&ÿ€ÿ€ÀÀÀÀÿÿÀÀÀÀÿ€ÿ€ €¿0AÈ&ÿÿ€ÁÀÀÀÀ`À`À`À`À`À`ÀÀÁÀÿ€ÿ €¿PA'€?àpp`0àÀÀÀÀà`0pp?à€ €¿`A8'ÿ€ÿÀÀàÀ`À`ÀàÿÀÿ€Á€ÀÀÀÀÁÀÿ€ÿ €¿PAp'À0À0````à?À0À0À€€ @A¨'àð8pgpÏøÌÌÌfÌfÌcÆ3gsc³0üð€¿@@Aà'000008ÆÆþ|€¿ A (Àð<<ðÀ €¿ AH(þþþþÀÀ0Ap(ë€É€ €>xèÈË> €¿@ Ah,$$$ÿ€ÿ€ÀÀ A ,ØØØÁ @Ø,ÀÀ€€ÀÀÀÀÀÀÀÀÀÀ@ø, @ -(--à,À,ˆ,P,,à+À++`+@++ø*Ø*¸**h*@**ð)¸))h)@))ð(È( (x(X(0((È''X' 'è&°&x&@&&à%¸%€%X% %è$°$x$@$$Ð#˜#`#(#ð"¸"€"H""ð!À! !€!`!8!!Ø   x P  ðȘpHðÀˆP(ذˆX0à°€P0èÀˆh@àÀˆhH Ȩˆ`@ بˆhH(И`8ø¸x8ø¸€@À€@à°€HȈHȘ` à ` èÀ˜pH øÐ xP(Ø ° ˆ ` 8  Ø   h 0 ø À   p H  ø Ð   ` ìà @-ü©ñÒMb@@%†QBÈB%†QBMUB%†QB|aAõy>B|a˜@%†QBT’dB|a˜@%†QB|aAØ0è0gUBÈBgUBZU…BqÛŽBÈBqÛŽBZU…B 1010 [B“îBÆm«AMU³ª¦B“îBHBMUÂÆm«AT’dB¾0°BT’dBgU…A:’äA³ª¦B:’äAP1`1p1€1¬m+B“îB¬m+B|a˜ÁjžwB“îBjžwB|a˜Á¹m«B¹m«B‰a˜Bèy¾BjžwBÈB¬m+BÈB:’äAèy¾B|a˜A¹m«B|a˜A‰a˜BÛy¾AZU…B:’äA„žwB|aBT’dBMU…BÛy>B‰a˜B¬m+B¡ç¡B|aB¹m«B:’äA¹m«B:’dA‰a˜B|a˜@jžwB¬m+B:’äA|a˜@|a˜A:’dA°1À1Ð1èy¾BÈB|aAMUBÈB¬m+BÐó´B¬m+B¡ç¡B|aBqÛŽB:’äAZU…B|a˜AZU…B|aA‰a˜B|aA¹m«B:’dAèy¾BÛy¾AÈBMUBÈB¬m+Bèy¾B:’dBÐó´BqÛŽBÐó´B¹m«Bèy¾Bèy¾BÈB‰a˜BMUBZU…B:’äA„žwB|a˜A„žwB|aAqÛŽB¡ç¡BÐó´B|a˜@èy¾B:’dAèy¾BÛy¾A¹m«BMUB‰a˜BMUBˆ2˜2 3ÈBT’dBÈB„žwBèy¾BZU…BÐó´BZU…B¹m«B„žwB¡ç¡B%†QBqÛŽB:’äA„žwB:’dA †QB|a˜@¬m+BÛy¾A:’dA|a˜@|aA|aA|a˜@|a˜A|a˜@:’äA|aA|aB:’dA¬m+BÛy>B„žwB †QBZU…BT’dB‰a˜BT’dB¹m«B †QBèy¾B¬m+BÈBMUBèy¾B:’äA¹m«B:’äA‰a˜BMUB„žwB¬m+BÛy>BZU…B:’dA‰a˜B|a˜@¹m«Bèy¾BÈB|a˜@ÈB|aA"ˆ3%†QBÈB%†QBZU…B 4_ŠB“îB_nBJ ÛBHBèy¾B¡ç!B‰a˜BqÛB%†QBqÛBMUB¡ç!B|aAHB|aÁ_nBÛy¾Á_ŠBMU ¸4qÛB“îBÐó4BJ ÛB0 [Bèy¾BG’€B‰a˜B_ŠB%†QB_ŠBMUBG’€B|aA0 [B|aÁÐó4BÛy¾ÁqÛBMU 5%†QBqÛŽB%†QB:’dAo’äAT’dB‰a˜B:’äA‰a˜BT’dBo’äA:’äAh5x5ˆ5 †QB¹m«B †QB|aA¬m+Bèy¾B¬m+B°5À5T’dB|a˜@%†QBõy>B|a˜@%†QB|aAT’dB|a˜@T’dB|a˜À%†QB:’dÁõy>B|a˜Áà5|aA¬m+Bèy¾B¬m+B(6%†QB|aAõy>B|a˜@%†QBT’dB|a˜@%†QB|aA@6|a˜A:’dÁ¹m«BÈBp6Ûy>BÈBMUBèy¾BÛy¾A¡ç¡B|a˜AT’dB|a˜A¬m+BÛy¾A|a˜AMUB|a˜@Ûy>B:’dBqÛŽB|a˜@¡ç¡B|a˜A¹m«B¬m+B¹m«BT’dB¡ç¡B¡ç¡BqÛŽBèy¾B:’dBÈBÛy>BÈBˆ6¡ç!B¡ç¡BHB¹m«BG’€BÈBG’€B7Ûy¾A‰a˜BÛy¾A¡ç¡B:’äAÐó´BMUBèy¾B¬m+BÈBjžwBÈBqÛŽBèy¾B‰a˜BÐó´B¡ç¡B¡ç¡B¡ç¡BqÛŽB‰a˜B„žwBMU…BÛy>B|a˜A¹m«B@7:’äAÈB¡ç¡BÈB †QB„žwBMU…B„žwB‰a˜BT’dB¡ç¡B%†QB¹m«B|aB¹m«B:’äA¡ç¡B:’dAqÛŽB|a˜@:’dB¬m+B:’äA|a˜@Ûy¾A|aA|a˜A|a˜A¸7G’€BÈBgU…AMUB¾0°BMUBG’€BÈBG’€B88P8‰a˜BÈB:’äAÈBÛy¾AT’dB:’äA„žwB¬m+BZU…B:’dBZU…BqÛŽB„žwB¡ç¡B%†QB¹m«B|aB¹m«B:’äA¡ç¡B:’dAqÛŽB|a˜@:’dB¬m+B:’äA|a˜@Ûy¾A|aA|a˜A|a˜Ap8$B¹m«B„ž“Bèy¾B_nBÈBHBÈBqÛBèy¾B%†ÑA¡ç¡BÆm«AT’dBÆm«AMUB%†ÑA:’dAqÛB|a˜@HB0 [B_ŠB|a˜@$B:’dA³ª¦B:’äA³ª¦BMUB$BÛy>B_ŠBT’dB0 [B„žwBHB„žwBqÛBT’dB%†ÑAÛy>BÆm«AMUB9¹m«BÈB|aB|a˜AÈB¹m«BÈBÀ9Ð9¬m+BÈB:’äAèy¾BÛy¾A¹m«BÛy¾A‰a˜B:’äAZU…B|aB„žwB:’dBT’dBqÛŽB%†QB¡ç¡B¬m+B¹m«BMUB¹m«B|a˜A¡ç¡B|aA‰a˜B|a˜@jžwB¬m+B:’äA|a˜@Ûy¾A|aA|a˜A|a˜A|a˜AMUBÛy¾A¬m+BMUB%†QBÛy>BT’dBMU…B„žwB‰a˜BZU…B¡ç¡B‰a˜B¡ç¡B¹m«B‰a˜Bèy¾BjžwBÈB¬m+BÈBð9³ª¦BZU…B$B%†QB_ŠB¬m+B0 [B|aBHB|aBqÛB¬m+B%†ÑA%†QBÆm«AZU…BÆm«AqÛŽB%†ÑA¹m«BqÛBèy¾BHBÈB0 [BÈB_ŠBèy¾B$B¹m«B³ª¦BZU…B³ª¦B¬m+B$B|a˜A_ŠB|a˜@0 [BÐó4B„ž÷A|a˜@%†ÑA:’dAà:%†QBZU…Bõy>B„žwB%†QBT’dBT’dB„žwB%†QBZU…B%†QB|aAõy>B|a˜@%†QBT’dB|a˜@%†QB|aA ;È;%†QBZU…Bõy>B„žwB%†QBT’dBT’dB„žwB%†QBZU…BT’dB|a˜@%†QBõy>B|a˜@%†QB|aAT’dB|a˜@T’dB|a˜À%†QB:’dÁõy>B|a˜Á<(<Ðó´B¹m«B:’dA¬m+BÐó´Bx<|aAT’dBèy¾BT’dB|aA:’äAèy¾B:’äA˜<¨<:’dA¹m«BÐó´B¬m+B:’dAÈ<Ûy¾A‰a˜BÛy¾A¡ç¡B:’äAÐó´BMUBèy¾B¬m+BÈBjžwBÈBdÛŽBèy¾B‰a˜BÐó´B¡ç¡B¡ç¡B¡ç¡BqÛŽB‰a˜B„žwBdÛŽBT’dB †QBÛy>B †QBMUB †QB|aAÛy>B|a˜@ †QB:’dB|a˜@ †QB|aAè<X=G’€B%†QB0 [BT’dBÐó4BT’dB¡ç!BÛy>B¡ç!B¬m+BÐó4BMUB0 [BMUBG’€B|aBG’€BT’dBG’€B|aB_ŠBMUB$BMUB³ª¦B¬m+B³ª¦BÛy>B$B„žwB_ŠBqÛŽB0 [B‰a˜BHB‰a˜BqÛBqÛŽB%†ÑA„žwBÆm«AÛy>BÆm«A¬m+B%†ÑA:’äAqÛB|a˜AHB:’dA0 [B:’dA_ŠB|a˜A=Ð= †QBÈB:’dA †QBÈBÐó´B:’äAMUB‰a˜BMUBx>ˆ>˜>|a˜AÈB|a˜A|a˜AÈBjžwBÈB‰a˜Bèy¾B¡ç¡BÐó´B¹m«B¡ç¡B¹m«BqÛŽB¡ç¡B„žwB‰a˜BT’dBjžwB%†QB|a˜A%†QBjžwB%†QB‰a˜BÛy>B¡ç¡B¬m+B¹m«BMUB¹m«B|a˜A¡ç¡B|aA‰a˜B|a˜@jžwB|a˜AÀ> Ð> ?¾0°B‰a˜B³ª¦B¹m«B„ž“Bèy¾BG’€BÈBÐó4BÈBqÛBèy¾B%†ÑA¹m«BÆm«A‰a˜BgU…A„žwBgU…A|aBÆm«AÛy¾A%†ÑA:’dAqÛB|a˜@Ðó4BG’€B„ž“B|a˜@³ª¦B:’dA¾0°BÛy¾A€?|a˜AÈB|a˜A|a˜AÈB †QBÈBMU…Bèy¾B‰a˜B¹m«B¡ç¡B‰a˜B¹m«B„žwB¹m«B|aB¡ç¡BÛy¾A‰a˜B:’dAMU…B|a˜@ †QB|a˜A@ (@Æm«AÈBÆm«AÆm«AÈB³ª¦BÈBÆm«A%†QB_nB%†QBÆm«A³ª¦B˜@¨@¸@È@Æm«AÈBÆm«AÆm«AÈB³ª¦BÈBÆm«A%†QB_nB%†QBø@AA¾0°B‰a˜B³ª¦B¹m«B„ž“Bèy¾BG’€BÈBÐó4BÈBqÛBèy¾B%†ÑA¹m«BÆm«A‰a˜BgU…A„žwBgU…A|aBÆm«AÛy¾A%†ÑA:’dAqÛB|a˜@Ðó4BG’€B„ž“B|a˜@³ª¦B:’dA¾0°BÛy¾A¾0°B|aBG’€B|aB¾0°B|aB@AØA|a˜AÈB|a˜A¹m«BÈB¹m«B|a˜A%†QB¹m«B%†QBøABB%†QBÈB%†QB@B‰a˜BÈB‰a˜BÛy¾AqÛŽB|aAZU…B|a˜@T’dBõy>B–aB|a˜@gUB|aAo’äAÛy¾Ao’äAMUB XB|a˜AÈB|a˜A¹m«BÈB|a˜AMUB¬m+BT’dB¹m«B°BÀBÐBÛy¾AÈBÛy¾AÛy¾A¡ç¡BøBC:’dAÈB:’dA:’dAÈB †QBÐó´BÈB †QBÐó´BÈBÐó´B(C8CHCXC|a˜AÈB|a˜A|a˜AÈB¹m«B¹m«BÈB¹m«BˆC˜C¨C¬m+BÈBMUBèy¾BÛy¾A¹m«B|a˜A‰a˜B:’dA„žwB:’dA|aB|a˜AÛy¾AÛy¾A:’dAMUB|a˜@¬m+BjžwBqÛŽB|a˜@¡ç¡B:’dA¹m«BÛy¾AÐó´B|aBÐó´B„žwB¹m«B‰a˜B¡ç¡B¹m«BqÛŽBèy¾BjžwBÈB¬m+BÈBÐC|a˜AÈB|a˜A|a˜AÈBjžwBÈB‰a˜Bèy¾B¡ç¡BÐó´B¹m«B¡ç¡B¹m«BZU…B¡ç¡BT’dB‰a˜B%†QBjžwBÛy>B|a˜AÛy>B€D D¬m+BÈBMUBèy¾BÛy¾A¹m«B|a˜A‰a˜B:’dA„žwB:’dA|aB|a˜AÛy¾AÛy¾A:’dAMUB|a˜@¬m+BjžwBqÛŽB|a˜@¡ç¡B:’dA¹m«BÛy¾AÐó´B|aBÐó´B„žwB¹m«B‰a˜B¡ç¡B¹m«BqÛŽBèy¾BjžwBÈB¬m+BÈB:’dB|a˜A¹m«B|aÁðD˜E|a˜AÈB|a˜A|a˜AÈBjžwBÈB‰a˜Bèy¾B¡ç¡BÐó´B¹m«B¡ç¡B¹m«BqÛŽB¡ç¡B„žwB‰a˜BT’dBjžwB%†QB|a˜A%†QB †QB%†QB¹m«B¸E ÈEF¹m«B¹m«B‰a˜Bèy¾BjžwBÈB¬m+BÈB:’äAèy¾B|a˜A¹m«B|a˜A‰a˜BÛy¾AZU…B:’äA„žwB|aBT’dBMU…BÛy>B‰a˜B¬m+B¡ç¡B|aB¹m«B:’äA¹m«B:’dA‰a˜B|a˜@jžwB¬m+B:’äA|a˜@|a˜A:’dA@F †QBÈB †QB|a˜AÈB¹m«BÈBèFøF|a˜AÈB|a˜A:’äAÛy¾A:’dAMUB|a˜@Ûy>B:’dBqÛŽB|a˜@¡ç¡B:’dA¹m«B:’äA¹m«BÈB G:’dAÈB †QBÐó´BÈB †QBpG€G|a˜@ÈB:’äA †QBÈB:’äA †QBÈB‰a˜BÈBÈB‰a˜B G°GÀGÐG|a˜AÈB¹m«B¹m«BÈB|a˜AHH:’dAÈB †QB%†QB †QBÐó´BÈB †QB%†QB0HHH¹m«BÈB|a˜A|a˜AÈB¹m«BÈB|a˜A¹m«BhHxHˆHqÛB“îBqÛBMU¡ç!B“îB¡ç!BMUÂqÛB“îB_ŠB“îBqÛBMUÂ_ŠBMU°HÀHÐHàH|a˜AÈB¹m«B:’dÁIG’€B“îBG’€BMUÂ_ŠB“îB_ŠBMUÂqÛB“îB_ŠB“îBqÛBMUÂ_ŠBMUÂ(I8IHIXI †QBJ ÛB:’dA¬m+B †QBJ ÛBÐó´B¬m+BˆI˜IMUÂ%†ÑBMUÂ%†ÑB:’äÁ:’äÁMU¸IÆm+BÈBZU…BqÛŽBÆm+BÈB–aBèy¾BZU…BqÛŽBèIøI¡ç¡BZU…B¡ç¡B¡ç¡B%†QBdÛŽB„žwBjžwBZU…BÛy>BZU…B|aB„žwB:’äA%†QBÛy¾A|aBÛy¾A:’äA:’äA:’dA|aB|a˜@Ûy>BjžwBdÛŽB|a˜@¡ç¡B:’dA J0JÛy¾AÈBÛy¾AÛy¾A%†QBMUB„žwB¬m+BZU…B:’dBZU…BMU…B„žwB‰a˜B%†QB¡ç¡B|aB¡ç¡B:’äA‰a˜B:’dAMU…B|a˜@:’dB¬m+BMUB|a˜@Ûy¾A:’dA°JÀJ¡ç¡B%†QBdÛŽB„žwBjžwBZU…BÛy>BZU…B|aB„žwB:’äA%†QBÛy¾A|aBÛy¾A:’äA:’äA:’dA|aB|a˜@Ûy>BjžwBdÛŽB|a˜@¡ç¡B:’dA@K¡ç¡BÈB¡ç¡B¡ç¡B%†QBdÛŽB„žwBjžwBZU…BÛy>BZU…B|aB„žwB:’äA%†QBÛy¾A|aBÛy¾A:’äA:’äA:’dA|aB|a˜@Ûy>BjžwBdÛŽB|a˜@¡ç¡B:’dA¸KÈKÛy¾A|aB¡ç¡B|aB¡ç¡BÛy>B‰a˜BT’dBdÛŽB„žwBjžwBZU…BÛy>BZU…B|aB„žwB:’äA%†QBÛy¾A|aBÛy¾A:’äA:’äA:’dA|aB|a˜@Ûy>BjžwBdÛŽB|a˜@¡ç¡B:’dAHLqÛŽBÈB„žwBÈB%†QBèy¾Bõy>B¡ç¡Bõy>BgUBZU…BZU…BZU…BØLM¡ç¡BZU…B¡ç¡B|aÁ‰a˜BÛy¾ÁdÛŽB:’äÁjžwBMUÂÛy>BMUÂ|aB:’äÁ¡ç¡B%†QBdÛŽB„žwBjžwBZU…BÛy>BZU…B|aB„žwB:’äA%†QBÛy¾A|aBÛy¾A:’äA:’äA:’dA|aB|a˜@Ûy>BjžwBdÛŽB|a˜@¡ç¡B:’dA MXM%†ÑAÈB%†ÑA%†ÑAÛy>B¡ç!B„žwBHBZU…BG’€BZU…Bwž“B„žwBœ$BÛy>Bœ$BØMèMõy>BÈB%†QBèy¾BT’dBÈB%†QB%†ÑBõy>BÈB%†QBZU…B%†QB0NXNT’dBÈB„žwBèy¾BZU…BÈB„žwB%†ÑBT’dBÈB„žwBZU…B„žwB:’dÁT’dB:’äÁõy>BMU–aBMUÂxN N%†ÑAÈB%†ÑAwž“BZU…B%†ÑA|a˜AÐó4B|aBœ$BØNèNøN%†QBÈB%†QB OZU…BÛy>B:’dA„žwBÛy¾AZU…B|aBZU…BÛy>B„žwB%†QBÛy>B%†QB%†QBÛy>BZU…B„žwB‰a˜BZU…BÐó´BZU…BÈB„žwB%†ÑBÛy>B%†ÑB8OHO€O%†ÑAZU…B%†ÑA%†ÑAÛy>B¡ç!B„žwBHBZU…BG’€BZU…Bwž“B„žwBœ$BÛy>Bœ$BÐOàOÐó4BZU…BqÛB„žwB%†ÑA%†QBÆm«A|aBÆm«A:’äA%†ÑA:’dAqÛB|a˜@Ðó4B_nB_ŠB|a˜@$B:’dA³ª¦B:’äA³ª¦B|aB$B%†QB_ŠB„žwB_nBZU…BÐó4BZU…B(PÛy¾AZU…BÛy¾AMUÂÛy¾A%†QBMUB„žwB¬m+BZU…B:’dBZU…BMU…B„žwB‰a˜B%†QB¡ç¡B|aB¡ç¡B:’äA‰a˜B:’dAMU…B|a˜@:’dB¬m+BMUB|a˜@Ûy¾A:’dA¸PÈP¡ç¡BZU…B¡ç¡BMU¡ç¡B%†QBdÛŽB„žwBjžwBZU…BÛy>BZU…B|aB„žwB:’äA%†QBÛy¾A|aBÛy¾A:’äA:’äA:’dA|aB|a˜@Ûy>BjžwBdÛŽB|a˜@¡ç¡B:’dAHQXQgUBZU…BgUBgUB|aB–aB%†QBõy>B„žwBT’dBZU…BqÛŽBZU…BØQèQœ$B%†QBwž“B„žwB_nBZU…BÐó4BZU…B„ž÷A„žwB%†ÑA%†QB„ž÷A¬m+B¡ç!B|aBG’€BMUBwž“B:’äAœ$B|a˜Aœ$B:’dAwž“B|a˜@_nBÐó4B„ž÷A|a˜@%†ÑA:’dA Rõy>BÈBõy>B|a˜A%†QB|a˜@„žwBqÛŽBgUBZU…BZU…BZU…B°RØR%†ÑAZU…B%†ÑA|a˜A„ž÷A|a˜@¡ç!B0 [BG’€B|a˜@œ$B|a˜Aœ$BZU…Bœ$BøR0SÛy¾AZU…B †QB¡ç¡BZU…B †QBPS`S:’dAZU…BMUB †QBZU…BMUB †QBZU…BqÛŽBÐó´BZU…BqÛŽB€SS S°S%†ÑAZU…Bœ$Bœ$BZU…B%†ÑAàSðS%†ÑAZU…B0 [B³ª¦BZU…B0 [BÐó4B|a˜ÁqÛB:’äÁ%†ÑAMUÂÆm«AMUÂT Tœ$BZU…B%†ÑA%†ÑAZU…Bœ$BZU…B%†ÑAœ$B`TpT€TG’€B“îB0 [Bo’äBHBJ ÛBÐó4BÈBÐó4BÐó´BHB¡ç¡B0 [B‰a˜B_nBZU…B_nBT’dBHBÛy>B0 [Bo’äBHB%†ÑBHBèy¾B0 [B¹m«B_nB¡ç¡BG’€BqÛŽBG’€B„žwB_nB%†QB¡ç!B¬m+B_nBMUBG’€BÛy¾AG’€B:’dA_nB|a˜@0 [BHB|aÁHB|a˜Á0 [B:’äÁHB|aB_nB:’äA_nB|a˜A0 [B|aAHB|a˜@Ðó4B|a˜ÀÐó4B:’dÁHBÛy¾Á0 [B:’äÁG’€BMU ¨TøT €U%†QB“îB%†QBMUÂèU¡ç!B“îBHBo’äB0 [BJ ÛB_nBÈB_nBÐó´B0 [B¡ç¡BHB‰a˜BÐó4BZU…BÐó4BT’dB0 [BÛy>BHBo’äB0 [B%†ÑB0 [Bèy¾BHB¹m«BÐó4B¡ç¡B¡ç!BqÛŽB¡ç!B„žwBÐó4B%†QBG’€B¬m+BÐó4BMUB¡ç!BÛy¾A¡ç!B:’dAÐó4B|a˜@HB0 [B|aÁ0 [B|a˜ÁHB:’äÁ0 [B|aBÐó4B:’äAÐó4B|a˜AHB|aA0 [B|a˜@_nB|a˜À_nB:’dÁ0 [BÛy¾ÁHB:’äÁ¡ç!BMU VPV ØV|aA:’äA|aA|aB:’dA%†QBÛy¾AT’dBMUBT’dB¬m+B%†QB„žwB|aBqÛŽBMUB¡ç¡BMUBÐó´B|aBèy¾BÛy>B|aA|aB:’dAÛy>BÛy¾A%†QBMUB%†QB¬m+BÛy>B„žwBMUBqÛŽB:’äA¡ç¡B:’äAÐó´BMUBèy¾BÛy>Bèy¾BT’dB @W ˜WqÛŽBÈBMUBMUÂÛy>BZU…BMUB„žwBÛy¾A%†QB|a˜A|aB|a˜AÛy¾AÛy¾A:’dAMUB|a˜@Ûy>B:’dBqÛŽB|a˜@¡ç¡B:’dA¹m«B:’äA¹m«B¬m+B¡ç¡B%†QBqÛŽB„žwB:’dBZU…BÛy>BZU…BXX%†QB%†ÑB1%†QB%†ÑB@1%†QB%†ÑB1%†QB%†ÑBp2%†QB%†ÑBp3%†QB%†ÑB˜4%†QB%†ÑB°4%†QB%†ÑB5%†QB%†ÑB`5%†QB%†ÑB˜5%†QB%†ÑBÐ5%†QB%†ÑB 6%†QB%†ÑB86%†QB%†ÑBh6%†QB%†ÑB€6%†QB%†ÑB7%†QB%†ÑB87%†QB%†ÑB°7%†QB%†ÑB08%†QB%†ÑB`8%†QB%†ÑBø8%†QB%†ÑB¸9%†QB%†ÑBà9%†QB%†ÑBØ:%†QB%†ÑB˜;%†QB%†ÑBð;%†QB%†ÑBh<%†QB%†ÑB<%†QB%†ÑB¸<%†QB%†ÑBà<%†QB%†ÑB€=%†QB%†ÑBh>%†QB%†ÑB¨>%†QB%†ÑBh?%†QB%†ÑB@%†QB%†ÑBˆ@%†QB%†ÑBØ@%†QB%†ÑB(A%†QB%†ÑBèA%†QB%†ÑB(B%†QB%†ÑBPB%†QB%†ÑB¨B%†QB%†ÑBàB%†QB%†ÑBC%†QB%†ÑBhC%†QB%†ÑB¸C%†QB%†ÑBxD%†QB%†ÑBàD%†QB%†ÑB¨E%†QB%†ÑB(F%†QB%†ÑBàF%†QB%†ÑBG%†QB%†ÑBhG%†QB%†ÑBG%†QB%†ÑBàG%†QB%†ÑB H%†QB%†ÑBXH%†QB%†ÑB˜H%†QB%†ÑBðH%†QB%†ÑB I%†QB%†ÑBhI%†QB%†ÑB¨I%†QB%†ÑBàI%†QB%†ÑBJ%†QB%†ÑB J%†QB%†ÑB0K%†QB%†ÑB°K%†QB%†ÑB8L%†QB%†ÑBÐL%†QB%†ÑBM%†QB%†ÑBÈM%†QB%†ÑB N%†QB%†ÑBhN%†QB%†ÑBÈN%†QB%†ÑBO%†QB%†ÑB0O%†QB%†ÑB¸O%†QB%†ÑBP%†QB%†ÑB°P%†QB%†ÑB8Q%†QB%†ÑBÈQ%†QB%†ÑBR%†QB%†ÑB¨R%†QB%†ÑBèR%†QB%†ÑB@S%†QB%†ÑBpS%†QB%†ÑBÀS%†QB%†ÑBT%†QB%†ÑBPT%†QB%†ÑBT%†QB%†ÑBÐU%†QB%†ÑBøU%†QB%†ÑB(W%†QB%†ÑBðW%†QB%†ÑB˜X%†QB%†ÑBCVAÈBCVAMUBCVA|aA…ë A|a˜@CVA&‘A|a˜@CVA|aA¨`¸`×£€@ÈB×£€@ZU…B÷u(BÈB÷u(BZU…Bð`aI.%B“îBãÇþ@MUÂÀ»‹B“îB"BMUÂãÇþ@T’dBØA•BT’dBÍÌL@:’äAÀ»‹B:’äA a0a@aPa7 åA“îB7 åA|a˜ÁZµ>B“îBZµ>B|a˜Á1ùŽB¹m«BÚwBèy¾BZµ>BÈB7 åAÈB4€eAèy¾Bq=š@¹m«Bq=š@‰a˜BvOAZU…B4€eA„žwBØð¾AT’dB‰ÁQBÛy>BÚwB¬m+Bs…B|aB1ùŽB:’äA1ùŽB:’dAÚwB|a˜@Zµ>B7 åA4€eA|a˜@q=š@:’dA€aa a &¸BÈB…Ë@#[ñAÈBðÅBÐó´BðÅB¡ç¡BÁ¹ BqÛŽBÄBËAZU…B $~AZU…B…Ë@‰a˜B…Ë@¹m«BMó1Aèy¾Be*¥AÈB#[ñAÈBðÅBèy¾BêWBÐó´B”‡ˆBÐó´BÛ¥Bèy¾B &¸BÈB¬ ’BMUBø~B:’äAÉöjB|a˜AÉöjB|aA”‡ˆBÓ›BóŸ®B|a˜@ &¸B:’dA &¸BÛy¾AÛ¥BMUB¬ ’BMUBXbhb èbžoÊBT’dBžoÊB„žwB“éÀBZU…B{c·BZU…BdÝ­B„žwBLW¤B%†QBK‘B:’äAÙ}|B:’dA`eVB|a˜@M0B†8ÈA‘xA|a˜@ÓÞ+A|aA)\¿@|a˜A)\¿@:’äAÓÞ+A|aB‘xA¬m+B1YCB„žwB`eVBZU…BªqiB‰a˜BªqiB¹m«B`eVBèy¾BM0BÈB¢4 Bèy¾BåPîA¹m«BåPîA‰a˜B¢4 B„žwBM0BÛy>BŇB:’dA4ÑšB|a˜@dÝ­B“éÀBžoÊB|a˜@žoÊB|aA"Xc{Ž@ÈB{Ž@ZU…Bpd8§#B“îB²ûAJ ÛBôì®Aèy¾BlxEA‰a˜B\ò@%†QB\ò@MUBlxEA|aAôì®A|aÁ²ûAÛy¾Á8§#BMU ˆdÃõ¨@“îB]ÜlAJ ÛBížÂAèy¾BÕgB‰a˜BtB%†QBtBMUBÕgB|aAížÂA|aÁ]ÜlAÛy¾ÁÃõ¨@MU àdð'öAqÛŽBð'öA:’dAR¸Þ@T’dBåPZB:’äAåPZBT’dBR¸Þ@:’äA8eHeXe1YCB¹m«B1YCB)\¿@¬m+B{c·B¬m+B€ee9E’A|a˜@´YXAö( A|a˜@´YXA|aA9E’A|a˜@9E’A|a˜À´YXA:’dÁö( A|a˜Á°eö(ì@¬m+BH0ºB¬m+Bøeb¡QA|aA¤pA|a˜@b¡QAéŽA|a˜@b¡QA|aAf®ç@:’dÁ;ГBÈB@f¢4BÈB' šAèy¾BÓÞA¡ç¡B)\Ÿ@T’dB)\Ÿ@¬m+BÓÞA|a˜A' šA|a˜@¢4BM,BªqeB|a˜@Å…B|a˜AKB¬m+BKBT’dBÅ…B¡ç¡BªqeBèy¾BM,BÈB¢4BÈBXf¸=A¡ç¡BÀªA¹m«Bœ„BÈBœ„Bèfé"A‰a˜Bé"A¡ç¡BÎoAÐó´BF¥Aèy¾BÖéAÈBÀABÈB94gBèy¾Bi@zBÐó´BL¦†B¡ç¡BL¦†BqÛŽBi@zB„žwBð'TBÛy>B¤p­@d,Bg|ahAÈBBÏ…BÈBMUB„žwBÛyRB„žwBT’xBT’dBBÏ…B%†QBZUB|aBZUB:’äABÏ…B:’dA%†eB|a˜@|a,BÛyæA|ahA|a˜@¾0A|aA @|a˜AˆgúþMBÈBìQx@MUBž–BMUBúþMBÈBúþMBh høxBÈB $fAÈBMóAT’dB $fA„žwB#[åAZU…B Ò+BZU…BÉödB„žwB”‡…B%†QB¬ B|aB¬ B:’äA”‡…B:’dAÉödB|a˜@ Ò+B#[åA $fA|a˜@MóA|aA…›@|a˜A@h@äzB¹m«BØgBèy¾Bh³.BÈB ›BÈBôìžAèy¾Blx%A¡ç¡B\²@T’dB\²@MUBlx%A:’dAôìžA|a˜@ ›B8§BÇËTB|a˜@@äzB:’dA8ø†B:’äA8ø†BMUB@äzBÛy>BÇËTBT’dB8§B„žwB ›B„žwBôìžAT’dBlx%AÛy>B\²@MUBÐhtBÈB]ÜÄA…ë±@ÈBtBÈBi i¨FëAÈBûqAèy¾BXÊ%A¹m«BXÊ%A‰a˜BûqAZU…BI.ÅA„žwBãÇ.BT’dB‹ìgB%†QBu‡B¬m+BˆBMUBˆB|a˜Au‡B|aA»øzB|a˜@ÔAB¨FëAûqA|a˜@XÊ%A|aA33³@|a˜A33³@MUBXÊ%A¬m+BêŸA%†QBƒ¯BT’dBBàTB„žwB»øzBZU…Bu‡B‰a˜Bu‡B¹m«B»øzBèy¾BÔABÈB¨FëAÈBÀiu‰BZU…B»ø~B%†QBBàXB¬m+B³»B|aBƒ¯ B|aBê§A¬m+BXÊ5A%†QB33Ó@ZU…B33Ó@qÛŽBXÊ5A¹m«Bê§Aèy¾Bƒ¯ BÈB³»BÈBBàXBèy¾B»ø~B¹m«Bu‰BZU…Bu‰B¬m+B»ø~B|a˜ABàXB|a˜@³»B¨FóA‹ý€A|a˜@XÊ5A:’dA°jvOaAZU…B¸A„žwBvOaAT’dBÀ–A„žwBvOaAZU…BvOaA|aA¸A|a˜@vOaAÀ–A|a˜@vOaA|aApk˜kñcOAZU…B33A„žwBñcOAT’dBXÊA„žwBñcOAZU…BXÊA|a˜@ñcOA33A|a˜@ñcOA|aAXÊA|a˜@XÊA|a˜ÀñcOA:’dÁ33A|a˜ÁÐkøkB€žB¹m«B ×C@¬m+BB€žBHlff¶@T’dBÔ¶BT’dBff¶@:’äAÔ¶B:’äAhlxl…ë1@¹m«BåðB¬m+B…ë1@˜lR¸A‰a˜BR¸A¡ç¡BéRAÐó´BçŒAèy¾B¥½ÛAÈB‘:BÈBð'`Bèy¾B94sBÐó´B4 ƒB¡ç¡B4 ƒBqÛŽB94sB„žwBð'`BT’dB2÷BÛy>B2÷BMUB2÷B|aAëB|a˜@2÷Ba'B|a˜@2÷B|aA¸l(mOÞDB%†QBðÅBT’dB#[ñAT’dBÄBËAÛy>BÄBËA¬m+B#[ñAMUBðÅBMUBOÞDB|aBOÞDBT’dBOÞDB|aBêWBMUBø~BMUB”‡ˆB¬m+B”‡ˆBÛy>Bø~B„žwBêWBqÛŽBðÅB‰a˜BÁ¹ B‰a˜Be*¥AqÛŽBMó1A„žwB…Ë@Ûy>B…Ë@¬m+BMó1A:’äAe*¥A|a˜AÁ¹ B:’dAðÅB:’dAêWB|a˜A`m m|a"BÈB @|a"BÈB‰aBI†AMUBBÏ€BMUBHnXnhnR¸6AÈBR¸6AR¸6AÈBÀYBÈB4 ‰Bèy¾BL¦’BÐó´Bd,œB¡ç¡Bd,œBqÛŽBL¦’B„žwB4 ‰BT’dBÀYB%†QBR¸6A%†QBÀYB%†QB4 ‰BÛy>BL¦’B¬m+Bd,œBMUBd,œB|a˜AL¦’B|aA4 ‰B|a˜@ÀYBR¸6An  n èn]-œB‰a˜BE§’B¹m«B+6Bèy¾B²YBÈBôì BÈB*©ÍAèy¾BlxA¹m«BÀ6A‰a˜B¸Õ@„žwB¸Õ@|aBÀ6AÛy¾AlxA:’dA*©ÍA|a˜@ôì B²YB+6B|a˜@E§’B:’dA]-œBÛy¾APo)\?AÈB)\?A)\?AÈBW,5BÈBåPnBèy¾B¯4ŠB¹m«BǺ“B‰a˜Bß@B„žwBß@B|aBǺ“BÛy¾A¯4ŠB:’dAåPnB|a˜@W,5B)\?Aèo øoR¸6AÈBR¸6AR¸6AÈBL¦’BÈBR¸6A%†QB‘FB%†QBR¸6AL¦’Bhpxpˆp˜pR¸6AÈBR¸6AR¸6AÈBL¦’BÈBR¸6A%†QB‘FB%†QBÈpØpèp*úœB‰a˜Bt“B¹m«Bãg€Bèy¾BL·ZBÈBކBÈB]ÜÐAèy¾BŸ«„A¹m«B&=A‰a˜B…ëá@„žwB…ëá@|aB&=AÛy¾AŸ«„A:’dA]ÜÐA|a˜@ކBL·ZBãg€B|a˜@t“B:’dA*úœBÛy¾A*úœB|aBL·ZB|aB*úœB|aBq¨qR¸6AÈBR¸6Ad,œBÈBd,œBR¸6A%†QBd,œB%†QBÈqØqèqÂ-AÈBÂ-ArÛyHBÈBÛyHBÛy¾A¬m5B|aA|a"B|a˜@:’øA|a¬A|a@A|a˜@|aè@|aA @Ûy¾A @MUB (ráz4AÈBáz4A¶ä›BÈBáz4AMUB¦[ BT’dB¶ä›B€rr rHá:AÈBHá:AHá:AS¥‰BÈrØrÂ-AÈBÂ-AÂ-AÈB ÒCBÛ®BÈB ÒCBÛ®BÈBÛ®Børss(sq=2AÈBq=2Aq=2AÈB›B›BÈB›BXshsxsà> BÈBMÊAèy¾B†8|A¹m«BÈ0A‰a˜B®Ç@„žwB®Ç@|aBÈ0AÛy¾A†8|A:’dAMÊA|a˜@à> BžoWBˆ}B|a˜@;БB:’dASV›BÛy¾AjܤB|aBjܤB„žwBSV›B‰a˜B;БB¹m«Bˆ}Bèy¾BžoWBÈBà> BÈB sš™AAÈBš™AAš™AAÈBÔ[BÈB]|ŠBèy¾Bu”BÐó´BˆB¡ç¡BˆBZU…Bu”BT’dB]|ŠB%†QBÔ[BÛy>Bš™AAÛy>BPt `tP|BÈBãÇÂAèy¾BI.mA¹m«B‹ý A‰a˜Bš™©@„žwBš™©@|aB‹ý AÛy¾AI.mA:’dAãÇÂA|a˜@P|B­SBˆÅyB|a˜@óîB:’dA u™BÛy¾A#û¢B|aB#û¢B„žwB u™B‰a˜BóîB¹m«BˆÅyBèy¾B­SBÈBP|BÈBß @B|a˜A u™B|aÁÀthuHá:AÈBHá:AHá:AÈBþ%ZBÈBS¥‰Bèy¾Bk+“BÐó´Bƒ±œB¡ç¡Bƒ±œBqÛŽBk+“B„žwBS¥‰BT’dBþ%ZB%†QBHá:A%†QBŸ 4B%†QBƒ±œBˆu ˜uèuZU•B¹m«B*I‚Bèy¾B¬mKBÈBÛyþAÈB¾0ŒAèy¾BA¹m«BA‰a˜B¾0LAZU…B¾0ŒA„žwB|aØAT’dBÛy^BÛy>B*I‚B¬m+BBÏ‹B|aBZU•B:’äAZU•B:’dA*I‚B|a˜@¬mKBÛyþA¾0ŒA|a˜@A:’dAvðÅBÈBðÅB= @ÈB¬ ŠBÈB¸vÈv×£8AÈB×£8A:’äAKj‚A:’dA ›ÎA|a˜@r BrŠFB¯B|a˜@½ã’B:’dAÕiœB:’äAÕiœBÈB èv= @ÈB Ò!BÛBÈB Ò!B@wPw{@ÈBj<ÐA#[GBÈBj<ÐA#[GBÈBL“BŒêÂBÈBL“Bpw€ww w @ÈBZUŠBZUŠBÈB @Ðwàw\Â?ÈB÷uB%†QB÷uBÇk›BÈB÷uB%†QBxxZUŠBÈB @ @ÈBZUŠBÈB @ZUŠB8xHxXxÃõø@“îBÃõø@MUŸ«HA“îBŸ«HAMUÂÃõø@“îBt$B“îBÃõø@MUÂt$BMU€xx x°xHáº@ÈBn‘B:’dÁàx¬ B“îB¬ BMUÂÜB“îBÜBMUÂ{Ž@“îBÜB“îB{Ž@MUÂÜBMUÂøxyy(yM0BJ ÛB)\¿@¬m+BM0BJ ÛBLW¤B¬m+BXyhyÍÌŒ¿MUÂòRÏBMUÂòRÏB:’äÁÍÌŒ¿:’äÁÍÌŒ¿MUˆymBÈB[ScBqÛŽBmBÈB{âAèy¾B[ScBqÛŽB¸yÈy¦JBZU…B¦JB¦JB%†QB-2YB„žwBÎ3BZU…BêóAZU…BÁ¹§A„žwB7A%†QBÂÕ@|aBÂÕ@:’äA7A:’dAÁ¹§A|a˜@êóAÎ3B-2YB|a˜@¦JB:’dAðyzö( AÈBö( Aö( A%†QB9E’A„žwB÷uÞAZU…BŠ_(BZU…BéwNB„žwBbtB%†QBI΃B|aBI΃B:’äAbtB:’dAéwNB|a˜@Š_(B÷uÞA9E’A|a˜@ö( A:’dA€zzϦzB%†QBVŽTB„žwB÷u.BZU…BÑ¢êAZU…BržA„žwBª‚$A%†QB×£°@|aB×£°@:’äAª‚$A:’dAržA|a˜@Ñ¢êA÷u.BVŽTB|a˜@ϦzB:’dA{±!wBÈB±!wB±!wB%†QB7 QB„žwBØð*BZU…B“˜ãAZU…BÕg—A„žwB/nA%†QBáz”@|aBáz”@:’äA/nA:’dAÕg—A|a˜@“˜ãAØð*B7 QB|a˜@±!wB:’dAˆ{˜{= ·@|aBœs{B|aBœs{BÛy>BmghBT’dB#[UB„žwBÄB/BZU…Bj<ìAZU…B¬  A„žwBݵ'A%†QB= ·@|aB= ·@:’äAݵ'A:’dA¬  A|a˜@j<ìAÄB/B#[UB|a˜@œs{B:’dA|ÎBÈBÞêAÈB ÒAèy¾B‚soA¡ç¡B‚soA{.?ZU…BŸ BZU…B¨|Ð|øzBZU…BøzB|aÁÉöfBÛy¾ÁêSB:’äÁ Ò-BMUÂ#[éAMUÂe*A:’äÁøzB%†QBêSB„žwB Ò-BZU…B#[éAZU…Be*A„žwBMó!A%†QB…«@|aB…«@:’äAMó!A:’dAe*A|a˜@#[éA Ò-BêSB|a˜@øzB:’dAð|(}š™AÈBš™Aš™AÛy>Bê¿A„žwBT£BZU…BãÇ>BZU…BBàdB„žwB‹ìwBÛy>B‹ìwB¨}¸}ìQ AÈBª‚lAèy¾B´YœAÈBª‚lA%†ÑBìQ AÈBª‚lAZU…Bª‚lA~(~΋AÈB-2±Aèy¾BŒJ×AÈB-2±A%†ÑB΋AÈB-2±AZU…B-2±A:’dÁ΋A:’äÁ@¤û@MUÂázÔ¿MUÂH~p~š™AÈBš™ABàdBZU…Bš™A|a˜AI.åA|aB‹ìwB¨~¸~È~ìQ AÈBìQ Að~š™AZU…Bš™Aš™AÛy>Bê¿A„žwBT£BZU…BãÇ>BZU…BBàdB„žwB‹ìwBÛy>B‹ìwB‹ìwBÛy>Bˆ˜B„žwB¼”«BZU…Bé&ÈBZU…B33ÛB„žwBX¹äBÛy>BX¹äBPHáAZU…BHáAHáAÛy>BÁ¹»A„žwB?õBZU…BÎ=BZU…B-2cB„žwBw>vBÛy>Bw>vB °åPæAZU…B' šA„žwBÓÞA%†QB)\Ÿ@|aB)\Ÿ@:’äAÓÞA:’dA' šA|a˜@åPæAM,B`eRB|a˜@Ù}xB:’dAÅ…B:’äAÅ…B|aBÙ}xB%†QB`eRB„žwBM,BZU…BåPæAZU…Bø)\AZU…B)\AMUÂ)\A%†QBÓÞ—A„žwB‘äAZU…BW,+BZU…B¶DQB„žwB/]wB%†QB¯4…B|aB¯4…B:’äA/]wB:’dA¶DQB|a˜@W,+B‘äAÓÞ—A|a˜@)\A:’dAˆ€˜€}îwBZU…B}îwBMUÂ}îwB%†QBÖQB„žwB¥½+BZU…B-2åAZU…Bo™A„žwBb¡A%†QBHáš@|aBHáš@:’äAb¡A:’dAo™A|a˜@-2åA¥½+BÖQB|a˜@}îwB:’dA()\AZU…B)\A)\A|aBçŒcA%†QB2÷½A„žwBøBZU…B†8>BZU…B¨¸òRdB%†QB¨FQB„žwB"BZU…Bû½AZU…BñcA„žwBff–@%†QBñcA¬m+B·â—A|aBI.+BMUB¨FQB:’äAòRdB|a˜AòRdB:’dA¨FQB|a˜@"Bû½AñcA|a˜@ff–@:’dAð6mAÈB6mA|a˜Ah³œA|a˜@&äèArŠBq= ?ZU…BB~BZU…B€‚¨‚)\AZU…B)\A|a˜AçŒcA|a˜@2÷½A' B†8>B|a˜@/]wB|a˜A/]wBZU…B/]wBÈ‚ƒffæ?ZU…B¡øòAˆÅkBZU…B¡øòA ƒ0ƒ @ZU…B|a¬A|a"BZU…B|a¬A|a"BZU…BT’nB‰aBZU…BT’nBPƒ`ƒpƒ€ƒázÔ?ZU…Bü)XBü)XBZU…BázÔ?°ƒÀƒûÑ@ZU…B€ˆ B·Ñ~BZU…B€ˆ BBàÌA|a˜Áƒ¯€A:’äÁûÑ@MUÂffæ?MUÂàƒðƒ´HcBZU…B{Ž@{Ž@ZU…B´HcBZU…B{Ž@´HcB0„@„P„„ùA“îB[S­Ao’äBû:‡AJ ÛB9EBAÈB9EBAÐó´Bû:‡A¡ç¡B[S­A‰a˜BºkÓAZU…BºkÓAT’dBû:‡AÛy>B[S­Ao’äBû:‡A%†ÑBû:‡Aèy¾B[S­A¹m«BºkÓA¡ç¡B„ùAqÛŽB„ùA„žwBºkÓA%†QBö(ì@¬m+BºkÓAMUB„ùAÛy¾A„ùA:’dAºkÓA|a˜@[S­Aû:‡A|aÁû:‡A|a˜Á[S­A:’äÁû:‡A|aBºkÓA:’äAºkÓA|a˜A[S­A|aAû:‡A|a˜@9EBA|a˜À9EBA:’dÁû:‡AÛy¾Á[S­A:’äÁ„ùAMU x„È„ P…×£8A“îB×£8AMU¸…HáA“îBb¡•Ao’äBÁ¹»AJ ÛB ÒáAÈB ÒáAÐó´BÁ¹»A¡ç¡Bb¡•A‰a˜B_AZU…B_AT’dBÁ¹»AÛy>Bb¡•Ao’äBÁ¹»A%†ÑBÁ¹»Aèy¾Bb¡•A¹m«B_A¡ç¡BHáAqÛŽBHáA„žwB_A%†QB?õB¬m+B_AMUBHáAÛy¾AHáA:’dA_A|a˜@b¡•AÁ¹»A|aÁÁ¹»A|a˜Áb¡•A:’äÁÁ¹»A|aB_A:’äA_A|a˜Ab¡•A|aAÁ¹»A|a˜@ ÒáA|a˜À ÒáA:’dÁÁ¹»AÛy¾Áb¡•A:’äÁHáAMU Ѕ † ¨†Há:@:’äAHá:@|aB Òõ@%†QBF¥‰AT’dBÖÕAT’dBaB%†QB94]B|aBL¦BMUB|²”BMUB«¾§B|aBÃD±BÛy>BHá:@|aB Òõ@Ûy>BF¥‰A%†QBÖÕA%†QBaBÛy>B94]BMUBL¦B:’äA|²”B:’äA«¾§BMUBÃD±BÛy>BÃD±BT’dB ‡ h‡%†QBÈB:’dAMUÂ:’äAZU…B:’dA„žwB|a˜@%†QB|aBÛy¾A|a˜@:’dA:’dA|a˜@:’äA|aB%†QB|a˜@„žwB:’dAZU…B:’äAZU…B¬m+B„žwB%†QB%†QB„žwB|aBZU…B:’äAZU…BЇà‡%†QB%†ÑBà`CVA‹ýÔAarЏA¥½MB`a"B*úžB@bûœBÕi˜B@cOÞDB &ÁBhd`eVB„ËB€d{Ž@…ëYAØdôì®Av±Bheð'öA‰ÁmB e1YCB4‚ÂBðe´YXAª‚ÐAfÊòHB ‚ÉB8fb¡QAÓÞÓAPfK"B¡6¤BàfÒ@B'"šBgØðöA…B€gaBK›BhMUBéšB0hkÚBSV BÈhðÅB—_›Bˆi ›Bœ“B°i½’BtšB¨j³»BZU›Bhk³»B-!”BÀkvOaAXÊÑA8lñcOA/nÒA`líž$B“8£Bˆlx:BB4‚ÂB°l4€#B“8£BPm2÷BIΓB8nÁ¹ BǺ”Bxn|a"B#û B8oa3Bß@§Bào$ùB*ú¨BXpW,5BÊ’ªB¨p2÷Bž^œBøp2÷BV}B¸q½’!B†‰³Bøqa3Bd,²B rÂ-AffªAxr:’øAúþoB°rt2BE§žBèro!BS¥ŽB8s ÒCBÇkÂBˆs©ä1B±BHt?W1B7©±B°t³»5BZU«Bxu¯”-BV.°BøuŸ 4BÀ»¤B°vMU%BE§¡BØvðÅB¶äB8wB~3B1ù²B`w Ò!B“8£B°w#[GB7 ÉBðwMUBÀ»B(x÷uBMŸBhxMUBO~“BÀxކ°At8Bðxv±BÕiœB8y›æ»A½’9BxyM0Bv´B°y¾MB¾ÐBàyÌ.*B$§Bpzo B¯4…B{[SBíŒB€{˜]B†Ø‰B|yØB›†ŒB |e* Bº ‰Bà|‚soAížB˜}Á¹B?÷Bð}T£BÁ ŽB8~ª‚lAéæA˜~΋AôìBØ~T£BzBìQ AR¸šAˆ‹ìwB‹ì÷Bè?õBÃB€€¢4BV}B' B›B˜F¥B]|Bà2÷½AûEBx‚uäA´HyB¸‚6mAÄBBƒøBoRŽB@ƒ¡øòA_irBƒ|a"B#û BЃ‰ÁËA šaB „€ˆ B-!„B`„úþáA´HwB …[S­Aœ„&BÈ…×£8Aq=¾Aø†b¡•AÅà%BÀ‡À7BqŒ¶BhˆMUBZU…B@-DTû!@@@@@€?ð¿à?€À@` ¸  @ @ÀÀ€àà€€ @ @è€À@` ¸  @ @‘hP @8‘hP  @X‘h@  @x‘h @ @˜‘€pHHH8€?€? @¸‘ ø À@Ø‘``  @ø‘`` P @’`` @ @8’``@  @X’`` @ @x’Øà P @˜’`p p@ @¸’à@@@À €@Ø’à@@@À @€@ø’à@@@À@ €@“à@@@À@€€@8“`€À ` €@X“`€À ` @€@x“`€À `@ €@˜“`€À `@€€@¸“À @`€€€`@@€@ؓؠp(ØÀ@ø“à ` À@ @€@”à ` À €@8”à ` À P€@X”à ` À @€@x”à ` À@ €@˜”à ` À@€€@¸”àPP`PP  @Ø”à@pHp@àÀ@ø”8((Dî A•8lDDDDî( A@•8lDDDDî( Ah•8lDDDDî A•8lDDDDî  A¸•€|fRRJf> €?Aà•ˆP PˆÀ@–xÌ„„„ÌxP à@(–xÌ„„„ÌxP( à@P–xÌ„„„ÌxP  à@x–xÌ„„„Ìx à@ –xÌ„„„Ìx @ à@È–äLLTTdîP( Að–øLDäDLøà@—à@@@@@à  €@8—à@@@@@à @ €@`—à@@@@@à@  €@ˆ—à@@@@@à@€ €@°—øH@p@HøP À@Ø—øH@p@HøP  À@˜øH@p@Hø  À@(˜øH@p@Hø @ À@P˜` xÄ€€€Ä| @@à@x˜ïIx.(9A ˜îD|((8( AÀ˜îD|((8( Aè˜îD|((8( A™îD|((8( A8™îD|((8 A`™îD|((8  Aˆ™à €@@@@€@°™D>,Ô(HäAЙN$*öHÈDAð™D>,ôHÈDAš PP €¿ @0šà@ @À€@Pšà@À@@À@@pšÀ @@@€@š€À@°š((((hèèè| @À@К€€è@ @øš€@ À@@›À @à@À@@8›à@ `@À@@X›ø ø À@x›``@À€@˜›àÀÀ€@¸›8Dª²ºD8€¿AØ›àÀ€@ø›ø€¿€¿à@œP  P€¿ @8œà  ÀÀ€@Xœ8Dš¢šD8€¿Axœ €¿ÀÀ @˜œà P @p €? @¸œ€€€€€€@àœp ø ØPˆ @ˆpPPpˆ€¿ @ ðÈ@à@P0 @@€à€p€? @`€€€€€€€¿@@@€@ ˜dÀà@À€@@@ @@@€ @€@à€€€€€€€€€ @@ž @@@€@@@  @€@0žð@ ð @Xž@@ 0PHÜ€?@ @xžØP PØÀ@˜ž(lT’ÛA¸ž `PØ @Øžh @øž0@@@à@€@Ÿà `€à€@8Ÿà@@` €@XŸ8pp@ @xŸÀ€àà@ @˜Ÿ`` @¸ŸØà @ØŸÛ’’’ìAøŸà@@@@@À€@ ˜à €€ @8 €@@@@@À@ @@@X @@@@À@@@€ Øà€€ @  à`@  p@ @À à@@@à@0€@à `€À `€@¡hp0 @ ¡`€€€`€@@¡àà€€ @`¡à ` À€@€¡À€ À@@ ¡ø@@ @À¡  @€¿€À @à¡À@@@@@@@À @@@¢ @@@€€@@(¢À€€€€€€€À @@@H¢øˆ@ ˆøÀ@p¢8((DîA¢îD((DîA°¢""UUÉ€ˆ€ÝÀ  AТ((lDîAø¢8lDDDDîA£p ¨øÀ@8£à`Àp @X£ìHPpHHðà@x£ pÌ„„„Ìx @à@˜£à@@pHHðÀ@À£xÌ„„„Ìxà@à£äLLTTdîA¤ë€IUUcc〠 A ¤øH@@@@àÀ@H¤ìHP`PHìà@h¤À  p€@ˆ¤à@@@@@à€@¨¤îDD|DDîAȤxÄ„œ€Ä|à@è¤à@@p@HøÀ@¥øH@p@HøÀ@(¥øLDDDLøà@H¥xÄ€€€Ä|à@h¥ðHHpHHðÀ@ˆ¥îD|((8A¨¥>@’­¥¥B< @AÈ¥@@@  à€@ð¥€@ @€ @¦øø€¿À@0¦ @€@ €¿ @P¦€€€€€¿@@@p¦€€€¿@@¦À p` @°¦``` @Ц@@@ ð @ð¦`à@0 @§àà@p @0§øP0 @P§à`` @p§ð@ ` @§à@@@@À@€¿ @°§`` @Ч€€@@@ @@ð§€€¿@@¨ð€¿Àà@0¨€€€€¿@@@P¨ ø À@p¨ @ €À @¨€@@ @@€ @€@°¨ @@€€€@@  @€@ب@À À@@©v˜tnP0A ©D**V¨¤~A@© à`€p  €? @`©PPøPøPP @ˆ©   À€@¨©€€€€€€€¿@@È©@è©ð©Щ°©©p©H©(©©è¨À¨˜¨x¨X¨8¨¨ø§ا¸§˜§x§X§8§§ø¦ئ¸¦˜¦x¦X¦8¦¦ø¥Ø¥°¥¥p¥P¥0¥¥ð¤Ф°¤¤p¤P¤0¤¤è£È£¨£€£`£@£ ££à¢¸¢˜¢x¢X¢0¢¢è¡È¡¨¡ˆ¡h¡H¡(¡¡è È ¨ ˆ h @    àŸÀŸ Ÿ€Ÿ`Ÿ@Ÿ ŸŸàžÀž ž€ž`ž@žžðȨˆhH(èœÈœ œ€œ`œ@œ œœà›À› ›€›`›@› ››àš¸š˜šxšXš8ššø™Ø™¸™˜™p™H™ ™ø˜И¨˜ˆ˜`˜8˜˜è—À—˜—p—H— ——Ø–°–ˆ–`–8––ð•È• •x•P•(••à”À” ”€”`”@” ””à“À“ “€“`“@“ ““à’À’ ’€’`’@’ ’’à‘À‘ ‘€‘`‘@‘ ‘øÐÐà ªàð 10€0€`€`Àñà33  @0A˜­ð````ns€a€`À`À`À`À`À`Àa€s€n````à €¿ @@Aà­àð 10€0€`€`Àñà€€  @0A(®à>ÀqÀ`À`À`À`À`À`À`À`ÀáÀ33 €¿PAp®à>ÀqÀ`À`À`À`À`À`À`À`ÀáÀ! €¿PA¨®à>ÀqÀ`À`À`À`À`À`À`À`ÀáÀ€€ €¿PAè®à>ÀqÀ`À`À`À`À`À`À`À`ÀáÀ 80 €¿PA(¯ÀÞs€q€ÐÀØÀÈÀÌÀÄÀÆÀc€s€ÀÀ €¿€?@Ah¯ÿðÿ𠀿À`A ¯s€a€ÀÀÀÀÀÀÀÀÀÀÀÀa€s€33 €¿@AЯs€a€ÀÀÀÀÀÀÀÀÀÀÀÀa€s€'€ €¿@A°s€a€ÀÀÀÀÀÀÀÀÀÀÀÀa€s€! €¿@A@°s€a€ÀÀÀÀÀÀÀÀÀÀÀÀa€s€€€ €¿@A€°s€a€ÀÀÀÀÀÀÀÀÀÀÀÀa€s€ 80 €¿@AÀ°ñà`À`À`À`À`À`À`À`ÀqÀo€ç'€ €¿PA±s€a€ÀÀÀÀÀÀÀÀÀÀÀÀa€s€Æ<q€À €¿@A8±x0000000000pÌÌÀ@x±x0000000000p„Hx0À@ ±ð``````````à€`8€¿À@бx0000000000p0àÀÀ@²p€àÀÀÀÿ€Á€A€c33 €¿0A0²p€àÀÀÀÿ€Á€A€c! €¿0Ah²p€àÀÀÀÿ€Á€A€c  €¿0A¨²p€àÀÀÀÿ€Á€A€cp` €¿0Aè²<fp€àÀÀÀÀÀA€c€ €¿À@0A(³pðûøÇ„ÃÃc;ü c g˜<𠀿€Ah³q€ûÇÃÃc;cg>"" €¿0A˜³q€ûÇÃÃc;cg>ff €¿0Aسq€ûÇÃÃc;cg>\: €¿0A´q€ûÇÃÃc;cg>B$< €¿0AH´q€ûÇÃÃc;cg>  €¿0Aˆ´q€ûÇÃÃc;cg>p` €¿0AÈ´çl€lÀ`À`ÀaÀa€c€glca€a€a€a€3 €¿@Aµü000?À0p00000000p?À000ü €¿pAHµà€€€€€€À@` 080 ü?Àp0€Aˆµà00000000000000ü00€¿Aеà00000000000000ü`À€€¿A¶à00000000000000üÀp0€¿A`¶à00000000000000ü@€€¿A¨¶ 'à88hdÂÂÁÁÀƒÀƒÀC`F`&88䀿€?Að¶€@ÀÀa€3 3a€ÀÀ€@ À€¿`A0·à88``ÀÀÀÀÀÀÀ``88à``€¿A`·à88``ÀÀÀÀÀÀÀ``88àà€¿A¨·à88``ÀÀÀÀÀÀÀ``88à`À€€¿Að·à88``ÀÀÀÀÀÀÀ``88àÀp0€¿A8¸à88``ÀÀÀÀÀÀÀ``88à@€€¿A€¸ø   4 d d Ä!„!„#&&,880ðà€¿Aȸà8ÿ8àˆA¹ü000000000000000üÌÌ€¿AP¹~~f<€¿A€¹ü000000000000000ü@0 €¿A°¹ü000000000000000ü0àÀ€¿Aà¹ÿø000000@0@?À0@0@000000ÿð€€ €¿pAºÿø000000@0@?À0@0@000000ÿð À€ €¿pAXºÿø000000@0@?À0@0@000000ÿðÀÀ €¿pA ºÿø000000@0@?À0@0@000000ÿ𠀿pA躀 ÀÀÀà88``ÀÀÀÀÀÀÀ``8 <䀿À@€A0»ùÿð0`0````à€ `€€`€`€``` ` à`ÿà¨Ax»ü€0   ø 000``ÀÀ€À  ÀˆAÈ»ü€0   ø 000``ÀÀ€00ˆA ¼ü€0   ø 000``ÀÀ€àˆAx¼ü€0   ø 000``ÀÀ€`À€ˆAмü€0   ø 000``ÀÀ€Àp0ˆA0½ü€0   ø 000``ÀÀ€ À€ˆA½>cÁÃÃàp08 €¿ @0Að½ €"2 qŽˆ†ŒÂ ` 00ŒL 8A ¾0~" ûF!&!œ À @ `  0` €¿Ap¾0ÿD d$û! !„ À @ `  0` €¿A°¾ˆÌf3€€3f̈ À€¿@Að¾üxÌÌÌÌÌx €¿ÁA ¿ø  `  €¿àÀà@H¿xÌ <0€¿À@Ap¿ÀÀÀÀÀÀ@¿ 9yyùùùyy9€ €¿ @0A°¿@àÀ@@\à~ÀqÀ`À`À`À`À`À`À`À`ÀáÀ €¿ @PAø¿€`8ÀPÁA8ÀpˆŒ 0ŒL8 àÀà@XÀüD 0 ŒL8 àÀà@€Àÿðÿðÿðÿ𠀿`A¨À8D‚‚‚D8€¿ ÁAàÀüü€¿`ÁAÁð0`GÂ1€‚ €‚@€ƒà€‚0€‚€Â€B1gã0ð€¿˜A Áþþ€¿ ÀApÁ00000ÿðÿ𠀿@À`AÁ€€3fÌÌf3€€ À€¿PA¸Á~vÌÌ| Ìx ÁAèÁð0aÃGqÄ€Œ€ˆ€ˆ€ˆ€Œ€Ä€G1aã0ð€¿˜AÂÌÌ€¿`ÁA`Â8db8tâÇN<8p`F&À@@A€ÂÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ@°ÂÀàà€ € À@`0 p0ø|`AàÂÀ`îàÀ1€`À`À`À`À1€ÀîàÀ` €¿@ÀPA Ã瀾Àx@000000ü00001€€ €¿@APÃ@@>p€ÐÈÈÈÄÄC€c€ €¿@@AÃÀÀÀÀÀÀÀÀÀÀÀÀÀÀ€À @AÈÃÀ@øÃƒ€ÇÀ|`8 €¿ ÀPAÄà0  0à€¿ @ A8ÄÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ@hÄ 0 À 0 €¿ @ A˜ÄÿÃap08†Ãÿ €¿ AÈÄàð 10€0€`€`Àñà  @0AðÄñà`À!€3€ 91€`Àñà €¿PA0Å88(dd1d0Â0Â`Â`Ãñç€ ˆA`Å10€0€`€`Àñà 0A Åà>ÀqÀ`À`À`À`À`À`À`À`ÀáÀ €¿PAÐÅ2000000000þp0à@ÆøÆƒ|pàÂf> €¿ A(Æð````````vnæ €¿APÆÀ€€€€€s€a€Á€Á€Á€Á€Á€Á€a€s€€ €¿ @@AxÆð````ns€a€`À`À`À`À`À`Àa€s€î €¿ @@A¸Æs€a€ÀÀÀÀÀÀÀÀÀÀÀÀa€s€ €¿@AøÆñà`À`À`À`À`À`À`À`ÀqÀo€ç €¿PA(ÇñãÀ`Á€`Á€`Á€`Á€`Á€`Á€`Á€`Á€qã€oŸç €¿ AXÇð```````````````à€¿À@˜ÇóàaÀc€gnlxhdfcgÀ````à €¿@AÈÇÀà00000000000000p00 @À@Èð``````````à``€¿À@8Èñà`À`À`À`À`À`À`À`ÀqÀo€g````à €¿PAhÈ?ñÀÀ`À ``?À`0>3a€a€a€a€3À €¿ @@A¨Èx0000000000þ000à@èÈp€àÀÀÀÿ€Á€A€c €¿0AÉÀs€a€Á€Á€Á€Á€Á€Á€a€s€€€€€€€ €¿@AHÉp€àÀÀÀÀÀA€c€ €¿0AˆÉ^s€a€`À`À`À`À`À`Àa€s€n````à €¿@A¸Éq€ûÇÃÃc;cg> €¿0AøÉ`à€À`À@Áà@(Êÿøÿø  @PAHÊ€€Á€Ac"6 €¿Á0AhÊøø€¿€@A˜Ê 00 ``@ÀÀà@ÈÊøÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀøÀ€@AøÊÿøàp08€À€À€àÀpÿ𠀿pA(Ëà€€€€€€À@` 080 ü?€AhËüÀ0€ 8pàÀÀ  ~€A¨Ëƒƒƒ€‡€F€FÀF@L@L` ,` , , 000ü~~¸AøË€€€À@`  0   00ü€ˆAHÌà00000000000000ü€¿A˜ÌÀƒƒà ÿü€¿€AØÌžñ€ÀÀ€`€``àÀ€xàÀ@À@ÀÀcÀ@ €¿PAÍü0080p0`0À1À3€?À0p0008008000pÿÀ€¿€AXÍ8pàÀà88``ÀÀÀÀÀÀÀ``88à€¿ @A˜Íü0000000?À0p00000000pÿÀ €¿pAàÍà88``ÀÀÀÀÀÀÀ``88à€¿A Îø   4 d d Ä!„!„#&&,880ð€¿A`Îø!ø `` `` Ð` Ð`!ˆ`!ˆ`#`#`&`&`,`,`8`8`0àðø€¿°A Îÿø000000000000000ü €¿`AðÎü00080p0à1À3€?>31€0À0`000ü~€¿ˆA0ÏxÌÆ€ €¿0ApÏü000000000000000ü€¿A°Ïü€0000000?þ0000000ü€€¿˜AàÏà88` ` À À À?ÀÀÀÀ``8 <䀿A0Ðü000000 0 ?à0 0 000000ÿ𠀿`ApÐÿø000000@0@?À0@0@000000ÿ𠀿pA°ÐÿÀ0p080 0 00000000 0 080pÿÀ€¿ˆAðÐà88``ÀÀÀÀÀÀÀ``8 <䀿€A0Ñÿà0x00 0 0 008?à0@00000000pÿÀ€¿€ApÑü€0   ø 000``ÀÀ€ˆA°Ñð 0aÞc{Æ9€Æ€ÆÀÆ@Æ @à @ÃŒ@áü@`ìÀp€8€øÀ@@°AÒ00 ÃÃÆ|À0AXÒÀpÀ`ÀpÀ €¿€¿PAˆÒÿðÿðÿðÿ𠀿€À`A¸Ò`ÀpÀpÀ` €¿€¿PAàÒÀ` àÀÀÀÀ@@à@ÓÀÀÀÀ ÀÀ@8Óð€€€sÀaÀÀÀÀÀÀÀÀÀÁÀa€w€ €¿@A`Ós€á€ÀÀÀÀÀÀAÀa€73a€a€a€3 €¿@A Ó €€ÀÀÿÀÀ €¿@AàÓ{€a€àÀÀÀÀÀÀÀÀÀÁ€ó€î`p0À €¿@A Ô~ã€Á€ÀÀÀÀÀ€€~x` €À €¿@A`ÔÿÀÿÀÃCc#3  €¿@A ÔxæÃ€€€€ ƒƒG~ €¿@AàÔÿ€ÿÀ`@0 €€€€C€ €¿@A ÕÿxÀ@A`Õ3a€a€áÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀa€a€3 €¿@AÕÀÀÀ`` 00 €?@@à@ÐÕÀÀÀÀ@Öÿðÿ𠀿ÀÀ`A ÖÀ` àÀÀ@@à@@Öÿðÿ𠀿€¿`A`ÖÉ€ë€ë€É€ ÀÁ@AÖ€@ 0 0 @€€¿ @AÀÖ0 ``ÀÀÀÀÀÀÀÀ`` 0€¿ @AðÖÀ` àÀ@À@ÁA ×<<~ááÀÀÁÀÁ c 7>€À@@ À€€¿A@×0<r a`€`€0€€xÀä@Â`Á0Áa3ü €¿˜A€×?åÀÄÀ„`„``àÀ€<tdd d`4à€ @@AÈ×"""""ÿÀÿÀàà€€€€€ €¿PA؈ÌÌÌÌ€¿@Á APØÀÀÀÀÀÀÀÀÀÀÀÀÀÀ@ÀApØÀ@ Ø¨ØˆØXØ8Øø×°×h×(×ר֍ÖxÖHÖ(ÖÖèÕ¸ÕxÕHÕÕÈÔˆÔHÔÔÈÓˆÓHÓ ÓøÒÈÒ ÒpÒ@ÒèјÑXÑÑØÐ˜ÐXÐÐÈϘÏXÏÏØÎˆÎHÎÎÈÍ€Í@ÍÍÀÌ€Ì0ÌàËËPËËàʰʀÊPÊ0ÊÊàÉ ÉpÉ0ÉÉÐÈÈPÈ ÈðǰǀÇ@ÇÇàÆ Æ`Æ8ÆÆèŸňÅHÅŨİĀÄPÄ ÄÄàðÃxÃ8ÃÃȘÂhÂHÂøÁÐÁ ÁxÁXÁÁèÀÈÀÀhÀ@À À࿘¿x¿X¿0¿¿ؾ˜¾X¾¾ؽx½½¸¼`¼¼°»`»»кˆº@ºø¹ȹ˜¹h¹8¹ø¸°¸h¸ ¸Ø··H··ض¶H¶¶¸µpµ0µð´°´p´0´ø³À³€³P³³в²P²²è±¸±ˆ±`± ±è°¨°h°(°ð¯¸¯ˆ¯P¯¯Ю®X®®È­ à ÀØzDÿÿÿÿ¨òÿÿÿÿóÿÿÿÿ§óÿÿÿÿÿóÿÿÿÿ©õÿÿÿÿùöÀ~PA€ÿÿGAIsProcessorFeaturePresentKERNEL32e+000__GLOBAL_HEAP_SELECTED__MSVCRT_HEAP_SELECTÿÿÿÿí(ÿÿÿÿh)ð?5Âh!¢ÚÉ>@ÿÿÿÿÿÿï˜À˜@ðEEE50P (8PX700WP `h````ppxxxx(null)(null)ÿÿÿÿà:ÿÿÿÿi;runtime error TLOSS error SING error DOMAIN error R6028 - unable to initialize heap R6027 - not enough space for lowio initialization R6026 - not enough space for stdio initialization R6025 - pure virtual function call R6024 - not enough space for _onexit/atexit table R6019 - unable to open console device R6018 - unexpected heap error R6017 - unexpected multithread lock error R6016 - not enough space for thread data abnormal program termination R6009 - not enough space for environment R6008 - not enough space for arguments R6002 - floating point not loaded Microsoft Visual C++ Runtime Library Runtime Error! Program: ...ÿÿÿÿ¯R³RÿÿÿÿcSgSÿÿÿÿ¼TÀTÿÿÿÿÃVÇVÿÿÿÿ2W6WGetLastActivePopupGetActiveWindowMessageBoxAuser32.dll1#QNAN1#INF1#IND1#SNAN_yn_y1_y0frexpfmod_hypot_cabsldexpmodffabsfloorceiltancossinsqrtatan2atanacosasintanhcoshsinhlog10logpowexpH:mm:ssdddd, MMMM dd, yyyyM/d/yyPMAMDecemberNovemberOctoberSeptemberAugustJulyJuneAprilMarchFebruaryJanuaryDecNovOctSepAugJulJunMayAprMarFebJanSaturdayFridayThursdayWednesdayTuesdayMondaySundaySatFriThuWedTueMonSunSunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDecäNçX€æŒêØ8ä’ë€Øæì ‚täpì<€ˆå^îPDë¨ê¼êÊêÜêîê‚ënëTë˜ê2ë"ëëëì*ì@ìPì ì^ìšñˆñxñhñRñ8ñ ññìðàðÎðÀð°ðžðˆð|ð¬ñLð<ð.ððððúïäïØïÀï¤ï¸ñÊñÜñæñòñ òò2òDòTò”ï†ïxïjïZï@ï4çççdðôæ*ïï ïøîàîÈî´î î’î„îxîlî0í@íPí^ílí|íŠí˜í¦í´í¾íÊíÖíæíòíîî$î<îJî"ííüìôìäìÔìÀì²ì¦ì–ì†ìzì í2é\çnçzçˆçšç|êpêdêRêªç0ê&êêêîéàéÔéÂé´é¦é˜éŠéxéféTéDéDê"éééôèàèÔè¼è¢è’è€ènè^èLè<è(èè èöçâçÆç²çœë®ë¼ëÐëâëòëÂLoadLibraryA&GetModuleHandleAQueryPerformanceFrequencyQueryPerformanceCounterKERNEL32.dll’IsWindowVisible&SetCursoršLoadCursorA©WindowFromPointüGetCursorPosýGetDCÿGetDesktopWindowÊMsgWaitForMultipleObjects•DispatchMessageA‚TranslateMessageÜPeekMessageAjShowWindowAdjustWindowRectðGetClientRect:ClientToScreen[SetWindowPosXSetWindowLongAVGetWindowLongA\GetWindowRectChangeDisplaySettingsAÅEnumDisplaySettingsAReleaseDCFGetSystemMetricsòRegisterClassAžLoadIconAŽDestroyWindowÞPostMessageAYCreateWindowExAçGetClassInfoA^SetWindowTextA|TrackPopupMenuXCreatePopupMenuDestroyMenuAppendMenuAtInsertMenuARemoveMenu„DefWindowProcA»EndPaint BeginPaint ScreenToClient7ChildWindowFromPointGetKeyStatewToAsciiGetKeyboardStateSetCaptureReleaseCaptureRSetTimer•KillTimer(SetCursorPosUSER32.dllSDeleteObjectChoosePixelFormatSwapBuffersWGetPixelFormatéSetPixelFormatTDescribePixelFormat×GdiFlush¬RealizePaletteÈSelectPalette UnrealizeObjectBCreatePalettecGetSystemPaletteEntriesçSetPaletteEntries%GetDeviceCapsGDI32.dlljoyGetDevCapsAjoyGetPosEx!joyReleaseCapture#joySetThreshold"joySetCapture˜timeGetTimeWINMM.dll*gluSphere&gluQuadricNormals%gluQuadricDrawStylegluNewQuadricgluCylindergluErrorStringGLU32.dll glBitmapËglPixelStoreipglGetIntegervaglFinish}glGetString\wglDeleteContextôglReadBufferJglDrawBufferRglEndIglVertex3fv¿glNormal3fv glBeginÓglPopAttribÐglPolygonModeØglPushAttribHglVertex3f¾glNormal3f=glTranslatef@glVertex2fÕglPopMatrix]glEvalMesh2±glMapGrid2f­glMap2fglScalefglRotatefÚglPushMatrixPglEnablenglGetErrorewglMakeCurrent`wglGetCurrentDC_wglGetCurrentContextWglViewportZwglCreateContextOPENGL32.dll™HeapAllocŸHeapFree¢HeapReAlloc}ExitProcessžTerminateProcess÷GetCurrentProcessfEnterCriticalSectionÁLeaveCriticalSectionÊGetCommandLineAtGetVersion>GetProcAddress$GetModuleFileNameA GetEnvironmentVariableAuGetVersionExAHeapDestroy›HeapCreate¿VirtualFree»VirtualAllocªInitializeCriticalSectionUDeleteCriticalSection/RtlUnwindúGetCurrentThreadId¥TlsSetValue¢TlsAlloc£TlsFreeqSetLastError¤TlsGetValueGetLastError­InterlockedDecrement°InterlockedIncrement£HeapSizeÒWideCharToMultiBytemSetHandleCountRGetStdHandleGetFileTypePGetStartupInfoAßWriteFile²FreeEnvironmentStringsA³FreeEnvironmentStringsWGetEnvironmentStringsGetEnvironmentStringsWäMultiByteToWideChar¿LCMapStringAÀLCMapStringWSGetStringTypeAVGetStringTypeW¿GetCPInfo!CompareStringA"CompareStringW¹GetACP1GetOEMCPbSetEnvironmentVariableAjSetFilePointerªFlushFileBuffers RaiseException|SetStdHandleCloseHandleóOê;>÷ww˜òtôPö É ¸ðTÐ}PRðÊ@̰ÐpÍ`ÎðÈÀ¸à·ÀÉÀº Ñ@ »°f@½à…€Q€PWh@X ipÊ…©0ŠÀÀ`À`Eà‚ðu°~Ðð}P~Ѐ@‚ƒÐŠXHpÅ€Å@¼À»Šà¼À¿à¾°‰PHЉpHÀÐϰˆ@¦P¾@¿ ƒƒÊ0ª€¾ ¨€ŠÀ€ ˜ œÀ›ÐŒÀŸ€œp‘ðœœÀœ‚`ƒ@¨ Àž`žžŸ@ŸpE‰P¨P¨€§à½`¨ ½0ð ‘Л0˜@ŒP¥0œ }÷ ÷I÷b÷÷°÷Á÷Ð÷ß÷ó÷øø&ø<øPøaøpø„ø•ø¥ø·øÆøÔøâøòøùù'ù>ùTùcùsù†ùŽù›ù§ù¸ùÆùÖùåù÷ùúú!ú5úKúbúuú†ú—úªú·úÉúÖúèúûú ûû/ûEûSûfûû‘û°ûÈû×ûêûüû üü/ü<üJü[ülüxü†ü™ü°üÀüÏüÝüëüýý*ý:ýJý_ýný†ýžý¶ýÆýØýîýþþ#þ3þHþ]þkþxþ…þ•þ¨þ»þËþàþíþúþÿ#ÿ6ÿEÿTÿhÿ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvglut32.dll__glutCreateMenuWithExit__glutCreateWindowWithExit___glutGetFCB@4__glutInitWithExit___glutSetFCB@8glutAddMenuEntryglutAddSubMenuglutAttachMenuglutBitmapCharacterglutBitmapLengthglutBitmapWidthglutButtonBoxFuncglutChangeToMenuEntryglutChangeToSubMenuglutCopyColormapglutCreateMenuglutCreateSubWindowglutCreateWindowglutDestroyMenuglutDestroyWindowglutDetachMenuglutDeviceGetglutDialsFuncglutDisplayFuncglutEnterGameModeglutEntryFuncglutEstablishOverlayglutExtensionSupportedglutForceJoystickFuncglutFullScreenglutGameModeGetglutGameModeStringglutGetglutGetColorglutGetMenuglutGetModifiersglutGetWindowglutHideOverlayglutHideWindowglutIconifyWindowglutIdleFuncglutIgnoreKeyRepeatglutInitglutInitDisplayModeglutInitDisplayStringglutInitWindowPositionglutInitWindowSizeglutJoystickFuncglutKeyboardFuncglutKeyboardUpFuncglutLayerGetglutLeaveGameModeglutMainLoopglutMenuStateFuncglutMenuStatusFuncglutMotionFuncglutMouseFuncglutOverlayDisplayFuncglutPassiveMotionFuncglutPopWindowglutPositionWindowglutPostOverlayRedisplayglutPostRedisplayglutPostWindowOverlayRedisplayglutPostWindowRedisplayglutPushWindowglutRemoveMenuItemglutRemoveOverlayglutReportErrorsglutReshapeFuncglutReshapeWindowglutSetColorglutSetCursorglutSetIconTitleglutSetKeyRepeatglutSetMenuglutSetWindowglutSetWindowTitleglutSetupVideoResizingglutShowOverlayglutShowWindowglutSolidConeglutSolidCubeglutSolidDodecahedronglutSolidIcosahedronglutSolidOctahedronglutSolidSphereglutSolidTeapotglutSolidTetrahedronglutSolidTorusglutSpaceballButtonFuncglutSpaceballMotionFuncglutSpaceballRotateFuncglutSpecialFuncglutSpecialUpFuncglutStopVideoResizingglutStrokeCharacterglutStrokeLengthglutStrokeWidthglutSwapBuffersglutTabletButtonFuncglutTabletMotionFuncglutTimerFuncglutUseLayerglutVideoPanglutVideoResizeglutVideoResizeGetglutVisibilityFuncglutWarpPointerglutWindowStatusFuncglutWireConeglutWireCubeglutWireDodecahedronglutWireIcosahedronglutWireOctahedronglutWireSphereglutWireTeapotglutWireTetrahedronglutWireToruslýŒŒ[4-misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1-misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1glutSetColor: index %d out of rangeglutSetColor: current window is RGBAglutSetColor: cannot set color of overlay transparent index %d glutGetColor: index %d out of rangeglutGetColor: current window is RGBAglutGetColor: requesting overlay transparent index %d glutCopyColormap: source colormap of window %d must be color indexglutCopyColormap: destination colormap must be color indexglutCopyColormap: window %d has no overlayout of memory.†ˆ‹ˆ†…„…„„‚ƒ‚ƒ ÿÿÿÿfailed to parse mode stringUnrecognized display string word: %s (ignoring) win32pfdslowsamplesstereosinglestencilrgbrgbarednumluminanceindexgreendoubledepthconformantbufferblueauxbufsaccaccaalpha=>?@ABCDEFGHIJKLMNOPQRSPQRSTUVWXYZ[\]^_ÍÌL>ÍÌ,@ÍÌL>B`å½ÍÌ,@B`å=ÍÌL¾ÍÌ,@ÍÌL¾ÍÌ,@33«?"@33«?w¾?¿"@w¾??33«¿"@33«¿"@¸?"@¸?{N¿"@{N?¸¿"@¸¿"@À?š™@À?= W¿š™@= W?À¿š™@À¿š™@à?ð?à?Ház¿ð?Ház?à¿ð?à¿ð?@Í̬?@)\¿Í̬?)\?ÀÍ̬?ÀÍ̬?@fff?@)\¿fff?)\?Àfff?Àfff?Àfff?@ffæ>@)\¿ffæ>)\?Àffæ>Àffæ>À?fff>À?= W¿fff>= W?À¿fff>À¿fff>À?š™>À?= W¿š™>= W?À¿š™>À¿š™>ÍÌÌ¿š™@ÍÌÌ¿š™™¾š™@À¿š™™¾@À¿@33Àš™@33Àš™™¾š™@ Àš™™¾@ À@ÍÌ,Àš™@ÍÌ,Àš™™¾š™@@Àš™™¾@@À@ÍÌ,Àffæ?ÍÌ,Àš™™¾ffæ?@Àš™™¾ffæ?@Àffæ?ÍÌ,Àš™É?ÍÌ,Àš™™¾š™É?@Àš™™¾Í̬?@ÀÍ̬? À? Àš™™¾?š™)Àš™™¾p?š™)Àp?Àš™™¾fff?33ó¿š™™¾š™?33ó¿š™?š™Ù?ff¶?š™Ù?Ãõ(¿ff¶?š™Ù?Ãõ(¿š™?š™Ù?š™?ff&@ff¶?ff&@Ãõ(¿ff¶?ffF@Ãõ(¿33S?ffF@33S?33@ff@33@€¾ff@š™@€¾š™@š™@š™@ÍÌ,@š™@ÍÌ,@€¾š™@33S@€¾š™@33S@š™@333@ff@333@€¾ff@š™a@€¾š™@š™a@š™@š™9@ff@š™9@š™¾ff@ÍÌ\@š™¾ÍÌ @ÍÌ\@ÍÌ @333@š™@333@š™¾š™@ÍÌL@š™¾š™@ÍÌL@š™@š™I@ÍÌL?š™I@ÍÌL?ff澚™I@ffæ>ÍÌL¿š™I@ÍÌL¿š™I@ff6@33³?š™@33³?9´H¿š™@9´H?33³¿š™@33³¿š™@ÍÌÌ>33#@ÍÌÌ>B`e¾33#@B`e>ÍÌ̾33#@ÍÌ̾33#@ff¦?33#@ff¦?5^:¿33#@5^:?ff¦¿33#@ff¦¿33#@ff¦?š™@ff¦?5^:¿š™@5^:?ff¦¿š™@ff¦¿š™@ff¶?ºIL¿À?š™™=ff¶?ºIL?ff¶¿À¿š™™=ff¶¿À?= W¿š™™== W?À¿š™™=€?€?€?€?-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1GLUT: Warning in %s: (unamed)GL error: %sGLUT: Fatal Error in %s: GLUT: Fatal API Usage in %s: ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿinvalid glutVideoResizeGet parameter: %dglutEstablishVideoResizing: video resizing not possible. € glutSetWindow attempted on bogus window.redisplay needed for window %d, but no display callback.The following is a new check for GLUT 3.0; update your code.failed to create OpenGL rendering context.SetPixelFormat failed during window create.pixel format with necessary capabilities not found.cannot create windows in game mode.destroying menu window not allowed while menus in useNULL display callback not allowed in GLUT 3.0; update your code.glutReshapeWindow: non-positive width or height not allowedmenu manipulation not allowed while menus in use.glutSetMenu attempted on bogus menu.Current menu has no %d item.out of memorycannot attach menus in game mode.u˜s˜Œñ£ñ£ñsincossqrt€U€U˜úeQeQeQeQeQeQ  88ÿÿÿÿÿÿÿÿðñ àÐNOOèN “ÿÿÿÿ        ! 5A CPR S WY l m pr € ‚ ƒ„ ‘)ž ¡¤ § ·Î×  š@š@ ((((( H„„„„„„„„„„‚‚‚‚‚‚ .Àÿÿ5Âh!¢ÚÉÿ?ð?  àÝÐÝÿÿÿÿ dà8à à è߼ߌßhß<ßßÜÞ¤ÞlÞDÞx4Þy$ÞzÞüÞÿÞüÿÿ5 @ÿ€ÿÿÿ À À–ÀÀŽÀÀÀ‘À’À“Àx CCC¤`‚y‚!¦ß¡¥Ÿàü@~€ü¨Á£Ú£ þ@þµÁ£Ú£ þAþ¶Ï¢ä¢å¢è¢[þ@~¡þQQÚ^Ú _ÚjÚ2ÓØÞàù1~þDâ@â<â4â,â$â!ââ ââüáôáðáìá èá àá ØáÐáÈáÀá¸á°á¨á á"œá#˜á$”á”&€D€0XGhãdã`ã\ãXãTãPãHã@ã8ã,ã ãã ããããüâøâôâðâìâèâäâàâÜâÔâÈâÀâ¸âøâ°â¨â â”âŒâ€âtâpâlâdâPâHâ.H Q Q Q Q Q Q Q Q QHðøÿÿÿÿÿÿÿ@È@ú@@œ @PÃ@$ô@€–˜@ ¼¾@¿ÉŽ4@¡íÌÎÂÓN@ ðžµp+¨­Åi@Ð]ý%åŽOëƒ@q–וC)¯ž@ù¿ D킹@¿<Õ¦ÏÿIxÂÓ@oÆàŒé€ÉGº“¨A¼…kU'9÷pà|B¼ÝŽÞùûë~ªQC¡ævãÌò)/„&D(ªø®ãÅÄúDë§Ôó÷ëáJz•ÏEeÌÇ‘¦® ã£F e u†uvÉHMXBä§“9;5¸²íSM§å]=Å];‹ž’Zÿ]¦ð¡ ÀT¥Œ7aÑý‹Z‹Ø%]‰ùÛgª•øó'¿¢È]Ý€nLÉ›— ŠR`Ä%uÍÌÍÌÌÌÌÌÌÌû?q= ×£p= ×£ø?Zd;ßO—nƒõ?ÃÓ,eâX·Ññ?Ð#„GG¬Å§î?@¦¶il¯½7†ë?3=¼BzåÕ”¿Öç?ÂýýÎa„wÌ«ä?/L[áMľ”•æÉ?’ÄS;uD;š¯?Þgº”9E­±Ï”?$#Æâ¼º;1a‹z?aUYÁ~±S|»_?×î/¾’…ûD?$?¥é9¥'ê¨*?}¬¡ä¼d|FÐÝU>c{Ì#Twƒÿ‘=‘ú:zc%C1À¬>'>7>X>`>o>y>ƒ>‹>˜>Æ>ç>î>†?Œ?ì?ò? H0W01]1n1œ1£1m2°4·4Ø5ß5N6œ6q7)9-9195999=9A99¢9Õ9S:¥:²:Ó>*?j?q?00†00”0[1¿1ë2¨3•4o5Y68789+:;\5B5g5ƒ5‹5™5³5˜6ñ6&737A7O7l7u77…7×7æ7V8z8˜8 8®8¶8¿8ä8é8ô8ú89959T9b9l99¨9À9*:3:^:d:~:”:®:¼:Å:ÿ:; ;[;‡;Ž;;Ê;ñ;>9>T>o>,?T?‡?¬?É?P`40O0[0Ž0Ÿ0Ä0ó0I1Q1f1j1n1r1v1±1¿1Ä1É1k2r2w2‹2Ÿ2²2Æ2Ú2í233(3<3P3c3w3‹3›3¬3½3Í3Þ3ï34 44!4%4)4-4145494=4A4E4I4M4Q4U4Y4]4a4e4i4m4q4u4y4 555(595I5Z5k5{5Œ55­5¾5Ï5ß5ð5þ5 66'646B6P6^6i6z6~6‚6†6Š6Ž6’6–6š6ž6¢6¦6ª6®6²6¶6º6¾6Â6Æ6Ê6Î6Ò6Ö6U7_7o77„77–7¡7°7À7Õ7â7è7ò78 88#828h8o8}8­8»8ß8þ89929\9“9³9Ð9ì9:*:I:®:ü:Ý;Œ==”=˜=œ= =¤=Ö=ù=(>_>©>¶>ú>:?A?`\V0]0d0ý0Ž1'2À2n3r3v3z3~3‚3ä3è3ì3ð3ô30474N4N6R6V6Z6^6¸6À6Î6Ö6ß6ø67 777+747C7R7Z7h7x7ø7,848E8T8]8z8ƒ8 8¨8Å8Î8ê8ù8ý899 9 99\9‘9˜9»9Â9Ç9Ñ9Û9å9ï9 :::@:G:Q:h:“:œ:³:Á:ì:õ: ;;;2;<;S;`;w;|;;™;°;½;Ô;Ù;ì;ö; <<1<6>>$>;>H>_>d>w>>˜>¥>¼>Á>Ô>Þ>õ>???1?;?R?_?v?{?Ž?˜?¯?¼?Ó?Ø?ë?õ?p 00?0J0r0§0¬0¿0É0à0í011!1+121F1L1`1n1u1z1—1ž1¥182B2M2c2g2k2o2s2w2{22ƒ2‡2‹22“2—2›2Ÿ2£2§2«2¯2³2·2»2¿2Ã2Ç2Ë2Ï2Ó2×2£3§3«3¯3³3·3›4¤4²4¶4Ð4Û4å4÷4 55!575A5K5X5f5v5{5ƒ5ˆ5Ž5˜5¢5µ5¿5Í5Ú5â5 66A6O6Y6_6p6v6~6¡6¾6Ê6Õ6ç67 7717>7G7£7½7Ä7Õ7ü78n8u8†8­8¶89"9+999[9c9¿9Ï9Ø9æ9::•:º:Â:O;t;}; <<•<®<´<º<Ü<å<ö<==,=2=9=×=÷=>>>#>,>4>=>W>`>u>}>ƒ>Œ>”>>·>Ô>Þ>ö>? ???)?k?}?Ž?œ?§?®?µ?¼?Ã?Ê?ß?ì?ó?ú?€`000"0&0*0.02060:0>0B0F0J0N0R0V0Z0f0n0v0‚0‡00–0Ÿ0º0¿0á0ó0ý011(171F1T1Y1i1‡1®1Þ1ø12"2K2x2›2È2ä23H3k3˜3¸3Å3444y4×4í4÷45565L5a5¤5±5è5ì5ñ5$6Z6i6x6•6Æ67.7p7{7˜7Í7×7Ý7ã7í7ô7"8+8”8·8À89Œ9¹9Ý9:::4:?:Q:^:d:„::¡:®:´:ø:>;D;\;o;{;“;©;Ç;Ò;è;<#<'<+;>[>y>™>·>ò>þ>???+?9?E?S?_?m?s?ª?º?ä?û?<0a0Ë0ñ0171B1µ1¾1è2ó2ù23333$3/353I3W3]3i3r3x3…3‹3•3Ÿ3©3³3½3Ç3Ñ3Û3å3ï3ù34 44!4+454?4I4S4]4g4q4}4†4Œ4™4¤4ª4¹4Á4Ç4Ö4á4ç4ö4ü4 555)5/5<5D5J5W5b5h5w5€5†5•5 5Ä5Ê5ß5å5ú56660666K6Q6~6ˆ6“6š6¦6­6¹6À6Ë6Ò6Þ6å6ë6´7À7Ý7a8f8‚;Œ;–; ;ª;°;<>,>G>Q>D?S?W?_?s?€?”?£?§?¯?ñ?ü? ø000#070=0P0c0v0…0D1u1œ1Í12X2‰2¿2333i3À3ø34A4]4s4›4±4â4ø4 565A5G5Þ5ç5ó5ü566*6F6^6~6‡6“6œ6¡6¶6Ê6Ú6å677#7,717F7Z7¢7§7®7µ7¼7Ã7Ê7Ú7ï7ó7÷7û7ÿ788 888$8u88¦8®8¼8Ç8×8÷899#9,919;9L9c9k9p9•99º9À9É9Ò9ß9í9÷9:::?:F:Y:k:(<85>Z>k>u>‰>¾>È>å>ï>þ> ??)?E?[?h?w?†?”?¢?Å?Ï?ß?í?û?ÀX00/0=0K0e0o00•0Ÿ0±0Å0Ï0á0õ0ü0C1Ï2Ó2×2Û2ß2ã2ç2ë2ï2ó2÷2û2ÿ233 33 3˜4Ÿ4Å4Ì4%5)5-5155595=5A5E5I5M5Q5U5Y5]5a5e5w5‡5—5¤5³5¹5Â5Ñ5à5ô5ý5666*6;6E6T6§6°6¶6À6ë67,7E7“7Þ7í7808‹8™8Û8å8ø89999'989>9F9T9Z9g9„9‘9§9×9ì9õ9>:I:u:}:Ÿ:¦:¹:Ë:ö:;';F;R;];i;ª;á;ê;ó;<.>&>H>i>v>‚>ë>&?/?8?j?t??š?¼?Ø?å?ñ?ü?ÐÔ0%0E0O0•0´0º0Á0Ñ0â0î0ú011%161C1O1Z1|1Š1²1¸1â162;2B2I2P2W2^2e2l2s2z2Œ22”2˜2œ2 2¤2¨2¬23¤3«3ø3ÿ3#4*4µ4¼48š8ž8¢8¦8ª8®8²8¶8º8Î8Ò8Ö8Ú8Þ8â8È9Ì9Ð9Ô9Ø9Ü9Ò:Ö:; ;-;h;u;Ÿ;­;/<¼<­=µ=Ê=Ô=â=ñ=W>_>p>Á>Ì>í>ù>y?Š?”?àØ‹0µ0Ã0Õ0/1L1i1¢1¾1$2+2Ï2Ó2×2Û2ß2ã2ç2ë2ï2ó2÷2û2ÿ233 333333#3Ç3ß3í3ó34]44¹4å4w5„5’5 5À5Ü56w6B7^7x7…7“77«7Õ7N8g8t8Ë8ñ8 9'9e9l9Õ9Ü9:":):0:¾:Å:»;Ö;Ý;â;é;f>D>ðØj1p1v1|1‚1ˆ1—1¥1«1¯1´1º1¾1Ä1È1Î1Ò1×12G2L2e2s2Í2$3*3C3H3l3 44,414t4¬45 5q5w5‹56‚6ˆ6Ã6É6â6#7)737*8B8ç8þ89)9[:f:k:u:z:Ã:Ï:Ö:æ:ì:ó:ý:;;#;/;4;Q;W;ä<ï<ö<='=-=2=>=J=z=ˆ=‘=–=+>4>A>R>Þ>ì>þ> ?6?A?S?Ž?œ?®?¹?æ?ñ?ì0P0b0¢0­0¿01§1µ1Ã1Î1â1è1ö1ÿ12,2;2M2V2r2•2Ÿ2¨2Ä2ç2É3Ð3ß3ç3ò3ø3þ34 4%4/4I4W4_4e4¨4º4515@5\5}5†5¡5´5º5Ã5Ê5ó566<6Œ6‡7“7·8:):k:š: :Ù:;¥;¬;»;Þ;ä;ð;<<<<;´>¼>Ä>Ì>Ø>Ý>é>ñ>ù>???'?/?7?J?R??š?ª?°?Ä? ð0n0ˆ0‘0È1à1ç1ï1ô1ø1ü1%2K2e2l2p2t2x2|2€2„2ˆ2Ò2Ø2Ü2à2ä2J3U3p3w3|3€3„3¡3Ë3ý344 44444 4j4p4t4x4|4Í4Õ4ï4õ455+515>5N5T5\5z5€5‘5¨5²5Ë5-6E6K6`6m6’6Û6ö6þ67 7K7}7‘7¥7æ7%848Œ8‘8ª8K9Q9ƒ9—9A:P:Ù:@;è;\<»<¼=Ì=Ý=å=õ=>µ>½>?$??›?¦?µ?¿?0¬~00£0Ó12—3Þ3ÿ34‹4S7W7[7_7c7g7k7o7`8f8ˆ8œ8Î8Õ8ê89&9G9\9€9ª9¸9é9ï9ü9:B:R:W:¤:²:õ:>;D;R;š;¢;Ë;Ø;Ý;ê;ö;°<·<Ð<=$=z==‡=Œ=”=™=¾=Ã=B>G>d>j>É>??"?H?U?c?n??¨?·?ù?@˜ 0+070S0h0~0…0‘0 0Ò0â0%111;1O1]1j1o1u1Ð1×12d2G3`3•33·3Ã3Ó34b4u4³456P6X6^6d6¥6Ý6ï67>7Ñ:ç:h>€>‡>>”>˜>œ>Å>ë>? ????? ?$?(?r?x?|?€?„?ê?õ?P(000 0$0A0k00¤0¨0¬0°0´0¸0¼0À0 11111¥1ª1É1Ö1ã1í1÷1ÿ1 2+2H2`2€2Ø2î2!3‰3®3É3Î3ê3ý3444.4?4R4j4Š4à4ò45565A5L5V5^5i5w5¬5Ç5Þ56—6ò6W7o7Ñ7í7ú788#8/8a8s8‚8£8©8Ê8Ô8ß8ä8ì8999&9.999g9s9}9ˆ9’9œ9¢9å9ï9ô9ù9þ9::Œ:’:°:Á:Ô:é:;;";2;S;_;q;;Ž;Ÿ;Ò;à;î;ý;'<1Å>Ø>O?\???°?`ˆ$0Ä01)1>1ˆ1Ð1ç1ù1222Z22‘2—2)494k4u4º4Ã4É4Õ4Ú4ä4ë4ó4ù455525E8\8§8ÿ8979g99¨9í9 :Ú:ò:$;<;€<„<ˆ<Œ<<”<˜<œ< <¤<¨<¬<^=x=‰=¦=pl#0T0÷2!4'4A4L4T4i4t4|4‘4—4Ú45$666H6r66¡6Ã6ð67>7E7k7ƒ77¨7´7Ç7F8P8l8à:ô:n;¶;¼;Ê;€¼Ü2ü23<3d3Œ3´3Ü34,4T4t4”4¼4ä4 545\5„5¬5Ô5ü5$6L6t6œ6Ä6ì6 7,7T7|7¤7Ì7ô78D8l8”8¼8ä8 949\9|9¤9Ì9ô9:D:l:”:¼:ä: ;4;\;„;¬;Ô;ü;$4>T>|>œ>¼>Ü>ü>?4>\>|>œ>¼>ä>?,?L?l?Œ?¬?Ô?ô? l0<0d0„0¤0Ä0ä01,1L1l1Œ1¬1Ô1ü12<2d2Œ2´2Ü23$3(3,3034383<3@3D3H3L3P3T3X3\3`3d3h3l3p3t3x3|3€3„3ˆ3Œ33”3˜3œ3 3¤3¨3¬3°3´3¸3¼3À3Ä3È3Ì3Ð3Ô3Ø3Ü3à3ä3è3ì3ð3ô3ø3ü3444 44444 4$4(4,4044484<4@4D4H4L4P4T4X4\4`4d4h4l4p4t4x4|4€4„4ˆ4Œ44”4˜4œ4 4¤4¨4¬4°4´4¸4¼4À4Ä4È4Ì4Ð4Ô4Ø4Ü4à4ä4è4ì4ð4ô4ø4ü4555 55555 5$5¨5¬5°5´5¸5¼5À5Ä5È5Ì5Ð5Ô5Ø5Ü5à5ä5è5ì5ð5ô5ø5ü5666 66666 6$6(6,6064686<6@6D6H6L6P6T6X6\6`6d6h6l6p6t6x6|6€6„6ˆ6Œ66”6˜6œ6 6¤6¨6¬6°6´6¸6¼6À6Ä6È6Ì6Ð6Ô6Ø6Ü6à6ä6è6ì6ð6ô6ø6ü6777 77777 7$7(747T7t7”7´7Ü78,8T8|8¤8Ì8ô89D9l9”9¼9ä9 :4:\:„:¬:Ô:ü:$;L;t;œ;¼;ä; <4<\<„<¬<Ô<ü<$=L=t=œ=Ä=ì= >4>\>„>¬>Ô>ü>$?L?t?œ?Ä?ì?°ä0<0d0Œ0´0Ü01,1T1|1¤1Ì1ô12D2d2„2¤2Ä2ä2 343T3t3”3¼3Ü3ü3$4D4d4„4¤4Ì4ì45<5d5„5¬5Ì5ô56<6d6Œ6¬6Ô6ô6747T7|7œ7¼7ä7 8,8L8l8”8¼8ä8 949\9„9¤9Ì9ì9:4:T:t:”:¼:ä: ;4;\;„;¬;Ô;ü;$,>T>|>¤>Ì>ô>?D?l?”?´?Ü?Àp0$0L0t0œ0Ä0ì01<1d1Œ1´1Ü1ü12<2\2|2¤2Ì2ì23<3d3„3¤3Ì3ì3444T4|4¤4Ì4ô4$5L5t5”5´5Ô5ô56L6t6”6´6Ü67,7L7l7”7¼7ä7 848T8X8\8`8d8h8l8p8t8x8|8€8„8ˆ8Œ88”8˜8œ8 8¤8¨8¬8°8´8¸8¼8À8Ä8È8Ì8Ð8Ô8Ø8Ü8à8ä8è8ì8ð8ô8ø8ü8999 99999 9$9(9,9094989<9@9D9H9L9P9T9X9\9`9d9h9l9p9t9x9|9€9„9ˆ9Œ99”9˜9œ9 9¤9¨9¬9°9´9¸9¼9À9Ä9È9Ì9Ð9Ô9Ø9Ü9à9ä9è9ì9ð9ô9ø9ü9::: ::::: :$:(:,:0:4:8:<:@:D:H:L:P:T:Ø:Ü:à:ä:è:ì:ð:ô:ø:ü:;;; ;;;;; ;$;(;,;0;4;8;<;@;D;H;L;P;T;X;\;`;d;h;l;p;t;x;|;€;„;ˆ;Œ;;”;˜;œ; ;¤;¨;¬;°;´;¸;¼;À;Ä;È;Ì;Ð;Ô;Ø;Ü;à;ä;è;ì;ð;ô;ø;ü;<<< <<<<< <$<(<,<0<4<8<<<@D>l>”>¼>ä>?,?T?|?œ?Ä?ì?Ðô040T0|0œ0Ä0ì01<1\1|1¤1Ì1ô12D2l2Œ2´2Ü23,3T3|3œ3Ä3ì34<4d4Œ4´4Ü45,5T5|5¤5Ì5ô56<6d6„6¬6Ì6ì6 7,7L7t7”7´7Ô7ô7848T8t8”8´8Ô8ô8949\9„9¤9Ä9ä9:$:D:d:Œ:´:Ü:ü:;<;\;|;œ;¼;Ü;ü;<<<\<|<œ<¼<Ü<=$=D=d=„=¤=Ä=ä=>$>D>d>„>¬>Ì>ô>?4?T?|?œ?¼?Ü?ü?à<0D0d0„0¤0Ä0ä01$1D1d1„1¤1Ä1ä12$2D2t2”2´2Ô2ô2343T3t3”3´3Ô3ô3444T4t4”4´4Ô4ô4545\5„5¤5Ä5ä5 6,6L6l6Œ66”6˜6œ6 6¤6¨6¬6°6´6¸6¼6À6Ä6È6Ì6Ð6Ô6Ø6Ü6à6ä6è6ì6ð6ô6ø6ü6777 77777 7$7(7,7074787<7@7D7H7L7P7T7X7\7`7d7h7l7p7t7x7|7€7„7ˆ7Œ77”7˜7œ7 7¤7¨7¬7°7´7¸7¼7À7Ä7È7Ì7Ð7Ô7Ø7Ü7à7ä7è7ì7ð7ô7ø7ü78888”8˜8œ8 8¤8¨8¬8°8´8¸8¼8À8Ä8È8Ì8Ð8Ô8Ø8Ü8à8ä8è8ì8ð8ô8ø8ü8999 99999 9$9(9,9094989<9@9D9H9L9P9T9X9\9`9d9h9l9p9t9x9|9€9„9ˆ9Œ99”9˜9œ9 9¤9¨9¬9°9´9¸9¼9À9Ä9È9Ì9Ð9Ô9Ø9Ü9à9ä9è9ì9ð9ô9ø9ü9::: :::D:l:”:¼:ä: ;4;T;t;œ;Ä;ì;<<D>l>”>¼>ä> ?4?\?„?¬?Ô?ü?ðà$0T0t0œ0Ä0ì01<1d1Œ1´1Ü12,2T2|2¤2Ì2ô2$3L3t3œ3Ä3ì34<4l4œ4Ì4ì4 5,5L5l5”5¼5Ü5ü56<6\6|6¬6Ì6ì6 7,7\7|7¤7Ì7ô78<8d8Œ8¬8Ì8ô89D9d9Œ9¬9Ô9ô9:<:\:|:¤:Ì:ì: ;,;T;|;¤;Ì;ô;D>t>œ>Ä>ì>?<>d>Œ>´>ä> ?4?\?„?¬?Ô?ü?°40t0´0ô041t1¬1Ü12\2œ2Ü23\3”3Ä3ô3$4T4”4Ô45T5”5Ì5 6L6Œ6Ì6 7L7t7¬7ä78<8\8|8œ8¼8ì8949T9t9œ9¼9Ü9:4:\:|:œ:Ô:ô:$;T;|;œ;Ô;ü;$<>d>œ>Ô>?,?\?„?¬?Ü? ¼0,0d0Œ0´0ì01L1t1”1´1Ô12,2\2”2Ì23<3t3¬3ä34T4Œ4Ä4ü445l5”5Ì5ô56T6Œ6Ä6ü647l7¤7Ü78D8l8Œ8´8Ü89,9T9|9¤9Ì9:,:T:|:¤:Ì:ì: ;,;T;t;¤;Ô;ô;,>> >>>>> >$>(>,>0>4>8><>@>D>H>L>P>T>X>\>`>d>h>l>p>t>x>|>€>„>ˆ>Œ>>”>˜>œ> >¤>¨>¬>°>´>¸>@?D?H?L?P?T?X?\?`?d?h?l?p?t?x?|?€?„?ˆ?Œ??”?˜?œ? ?¤?¨?¬?°?´?¸?¼?À?Ä?È?Ì?Ð?Ô?Ø?Ü?à?ä?è?ì?ð?ô?ø?ü?0à000 00000 0$0(0,0004080<0@0D0H0L0P0T0X0\0`0d0h0l0p0t0x0|0€0„0ˆ0Œ00”0˜0œ0 0¤0¨0¬0°0´0¸0¼0À0Ì011D1L1”1œ1¤1¬1t2|2„2t3|3„3œ4´4 5d5œ5¤5¬5Ô5Ü5$6<6l6„67<7´748d8l8ü8¼9ä9ì9Ü:œ;ô;ü;lt>¬>´>¼>l?t?|?@Ä0Œ0”0Ü0ä0ì0ô0,141<1ì1ô1,242<2T2¬2ä2ì2ô23$3l3t3|3„3¼3Ä3Ì3|4ä4ì4¬5´5,646<6ä6 77l7”7œ7ä7ì7ô7ü7$8,8\8d8œ8¤8¬8ô8ü89 9$9l9t9|9„9¬9´9ä9::¤:¬:4;<;´;<,>l>t>Ì>Ô> ???4?¼?Ä?Ì?P0$0´0<1D1Ì1Ô122¬2ì2ô2D3L3t3|3Ä3Ì3Ô3Ü34 4T4\4”4œ4¤4Ô5Ü5ä5ü5,747<7ô7ü7œ8¤8¼:Ì:Ü:ì:ü: ;;,;<;L;\;l;|;Œ;œ;¬;¼;Ì;Ü;ì;ü; <<,<<>,><>L>\>l>|>Œ>œ>¬>¼>Ì>Ü>ì>ü> ??,?D>|>„>Œ>D>œ>¤>Ü>ä>ì>?Œ?”?œ?ì?ô?€„0 11œ1¤1ä1ì1|2¼2Ä233D3L3”3œ3¤3¬3Ô3Ü3$4,4d4l4t4¤5¬5´5Ì5ü67 7Ä7Ì7l8t8Œ:œ:¬:¼:Ì:Ü:ì:ü: ;;,;<;L;\;l;|;Œ;œ;¬;¼;Ì;Ü;ì;ü; <<,<<>,><>L>\>l>|>Œ>œ>¬>¼>Ì>Ü>ì>ü> ??,?,>T>t>”>´>Ô>ô>?4?T?t?”?´?Ô?ô? 8040T0|0œ0¼0Ü0ü01<1\1|1œ1¼1Ü1ü1$2D2l2Œ2¬2Ì2ô2343T3t3”3¼3Ü3ü34D4d4„4¤4Ä4ä45$5D5d5„5¤5Ä5ì5 6,6L6l6Œ6¬6Ì6ì6 7,7L7l7Œ7¬7Ì7ì7 8,8L8l8Œ8¬8Ô8ü89<9\9„9¤9Ä9ä9:: ::::: :$:(:,:0:4:8:<:@:D:H:L:P:T:X:\:`:d:h:l:p:t:x:|:€:„:ˆ:Œ::”:˜:œ: :¤:¨:¬:°:´:¸:¼:À:Ä:È:Ì:Ð:Ô:Ø:Ü:à:ä:è:ì:ð:ô:ø:ü:;;; ;;;;; ;$;(;,;0;4;8;<;@;D;H;L;P;T;X;\;`;d;h;l;p;t;x;|;€;< <<<<< <$<(<,<0<4<8<<<@l>¤>ä>$?d?œ?Ì?°Œ0<0|0¼0ü041t1œ1Ì1ü1,2d2¤2ä2$3d3”3Ô3 4D4„4Ä45D5„5Ì56\6¤6ì6,7\7¤7ì748|8Ä8 9L9|9¬9Ü9 :T:œ:ä:,;t;Ä;l>¬>ì>?D?l?Œ?¬?ô?À 40T0|0¤0Ü0ü01l1Œ1´1ä1 2\2|2¬2Ü23L3Œ3Ä3ô3444d4”4Ä4ì4,5\5œ5Ì5ü5$6L6t6´6ô6$7T7”7Ä7848d8¤8ä89D9„9´9ô9$:D:d:”:Ä:ô:$;d;¤;ô;D<”<Ô<=T=”=Ü=>\>œ>ì>,?l?¬?Ü?Ðð,0l0¬0ì0,1l1¬1ü1T2„2´2Ü2 343\3œ3Ü34\4œ4Ü45\5Œ5Ì5ü56<6\6Œ6¼6ì67<7|7Ä7 8L8l8œ8¼8À8Ä8È8Ì8Ð8Ô8Ø8Ü8à8ä8è8ì8ð8ô8ø8ü8999 99999 9$9(9,9094989<9@9D9H9L9P9T9X9\9`9d9h9l9p9t9x9|9€9„9ˆ9Œ99”9˜9œ9 9¤9¨9¬9°9´9¸9¼9À9Ä9È9Ì9Ð9Ô9Ø9Ü9à9ä9è9ì9ð9ô9ø9ü9::: ::::: :$:(:,:0:4:8:À:Ä:È:Ì:Ð:Ô:Ø:Ü:à:ä:è:ì:ð:ô:ø:ü:;;; ;;;;; ;$;(;,;0;4;8;<;@;D;H;L;P;T;X;\;`;d;h;l;p;t;x;|;€;„;ˆ;Œ;;”;˜;œ; ;¤;¨;¬;°;´;¸;¼;À;Ä;È;Ì;Ð;Ô;Ø;Ü;à;ä;è;ì;ð;ô;ø;ü;<<< <<<<< <$<(<,<0<4<8<<<@>> >>>> >$>(>,>0@>L>l>|>Œ>@Ü0”0à2ä233$3,343<3D3L3T3\3d3l3t3|3„3Œ3”3œ3d6l6t6|6„6Œ6”6œ6¤6¬6´6¼6Ä6Ì6Ô6Ü6ä6ì6ô6ü67 777$7,747T7X7\7`7d7h7l7p7t7x7|7€7„7ˆ7Œ77”7˜7œ7 7¤7¨7¬7°7´7¸7¼7À7Ä7È7Ì7Ð7Ô7Ø7Ü7à7ä7è7ì7ð7ô7ø7ü788888 8$8(8,80848@8À;Ä;Chipmunk-6.1.5/msvc/glut/lib/glut32.lib000644 000765 000000 00000070070 12151675775 020551 0ustar00slembckewheel000000 000000 ! / 1005211635 0 6674 ` ñ6‚9Š:À>N>N>¾>¾?,?,?š?š@ @ @|@|@ê@êAZAZAÐAÐBDBDB´B´<<C"C"C–C–<Š<ŠDDDtDtDäDäERERE¾E¾F*F*F˜F˜GGGtGtGèGèH^H^HÒHÒI@I@I®I®J J J†J†JòJòK\K\KÌKÌL8L8L¦L¦MMM„M„MðMðNbNb=p=pNÊNÊO<O<O°O°P&P&P˜P˜QQQxQxQêQêRVRVRÆRÆS2S2S¢S¢TTT‚T‚TîTîUdUdUØUØVDVDV¶V¶W.W.WžWžXXX’X’YYYrYrYâYâZRZRZÀZÀ[0[0[œ[œ\\\x\x\è\è]R]R]¾]¾^0^0^¦^¦___‚_‚_ð_ð`\`\`Ð`ÐaDaDa¶a¶b&b&b”b”cccvcvcìcìdbdbdØdØeFeFe¶e¶f*f*fœfœg g gzgzgègèh\h\hÐhÐi>i>iªiªjjj†j†jøjøkjkjkØkØlLlLl¸l¸m$m$m˜m˜n n n|n|nênêoXoXoÊoÊ=â=â==__IMPORT_DESCRIPTOR_glut32__NULL_IMPORT_DESCRIPTORglut32_NULL_THUNK_DATA__imp__glutAddMenuEntry@8_glutAddMenuEntry@8__imp__glutAddSubMenu@8_glutAddSubMenu@8__imp__glutAttachMenu@4_glutAttachMenu@4__imp__glutBitmapCharacter@8_glutBitmapCharacter@8__imp__glutBitmapLength@8_glutBitmapLength@8__imp__glutBitmapWidth@8_glutBitmapWidth@8__imp__glutButtonBoxFunc@4_glutButtonBoxFunc@4__imp__glutChangeToMenuEntry@12_glutChangeToMenuEntry@12__imp__glutChangeToSubMenu@12_glutChangeToSubMenu@12__imp__glutCopyColormap@4_glutCopyColormap@4__imp__glutCreateMenu@4_glutCreateMenu@4___glutCreateMenuWithExit@8__imp____glutCreateMenuWithExit@8__imp__glutCreateSubWindow@20_glutCreateSubWindow@20__imp__glutCreateWindow@4_glutCreateWindow@4___glutCreateWindowWithExit@8__imp____glutCreateWindowWithExit@8__imp__glutDestroyMenu@4_glutDestroyMenu@4__imp__glutDestroyWindow@4_glutDestroyWindow@4__imp__glutDetachMenu@4_glutDetachMenu@4__imp__glutDeviceGet@4_glutDeviceGet@4__imp__glutDialsFunc@4_glutDialsFunc@4__imp__glutDisplayFunc@4_glutDisplayFunc@4__imp__glutEnterGameMode@0_glutEnterGameMode@0__imp__glutEntryFunc@4_glutEntryFunc@4__imp__glutEstablishOverlay@0_glutEstablishOverlay@0__imp__glutExtensionSupported@4_glutExtensionSupported@4__imp__glutForceJoystickFunc@0_glutForceJoystickFunc@0__imp__glutFullScreen@0_glutFullScreen@0__imp__glutGameModeGet@4_glutGameModeGet@4__imp__glutGameModeString@4_glutGameModeString@4__imp__glutGet@4_glutGet@4__imp__glutGetColor@8_glutGetColor@8__imp__glutGetMenu@0_glutGetMenu@0__imp__glutGetModifiers@0_glutGetModifiers@0__imp__glutGetWindow@0_glutGetWindow@0__imp__glutHideOverlay@0_glutHideOverlay@0__imp__glutHideWindow@0_glutHideWindow@0__imp__glutIconifyWindow@0_glutIconifyWindow@0__imp__glutIdleFunc@4_glutIdleFunc@4__imp__glutIgnoreKeyRepeat@4_glutIgnoreKeyRepeat@4__imp__glutInit@8_glutInit@8___glutInitWithExit@12__imp____glutInitWithExit@12__imp__glutInitDisplayMode@4_glutInitDisplayMode@4__imp__glutInitDisplayString@4_glutInitDisplayString@4__imp__glutInitWindowPosition@8_glutInitWindowPosition@8__imp__glutInitWindowSize@8_glutInitWindowSize@8__imp__glutJoystickFunc@8_glutJoystickFunc@8__imp__glutKeyboardFunc@4_glutKeyboardFunc@4__imp__glutKeyboardUpFunc@4_glutKeyboardUpFunc@4__imp__glutLayerGet@4_glutLayerGet@4__imp__glutLeaveGameMode@0_glutLeaveGameMode@0__imp__glutMainLoop@0_glutMainLoop@0__imp__glutMenuStateFunc@4_glutMenuStateFunc@4__imp__glutMenuStatusFunc@4_glutMenuStatusFunc@4__imp__glutMotionFunc@4_glutMotionFunc@4__imp__glutMouseFunc@4_glutMouseFunc@4__imp__glutOverlayDisplayFunc@4_glutOverlayDisplayFunc@4__imp__glutPassiveMotionFunc@4_glutPassiveMotionFunc@4__imp__glutPopWindow@0_glutPopWindow@0__imp__glutPositionWindow@8_glutPositionWindow@8__imp__glutPostOverlayRedisplay@0_glutPostOverlayRedisplay@0__imp__glutPostRedisplay@0_glutPostRedisplay@0__imp__glutPostWindowOverlayRedisplay@4_glutPostWindowOverlayRedisplay@4__imp__glutPostWindowRedisplay@4_glutPostWindowRedisplay@4__imp__glutPushWindow@0_glutPushWindow@0__imp__glutRemoveMenuItem@4_glutRemoveMenuItem@4__imp__glutRemoveOverlay@0_glutRemoveOverlay@0__imp__glutReportErrors@0_glutReportErrors@0__imp__glutReshapeFunc@4_glutReshapeFunc@4__imp__glutReshapeWindow@8_glutReshapeWindow@8__imp__glutSetColor@16_glutSetColor@16__imp__glutSetCursor@4_glutSetCursor@4__imp__glutSetIconTitle@4_glutSetIconTitle@4__imp__glutSetKeyRepeat@4_glutSetKeyRepeat@4__imp__glutSetMenu@4_glutSetMenu@4__imp__glutSetWindow@4_glutSetWindow@4__imp__glutSetWindowTitle@4_glutSetWindowTitle@4__imp__glutSetupVideoResizing@0_glutSetupVideoResizing@0__imp__glutShowOverlay@0_glutShowOverlay@0__imp__glutShowWindow@0_glutShowWindow@0__imp__glutSolidCone@24_glutSolidCone@24__imp__glutSolidCube@8_glutSolidCube@8__imp__glutSolidDodecahedron@0_glutSolidDodecahedron@0__imp__glutSolidIcosahedron@0_glutSolidIcosahedron@0__imp__glutSolidOctahedron@0_glutSolidOctahedron@0__imp__glutSolidSphere@16_glutSolidSphere@16__imp__glutSolidTeapot@8_glutSolidTeapot@8__imp__glutSolidTetrahedron@0_glutSolidTetrahedron@0__imp__glutSolidTorus@24_glutSolidTorus@24__imp__glutSpaceballButtonFunc@4_glutSpaceballButtonFunc@4__imp__glutSpaceballMotionFunc@4_glutSpaceballMotionFunc@4__imp__glutSpaceballRotateFunc@4_glutSpaceballRotateFunc@4__imp__glutSpecialFunc@4_glutSpecialFunc@4__imp__glutSpecialUpFunc@4_glutSpecialUpFunc@4__imp__glutStopVideoResizing@0_glutStopVideoResizing@0__imp__glutStrokeCharacter@8_glutStrokeCharacter@8__imp__glutStrokeLength@8_glutStrokeLength@8__imp__glutStrokeWidth@8_glutStrokeWidth@8__imp__glutSwapBuffers@0_glutSwapBuffers@0__imp__glutTabletButtonFunc@4_glutTabletButtonFunc@4__imp__glutTabletMotionFunc@4_glutTabletMotionFunc@4__imp__glutTimerFunc@12_glutTimerFunc@12__imp__glutUseLayer@4_glutUseLayer@4__imp__glutVideoPan@16_glutVideoPan@16__imp__glutVideoResize@16_glutVideoResize@16__imp__glutVideoResizeGet@4_glutVideoResizeGet@4__imp__glutVisibilityFunc@4_glutVisibilityFunc@4__imp__glutWarpPointer@8_glutWarpPointer@8__imp__glutWindowStatusFunc@4_glutWindowStatusFunc@4__imp__glutWireCone@24_glutWireCone@24__imp__glutWireCube@8_glutWireCube@8__imp__glutWireDodecahedron@0_glutWireDodecahedron@0__imp__glutWireIcosahedron@0_glutWireIcosahedron@0__imp__glutWireOctahedron@0_glutWireOctahedron@0__imp__glutWireSphere@16_glutWireSphere@16__imp__glutWireTeapot@8_glutWireTeapot@8__imp__glutWireTetrahedron@0_glutWireTetrahedron@0__imp__glutWireTorus@24_glutWireTorus@24___glutSetFCB@8__imp____glutSetFCB@8___glutGetFCB@4__imp____glutGetFCB@4/ 1005211635 0 7152 ` ï‚6Š9À:N>¾>,?š? @|@ê@ZAÐADB´B<"C–CŠ<DtDäDRE¾E*F˜FGtGèG^HÒH@I®I J†JòJ\KÌK8L¦LM„MðMbNp=ÊNiªij†jøjjkØkLl¸l$m˜m n|nênXoÊoâ==ñŠ,‰Š,‰  !"#$%&'()*+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwx  !"#$%&'()*+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwx__IMPORT_DESCRIPTOR_glut32__NULL_IMPORT_DESCRIPTOR___glutCreateMenuWithExit@8___glutCreateWindowWithExit@8___glutGetFCB@4___glutInitWithExit@12___glutSetFCB@8__imp____glutCreateMenuWithExit@8__imp____glutCreateWindowWithExit@8__imp____glutGetFCB@4__imp____glutInitWithExit@12__imp____glutSetFCB@8__imp__glutAddMenuEntry@8__imp__glutAddSubMenu@8__imp__glutAttachMenu@4__imp__glutBitmapCharacter@8__imp__glutBitmapLength@8__imp__glutBitmapWidth@8__imp__glutButtonBoxFunc@4__imp__glutChangeToMenuEntry@12__imp__glutChangeToSubMenu@12__imp__glutCopyColormap@4__imp__glutCreateMenu@4__imp__glutCreateSubWindow@20__imp__glutCreateWindow@4__imp__glutDestroyMenu@4__imp__glutDestroyWindow@4__imp__glutDetachMenu@4__imp__glutDeviceGet@4__imp__glutDialsFunc@4__imp__glutDisplayFunc@4__imp__glutEnterGameMode@0__imp__glutEntryFunc@4__imp__glutEstablishOverlay@0__imp__glutExtensionSupported@4__imp__glutForceJoystickFunc@0__imp__glutFullScreen@0__imp__glutGameModeGet@4__imp__glutGameModeString@4__imp__glutGet@4__imp__glutGetColor@8__imp__glutGetMenu@0__imp__glutGetModifiers@0__imp__glutGetWindow@0__imp__glutHideOverlay@0__imp__glutHideWindow@0__imp__glutIconifyWindow@0__imp__glutIdleFunc@4__imp__glutIgnoreKeyRepeat@4__imp__glutInit@8__imp__glutInitDisplayMode@4__imp__glutInitDisplayString@4__imp__glutInitWindowPosition@8__imp__glutInitWindowSize@8__imp__glutJoystickFunc@8__imp__glutKeyboardFunc@4__imp__glutKeyboardUpFunc@4__imp__glutLayerGet@4__imp__glutLeaveGameMode@0__imp__glutMainLoop@0__imp__glutMenuStateFunc@4__imp__glutMenuStatusFunc@4__imp__glutMotionFunc@4__imp__glutMouseFunc@4__imp__glutOverlayDisplayFunc@4__imp__glutPassiveMotionFunc@4__imp__glutPopWindow@0__imp__glutPositionWindow@8__imp__glutPostOverlayRedisplay@0__imp__glutPostRedisplay@0__imp__glutPostWindowOverlayRedisplay@4__imp__glutPostWindowRedisplay@4__imp__glutPushWindow@0__imp__glutRemoveMenuItem@4__imp__glutRemoveOverlay@0__imp__glutReportErrors@0__imp__glutReshapeFunc@4__imp__glutReshapeWindow@8__imp__glutSetColor@16__imp__glutSetCursor@4__imp__glutSetIconTitle@4__imp__glutSetKeyRepeat@4__imp__glutSetMenu@4__imp__glutSetWindow@4__imp__glutSetWindowTitle@4__imp__glutSetupVideoResizing@0__imp__glutShowOverlay@0__imp__glutShowWindow@0__imp__glutSolidCone@24__imp__glutSolidCube@8__imp__glutSolidDodecahedron@0__imp__glutSolidIcosahedron@0__imp__glutSolidOctahedron@0__imp__glutSolidSphere@16__imp__glutSolidTeapot@8__imp__glutSolidTetrahedron@0__imp__glutSolidTorus@24__imp__glutSpaceballButtonFunc@4__imp__glutSpaceballMotionFunc@4__imp__glutSpaceballRotateFunc@4__imp__glutSpecialFunc@4__imp__glutSpecialUpFunc@4__imp__glutStopVideoResizing@0__imp__glutStrokeCharacter@8__imp__glutStrokeLength@8__imp__glutStrokeWidth@8__imp__glutSwapBuffers@0__imp__glutTabletButtonFunc@4__imp__glutTabletMotionFunc@4__imp__glutTimerFunc@12__imp__glutUseLayer@4__imp__glutVideoPan@16__imp__glutVideoResize@16__imp__glutVideoResizeGet@4__imp__glutVisibilityFunc@4__imp__glutWarpPointer@8__imp__glutWindowStatusFunc@4__imp__glutWireCone@24__imp__glutWireCube@8__imp__glutWireDodecahedron@0__imp__glutWireIcosahedron@0__imp__glutWireOctahedron@0__imp__glutWireSphere@16__imp__glutWireTeapot@8__imp__glutWireTetrahedron@0__imp__glutWireTorus@24_glutAddMenuEntry@8_glutAddSubMenu@8_glutAttachMenu@4_glutBitmapCharacter@8_glutBitmapLength@8_glutBitmapWidth@8_glutButtonBoxFunc@4_glutChangeToMenuEntry@12_glutChangeToSubMenu@12_glutCopyColormap@4_glutCreateMenu@4_glutCreateSubWindow@20_glutCreateWindow@4_glutDestroyMenu@4_glutDestroyWindow@4_glutDetachMenu@4_glutDeviceGet@4_glutDialsFunc@4_glutDisplayFunc@4_glutEnterGameMode@0_glutEntryFunc@4_glutEstablishOverlay@0_glutExtensionSupported@4_glutForceJoystickFunc@0_glutFullScreen@0_glutGameModeGet@4_glutGameModeString@4_glutGet@4_glutGetColor@8_glutGetMenu@0_glutGetModifiers@0_glutGetWindow@0_glutHideOverlay@0_glutHideWindow@0_glutIconifyWindow@0_glutIdleFunc@4_glutIgnoreKeyRepeat@4_glutInit@8_glutInitDisplayMode@4_glutInitDisplayString@4_glutInitWindowPosition@8_glutInitWindowSize@8_glutJoystickFunc@8_glutKeyboardFunc@4_glutKeyboardUpFunc@4_glutLayerGet@4_glutLeaveGameMode@0_glutMainLoop@0_glutMenuStateFunc@4_glutMenuStatusFunc@4_glutMotionFunc@4_glutMouseFunc@4_glutOverlayDisplayFunc@4_glutPassiveMotionFunc@4_glutPopWindow@0_glutPositionWindow@8_glutPostOverlayRedisplay@0_glutPostRedisplay@0_glutPostWindowOverlayRedisplay@4_glutPostWindowRedisplay@4_glutPushWindow@0_glutRemoveMenuItem@4_glutRemoveOverlay@0_glutReportErrors@0_glutReshapeFunc@4_glutReshapeWindow@8_glutSetColor@16_glutSetCursor@4_glutSetIconTitle@4_glutSetKeyRepeat@4_glutSetMenu@4_glutSetWindow@4_glutSetWindowTitle@4_glutSetupVideoResizing@0_glutShowOverlay@0_glutShowWindow@0_glutSolidCone@24_glutSolidCube@8_glutSolidDodecahedron@0_glutSolidIcosahedron@0_glutSolidOctahedron@0_glutSolidSphere@16_glutSolidTeapot@8_glutSolidTetrahedron@0_glutSolidTorus@24_glutSpaceballButtonFunc@4_glutSpaceballMotionFunc@4_glutSpaceballRotateFunc@4_glutSpecialFunc@4_glutSpecialUpFunc@4_glutStopVideoResizing@0_glutStrokeCharacter@8_glutStrokeLength@8_glutStrokeWidth@8_glutSwapBuffers@0_glutTabletButtonFunc@4_glutTabletMotionFunc@4_glutTimerFunc@12_glutUseLayer@4_glutVideoPan@16_glutVideoResize@16_glutVideoResizeGet@4_glutVisibilityFunc@4_glutWarpPointer@8_glutWindowStatusFunc@4_glutWireCone@24_glutWireCube@8_glutWireDodecahedron@0_glutWireIcosahedron@0_glutWireOctahedron@0_glutWireSphere@16_glutWireTeapot@8_glutWireTetrahedron@0_glutWireTorus@24glut32_NULL_THUNK_DATAglut32.dll/ 1005211635 0 715 ` LóOê;ëà .debug$SAl@B.idata$2­Á@0À.idata$6 ßÁ@ À glut32.dll(ÿ Microsoft (R) LINK glut32.dll@comp.idÿ ÿÿ.idata$2@Àh.idata$6.idata$4@Àh.idata$5@Àh8P__IMPORT_DESCRIPTOR_glut32__NULL_IMPORT_DESCRIPTORglut32_NULL_THUNK_DATA glut32.dll/ 1005211635 0 250 ` LóOê;¹.debug$SAd@B.idata$3¥@0À glut32.dll(ÿ Microsoft (R) LINK@comp.idÿ ÿÿ__NULL_IMPORT_DESCRIPTORglut32.dll/ 1005211635 0 277 ` LóOê;Õ.debug$SAŒ@B.idata$5Í@0À.idata$4Ñ@0À glut32.dll(ÿ Microsoft (R) LINK@comp.idÿ ÿÿglut32_NULL_THUNK_DATA glut32.dll/ 1005211635 0 59 ` ÿÿLóOê;' ___glutCreateMenuWithExit@8glut32.dll glut32.dll/ 1005211635 0 61 ` ÿÿLóOê;) ___glutCreateWindowWithExit@8glut32.dll glut32.dll/ 1005211635 0 47 ` ÿÿLóOê;___glutGetFCB@4glut32.dll glut32.dll/ 1005211635 0 54 ` ÿÿLóOê;" ___glutInitWithExit@12glut32.dllglut32.dll/ 1005211635 0 47 ` ÿÿLóOê;___glutSetFCB@8glut32.dll glut32.dll/ 1005211635 0 51 ` ÿÿLóOê; _glutAddMenuEntry@8glut32.dll glut32.dll/ 1005211635 0 49 ` ÿÿLóOê; _glutAddSubMenu@8glut32.dll glut32.dll/ 1005211635 0 49 ` ÿÿLóOê; _glutAttachMenu@4glut32.dll glut32.dll/ 1005211635 0 54 ` ÿÿLóOê;" _glutBitmapCharacter@8glut32.dllglut32.dll/ 1005211635 0 51 ` ÿÿLóOê; _glutBitmapLength@8glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê; _glutBitmapWidth@8glut32.dllglut32.dll/ 1005211635 0 52 ` ÿÿLóOê; _glutButtonBoxFunc@4glut32.dllglut32.dll/ 1005211635 0 57 ` ÿÿLóOê;% _glutChangeToMenuEntry@12glut32.dll glut32.dll/ 1005211635 0 55 ` ÿÿLóOê;# _glutChangeToSubMenu@12glut32.dll glut32.dll/ 1005211635 0 51 ` ÿÿLóOê; _glutCopyColormap@4glut32.dll glut32.dll/ 1005211635 0 49 ` ÿÿLóOê; _glutCreateMenu@4glut32.dll glut32.dll/ 1005211635 0 55 ` ÿÿLóOê;# _glutCreateSubWindow@20glut32.dll glut32.dll/ 1005211635 0 51 ` ÿÿLóOê; _glutCreateWindow@4glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê; _glutDestroyMenu@4glut32.dllglut32.dll/ 1005211635 0 52 ` ÿÿLóOê;  _glutDestroyWindow@4glut32.dllglut32.dll/ 1005211635 0 49 ` ÿÿLóOê; _glutDetachMenu@4glut32.dll glut32.dll/ 1005211635 0 48 ` ÿÿLóOê; _glutDeviceGet@4glut32.dllglut32.dll/ 1005211635 0 48 ` ÿÿLóOê; _glutDialsFunc@4glut32.dllglut32.dll/ 1005211635 0 50 ` ÿÿLóOê; _glutDisplayFunc@4glut32.dllglut32.dll/ 1005211635 0 52 ` ÿÿLóOê;  _glutEnterGameMode@0glut32.dllglut32.dll/ 1005211635 0 48 ` ÿÿLóOê; _glutEntryFunc@4glut32.dllglut32.dll/ 1005211635 0 55 ` ÿÿLóOê;# _glutEstablishOverlay@0glut32.dll glut32.dll/ 1005211635 0 57 ` ÿÿLóOê;% _glutExtensionSupported@4glut32.dll glut32.dll/ 1005211635 0 56 ` ÿÿLóOê;$ _glutForceJoystickFunc@0glut32.dllglut32.dll/ 1005211635 0 49 ` ÿÿLóOê; _glutFullScreen@0glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê; _glutGameModeGet@4glut32.dllglut32.dll/ 1005211635 0 53 ` ÿÿLóOê;! _glutGameModeString@4glut32.dll glut32.dll/ 1005211635 0 42 ` ÿÿLóOê; _glutGet@4glut32.dllglut32.dll/ 1005211635 0 47 ` ÿÿLóOê;! _glutGetColor@8glut32.dll glut32.dll/ 1005211635 0 46 ` ÿÿLóOê;" _glutGetMenu@0glut32.dllglut32.dll/ 1005211635 0 51 ` ÿÿLóOê;# _glutGetModifiers@0glut32.dll glut32.dll/ 1005211635 0 48 ` ÿÿLóOê;$ _glutGetWindow@0glut32.dllglut32.dll/ 1005211635 0 50 ` ÿÿLóOê;% _glutHideOverlay@0glut32.dllglut32.dll/ 1005211635 0 49 ` ÿÿLóOê;& _glutHideWindow@0glut32.dll glut32.dll/ 1005211635 0 52 ` ÿÿLóOê; ' _glutIconifyWindow@0glut32.dllglut32.dll/ 1005211635 0 47 ` ÿÿLóOê;( _glutIdleFunc@4glut32.dll glut32.dll/ 1005211635 0 54 ` ÿÿLóOê;") _glutIgnoreKeyRepeat@4glut32.dllglut32.dll/ 1005211635 0 43 ` ÿÿLóOê;* _glutInit@8glut32.dll glut32.dll/ 1005211635 0 54 ` ÿÿLóOê;"+ _glutInitDisplayMode@4glut32.dllglut32.dll/ 1005211635 0 56 ` ÿÿLóOê;$, _glutInitDisplayString@4glut32.dllglut32.dll/ 1005211635 0 57 ` ÿÿLóOê;%- _glutInitWindowPosition@8glut32.dll glut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!. _glutInitWindowSize@8glut32.dll glut32.dll/ 1005211635 0 51 ` ÿÿLóOê;/ _glutJoystickFunc@8glut32.dll glut32.dll/ 1005211635 0 51 ` ÿÿLóOê;0 _glutKeyboardFunc@4glut32.dll glut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!1 _glutKeyboardUpFunc@4glut32.dll glut32.dll/ 1005211635 0 47 ` ÿÿLóOê;2 _glutLayerGet@4glut32.dll glut32.dll/ 1005211635 0 52 ` ÿÿLóOê; 3 _glutLeaveGameMode@0glut32.dllglut32.dll/ 1005211635 0 47 ` ÿÿLóOê;4 _glutMainLoop@0glut32.dll glut32.dll/ 1005211635 0 52 ` ÿÿLóOê; 5 _glutMenuStateFunc@4glut32.dllglut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!6 _glutMenuStatusFunc@4glut32.dll glut32.dll/ 1005211635 0 49 ` ÿÿLóOê;7 _glutMotionFunc@4glut32.dll glut32.dll/ 1005211635 0 48 ` ÿÿLóOê;8 _glutMouseFunc@4glut32.dllglut32.dll/ 1005211635 0 57 ` ÿÿLóOê;%9 _glutOverlayDisplayFunc@4glut32.dll glut32.dll/ 1005211635 0 56 ` ÿÿLóOê;$: _glutPassiveMotionFunc@4glut32.dllglut32.dll/ 1005211635 0 48 ` ÿÿLóOê;; _glutPopWindow@0glut32.dllglut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!< _glutPositionWindow@8glut32.dll glut32.dll/ 1005211635 0 59 ` ÿÿLóOê;'= _glutPostOverlayRedisplay@0glut32.dll glut32.dll/ 1005211635 0 52 ` ÿÿLóOê; > _glutPostRedisplay@0glut32.dllglut32.dll/ 1005211635 0 65 ` ÿÿLóOê;-? _glutPostWindowOverlayRedisplay@4glut32.dll glut32.dll/ 1005211635 0 58 ` ÿÿLóOê;&@ _glutPostWindowRedisplay@4glut32.dllglut32.dll/ 1005211635 0 49 ` ÿÿLóOê;A _glutPushWindow@0glut32.dll glut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!B _glutRemoveMenuItem@4glut32.dll glut32.dll/ 1005211635 0 52 ` ÿÿLóOê; C _glutRemoveOverlay@0glut32.dllglut32.dll/ 1005211635 0 51 ` ÿÿLóOê;D _glutReportErrors@0glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê;E _glutReshapeFunc@4glut32.dllglut32.dll/ 1005211635 0 52 ` ÿÿLóOê; F _glutReshapeWindow@8glut32.dllglut32.dll/ 1005211635 0 48 ` ÿÿLóOê;G _glutSetColor@16glut32.dllglut32.dll/ 1005211635 0 48 ` ÿÿLóOê;H _glutSetCursor@4glut32.dllglut32.dll/ 1005211635 0 51 ` ÿÿLóOê;I _glutSetIconTitle@4glut32.dll glut32.dll/ 1005211635 0 51 ` ÿÿLóOê;J _glutSetKeyRepeat@4glut32.dll glut32.dll/ 1005211635 0 46 ` ÿÿLóOê;K _glutSetMenu@4glut32.dllglut32.dll/ 1005211635 0 48 ` ÿÿLóOê;L _glutSetWindow@4glut32.dllglut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!M _glutSetWindowTitle@4glut32.dll glut32.dll/ 1005211635 0 57 ` ÿÿLóOê;%N _glutSetupVideoResizing@0glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê;O _glutShowOverlay@0glut32.dllglut32.dll/ 1005211635 0 49 ` ÿÿLóOê;P _glutShowWindow@0glut32.dll glut32.dll/ 1005211635 0 49 ` ÿÿLóOê;Q _glutSolidCone@24glut32.dll glut32.dll/ 1005211635 0 48 ` ÿÿLóOê;R _glutSolidCube@8glut32.dllglut32.dll/ 1005211635 0 56 ` ÿÿLóOê;$S _glutSolidDodecahedron@0glut32.dllglut32.dll/ 1005211635 0 55 ` ÿÿLóOê;#T _glutSolidIcosahedron@0glut32.dll glut32.dll/ 1005211635 0 54 ` ÿÿLóOê;"U _glutSolidOctahedron@0glut32.dllglut32.dll/ 1005211635 0 51 ` ÿÿLóOê;V _glutSolidSphere@16glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê;W _glutSolidTeapot@8glut32.dllglut32.dll/ 1005211635 0 55 ` ÿÿLóOê;#X _glutSolidTetrahedron@0glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê;Y _glutSolidTorus@24glut32.dllglut32.dll/ 1005211635 0 58 ` ÿÿLóOê;&Z _glutSpaceballButtonFunc@4glut32.dllglut32.dll/ 1005211635 0 58 ` ÿÿLóOê;&[ _glutSpaceballMotionFunc@4glut32.dllglut32.dll/ 1005211635 0 58 ` ÿÿLóOê;&\ _glutSpaceballRotateFunc@4glut32.dllglut32.dll/ 1005211635 0 50 ` ÿÿLóOê;] _glutSpecialFunc@4glut32.dllglut32.dll/ 1005211635 0 52 ` ÿÿLóOê; ^ _glutSpecialUpFunc@4glut32.dllglut32.dll/ 1005211635 0 56 ` ÿÿLóOê;$_ _glutStopVideoResizing@0glut32.dllglut32.dll/ 1005211635 0 54 ` ÿÿLóOê;"` _glutStrokeCharacter@8glut32.dllglut32.dll/ 1005211635 0 51 ` ÿÿLóOê;a _glutStrokeLength@8glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê;b _glutStrokeWidth@8glut32.dllglut32.dll/ 1005211635 0 50 ` ÿÿLóOê;c _glutSwapBuffers@0glut32.dllglut32.dll/ 1005211635 0 55 ` ÿÿLóOê;#d _glutTabletButtonFunc@4glut32.dll glut32.dll/ 1005211635 0 55 ` ÿÿLóOê;#e _glutTabletMotionFunc@4glut32.dll glut32.dll/ 1005211635 0 49 ` ÿÿLóOê;f _glutTimerFunc@12glut32.dll glut32.dll/ 1005211635 0 47 ` ÿÿLóOê;g _glutUseLayer@4glut32.dll glut32.dll/ 1005211635 0 48 ` ÿÿLóOê;h _glutVideoPan@16glut32.dllglut32.dll/ 1005211635 0 51 ` ÿÿLóOê;i _glutVideoResize@16glut32.dll glut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!j _glutVideoResizeGet@4glut32.dll glut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!k _glutVisibilityFunc@4glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê;l _glutWarpPointer@8glut32.dllglut32.dll/ 1005211635 0 55 ` ÿÿLóOê;#m _glutWindowStatusFunc@4glut32.dll glut32.dll/ 1005211635 0 48 ` ÿÿLóOê;n _glutWireCone@24glut32.dllglut32.dll/ 1005211635 0 47 ` ÿÿLóOê;o _glutWireCube@8glut32.dll glut32.dll/ 1005211635 0 55 ` ÿÿLóOê;#p _glutWireDodecahedron@0glut32.dll glut32.dll/ 1005211635 0 54 ` ÿÿLóOê;"q _glutWireIcosahedron@0glut32.dllglut32.dll/ 1005211635 0 53 ` ÿÿLóOê;!r _glutWireOctahedron@0glut32.dll glut32.dll/ 1005211635 0 50 ` ÿÿLóOê;s _glutWireSphere@16glut32.dllglut32.dll/ 1005211635 0 49 ` ÿÿLóOê;t _glutWireTeapot@8glut32.dll glut32.dll/ 1005211635 0 54 ` ÿÿLóOê;"u _glutWireTetrahedron@0glut32.dllglut32.dll/ 1005211635 0 49 ` ÿÿLóOê;v _glutWireTorus@24glut32.dll Chipmunk-6.1.5/msvc/glut/include/GL/000755 000765 000000 00000000000 12151675775 020114 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/msvc/glut/include/GL/glut.h000644 000765 000000 00000066026 12151675775 021252 0ustar00slembckewheel000000 000000 #ifndef __glut_h__ #define __glut_h__ /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1998. */ /* This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. */ #if defined(_WIN32) /* GLUT 3.7 now tries to avoid including to avoid name space pollution, but Win32's needs APIENTRY and WINGDIAPI defined properly. */ # if 0 /* This would put tons of macros and crap in our clean name space. */ # define WIN32_LEAN_AND_MEAN # include # else /* XXX This is from Win32's */ # ifndef APIENTRY # define GLUT_APIENTRY_DEFINED # if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) || defined(__LCC__) # define APIENTRY __stdcall # else # define APIENTRY # endif # endif /* XXX This is from Win32's */ # ifndef CALLBACK # if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) || defined(__LCC__) # define CALLBACK __stdcall # else # define CALLBACK # endif # endif /* XXX Hack for lcc compiler. It doesn't support __declspec(dllimport), just __stdcall. */ # if defined( __LCC__ ) # undef WINGDIAPI # define WINGDIAPI __stdcall # else /* XXX This is from Win32's and */ # ifndef WINGDIAPI # define GLUT_WINGDIAPI_DEFINED # define WINGDIAPI __declspec(dllimport) # endif # endif /* XXX This is from Win32's */ # ifndef _WCHAR_T_DEFINED typedef unsigned short wchar_t; # define _WCHAR_T_DEFINED # endif # endif /* To disable automatic library usage for GLUT, define GLUT_NO_LIB_PRAGMA in your compile preprocessor options. */ # if !defined(GLUT_BUILDING_LIB) && !defined(GLUT_NO_LIB_PRAGMA) # pragma comment (lib, "winmm.lib") /* link with Windows MultiMedia lib */ /* To enable automatic SGI OpenGL for Windows library usage for GLUT, define GLUT_USE_SGI_OPENGL in your compile preprocessor options. */ # ifdef GLUT_USE_SGI_OPENGL # pragma comment (lib, "opengl.lib") /* link with SGI OpenGL for Windows lib */ # pragma comment (lib, "glu.lib") /* link with SGI OpenGL Utility lib */ # pragma comment (lib, "glut.lib") /* link with Win32 GLUT for SGI OpenGL lib */ # else # pragma comment (lib, "opengl32.lib") /* link with Microsoft OpenGL lib */ # pragma comment (lib, "glu32.lib") /* link with Microsoft OpenGL Utility lib */ # pragma comment (lib, "glut32.lib") /* link with Win32 GLUT lib */ # endif # endif /* To disable supression of annoying warnings about floats being promoted to doubles, define GLUT_NO_WARNING_DISABLE in your compile preprocessor options. */ # ifndef GLUT_NO_WARNING_DISABLE # pragma warning (disable:4244) /* Disable bogus VC++ 4.2 conversion warnings. */ # pragma warning (disable:4305) /* VC++ 5.0 version of above warning. */ # endif /* Win32 has an annoying issue where there are multiple C run-time libraries (CRTs). If the executable is linked with a different CRT from the GLUT DLL, the GLUT DLL will not share the same CRT static data seen by the executable. In particular, atexit callbacks registered in the executable will not be called if GLUT calls its (different) exit routine). GLUT is typically built with the "/MD" option (the CRT with multithreading DLL support), but the Visual C++ linker default is "/ML" (the single threaded CRT). One workaround to this issue is requiring users to always link with the same CRT as GLUT is compiled with. That requires users supply a non-standard option. GLUT 3.7 has its own built-in workaround where the executable's "exit" function pointer is covertly passed to GLUT. GLUT then calls the executable's exit function pointer to ensure that any "atexit" calls registered by the application are called if GLUT needs to exit. Note that the __glut*WithExit routines should NEVER be called directly. To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ /* XXX This is from Win32's */ # if !defined(_MSC_VER) && !defined(__cdecl) /* Define __cdecl for non-Microsoft compilers. */ # define __cdecl # define GLUT_DEFINED___CDECL # endif # ifndef _CRTIMP # ifdef _NTSDK /* Definition compatible with NT SDK */ # define _CRTIMP # else /* Current definition */ # ifdef _DLL # define _CRTIMP __declspec(dllimport) # else # define _CRTIMP # endif # endif # define GLUT_DEFINED__CRTIMP # endif /* GLUT API entry point declarations for Win32. */ # ifdef GLUT_BUILDING_LIB # define GLUTAPI __declspec(dllexport) # else # ifdef _DLL # define GLUTAPI __declspec(dllimport) # else # define GLUTAPI extern # endif # endif /* GLUT callback calling convention for Win32. */ # define GLUTCALLBACK __cdecl #endif /* _WIN32 */ #include #include #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) # ifndef GLUT_BUILDING_LIB extern _CRTIMP void __cdecl exit(int); # endif #else /* non-Win32 case. */ /* Define APIENTRY and CALLBACK to nothing if we aren't on Win32. */ # define APIENTRY # define GLUT_APIENTRY_DEFINED # define CALLBACK /* Define GLUTAPI and GLUTCALLBACK as below if we aren't on Win32. */ # define GLUTAPI extern # define GLUTCALLBACK /* Prototype exit for the non-Win32 case (see above). */ extern void exit(int); #endif /** GLUT API revision history: GLUT_API_VERSION is updated to reflect incompatible GLUT API changes (interface changes, semantic changes, deletions, or additions). GLUT_API_VERSION=1 First public release of GLUT. 11/29/94 GLUT_API_VERSION=2 Added support for OpenGL/GLX multisampling, extension. Supports new input devices like tablet, dial and button box, and Spaceball. Easy to query OpenGL extensions. GLUT_API_VERSION=3 glutMenuStatus added. GLUT_API_VERSION=4 glutInitDisplayString, glutWarpPointer, glutBitmapLength, glutStrokeLength, glutWindowStatusFunc, dynamic video resize subAPI, glutPostWindowRedisplay, glutKeyboardUpFunc, glutSpecialUpFunc, glutIgnoreKeyRepeat, glutSetKeyRepeat, glutJoystickFunc, glutForceJoystickFunc (NOT FINALIZED!). **/ #ifndef GLUT_API_VERSION /* allow this to be overriden */ #define GLUT_API_VERSION 3 #endif /** GLUT implementation revision history: GLUT_XLIB_IMPLEMENTATION is updated to reflect both GLUT API revisions and implementation revisions (ie, bug fixes). GLUT_XLIB_IMPLEMENTATION=1 mjk's first public release of GLUT Xlib-based implementation. 11/29/94 GLUT_XLIB_IMPLEMENTATION=2 mjk's second public release of GLUT Xlib-based implementation providing GLUT version 2 interfaces. GLUT_XLIB_IMPLEMENTATION=3 mjk's GLUT 2.2 images. 4/17/95 GLUT_XLIB_IMPLEMENTATION=4 mjk's GLUT 2.3 images. 6/?/95 GLUT_XLIB_IMPLEMENTATION=5 mjk's GLUT 3.0 images. 10/?/95 GLUT_XLIB_IMPLEMENTATION=7 mjk's GLUT 3.1+ with glutWarpPoitner. 7/24/96 GLUT_XLIB_IMPLEMENTATION=8 mjk's GLUT 3.1+ with glutWarpPoitner and video resize. 1/3/97 GLUT_XLIB_IMPLEMENTATION=9 mjk's GLUT 3.4 release with early GLUT 4 routines. GLUT_XLIB_IMPLEMENTATION=11 Mesa 2.5's GLUT 3.6 release. GLUT_XLIB_IMPLEMENTATION=12 mjk's GLUT 3.6 release with early GLUT 4 routines + signal handling. GLUT_XLIB_IMPLEMENTATION=13 mjk's GLUT 3.7 beta with GameGLUT support. GLUT_XLIB_IMPLEMENTATION=14 mjk's GLUT 3.7 beta with f90gl friend interface. GLUT_XLIB_IMPLEMENTATION=15 mjk's GLUT 3.7 beta sync'ed with Mesa **/ #ifndef GLUT_XLIB_IMPLEMENTATION /* Allow this to be overriden. */ #define GLUT_XLIB_IMPLEMENTATION 15 #endif /* Display mode bit masks. */ #define GLUT_RGB 0 #define GLUT_RGBA GLUT_RGB #define GLUT_INDEX 1 #define GLUT_SINGLE 0 #define GLUT_DOUBLE 2 #define GLUT_ACCUM 4 #define GLUT_ALPHA 8 #define GLUT_DEPTH 16 #define GLUT_STENCIL 32 #if (GLUT_API_VERSION >= 2) #define GLUT_MULTISAMPLE 128 #define GLUT_STEREO 256 #endif #if (GLUT_API_VERSION >= 3) #define GLUT_LUMINANCE 512 #endif /* Mouse buttons. */ #define GLUT_LEFT_BUTTON 0 #define GLUT_MIDDLE_BUTTON 1 #define GLUT_RIGHT_BUTTON 2 /* Mouse button state. */ #define GLUT_DOWN 0 #define GLUT_UP 1 #if (GLUT_API_VERSION >= 2) /* function keys */ #define GLUT_KEY_F1 1 #define GLUT_KEY_F2 2 #define GLUT_KEY_F3 3 #define GLUT_KEY_F4 4 #define GLUT_KEY_F5 5 #define GLUT_KEY_F6 6 #define GLUT_KEY_F7 7 #define GLUT_KEY_F8 8 #define GLUT_KEY_F9 9 #define GLUT_KEY_F10 10 #define GLUT_KEY_F11 11 #define GLUT_KEY_F12 12 /* directional keys */ #define GLUT_KEY_LEFT 100 #define GLUT_KEY_UP 101 #define GLUT_KEY_RIGHT 102 #define GLUT_KEY_DOWN 103 #define GLUT_KEY_PAGE_UP 104 #define GLUT_KEY_PAGE_DOWN 105 #define GLUT_KEY_HOME 106 #define GLUT_KEY_END 107 #define GLUT_KEY_INSERT 108 #endif /* Entry/exit state. */ #define GLUT_LEFT 0 #define GLUT_ENTERED 1 /* Menu usage state. */ #define GLUT_MENU_NOT_IN_USE 0 #define GLUT_MENU_IN_USE 1 /* Visibility state. */ #define GLUT_NOT_VISIBLE 0 #define GLUT_VISIBLE 1 /* Window status state. */ #define GLUT_HIDDEN 0 #define GLUT_FULLY_RETAINED 1 #define GLUT_PARTIALLY_RETAINED 2 #define GLUT_FULLY_COVERED 3 /* Color index component selection values. */ #define GLUT_RED 0 #define GLUT_GREEN 1 #define GLUT_BLUE 2 #if defined(_WIN32) /* Stroke font constants (use these in GLUT program). */ #define GLUT_STROKE_ROMAN ((void*)0) #define GLUT_STROKE_MONO_ROMAN ((void*)1) /* Bitmap font constants (use these in GLUT program). */ #define GLUT_BITMAP_9_BY_15 ((void*)2) #define GLUT_BITMAP_8_BY_13 ((void*)3) #define GLUT_BITMAP_TIMES_ROMAN_10 ((void*)4) #define GLUT_BITMAP_TIMES_ROMAN_24 ((void*)5) #if (GLUT_API_VERSION >= 3) #define GLUT_BITMAP_HELVETICA_10 ((void*)6) #define GLUT_BITMAP_HELVETICA_12 ((void*)7) #define GLUT_BITMAP_HELVETICA_18 ((void*)8) #endif #else /* Stroke font opaque addresses (use constants instead in source code). */ GLUTAPI void *glutStrokeRoman; GLUTAPI void *glutStrokeMonoRoman; /* Stroke font constants (use these in GLUT program). */ #define GLUT_STROKE_ROMAN (&glutStrokeRoman) #define GLUT_STROKE_MONO_ROMAN (&glutStrokeMonoRoman) /* Bitmap font opaque addresses (use constants instead in source code). */ GLUTAPI void *glutBitmap9By15; GLUTAPI void *glutBitmap8By13; GLUTAPI void *glutBitmapTimesRoman10; GLUTAPI void *glutBitmapTimesRoman24; GLUTAPI void *glutBitmapHelvetica10; GLUTAPI void *glutBitmapHelvetica12; GLUTAPI void *glutBitmapHelvetica18; /* Bitmap font constants (use these in GLUT program). */ #define GLUT_BITMAP_9_BY_15 (&glutBitmap9By15) #define GLUT_BITMAP_8_BY_13 (&glutBitmap8By13) #define GLUT_BITMAP_TIMES_ROMAN_10 (&glutBitmapTimesRoman10) #define GLUT_BITMAP_TIMES_ROMAN_24 (&glutBitmapTimesRoman24) #if (GLUT_API_VERSION >= 3) #define GLUT_BITMAP_HELVETICA_10 (&glutBitmapHelvetica10) #define GLUT_BITMAP_HELVETICA_12 (&glutBitmapHelvetica12) #define GLUT_BITMAP_HELVETICA_18 (&glutBitmapHelvetica18) #endif #endif /* glutGet parameters. */ #define GLUT_WINDOW_X ((GLenum) 100) #define GLUT_WINDOW_Y ((GLenum) 101) #define GLUT_WINDOW_WIDTH ((GLenum) 102) #define GLUT_WINDOW_HEIGHT ((GLenum) 103) #define GLUT_WINDOW_BUFFER_SIZE ((GLenum) 104) #define GLUT_WINDOW_STENCIL_SIZE ((GLenum) 105) #define GLUT_WINDOW_DEPTH_SIZE ((GLenum) 106) #define GLUT_WINDOW_RED_SIZE ((GLenum) 107) #define GLUT_WINDOW_GREEN_SIZE ((GLenum) 108) #define GLUT_WINDOW_BLUE_SIZE ((GLenum) 109) #define GLUT_WINDOW_ALPHA_SIZE ((GLenum) 110) #define GLUT_WINDOW_ACCUM_RED_SIZE ((GLenum) 111) #define GLUT_WINDOW_ACCUM_GREEN_SIZE ((GLenum) 112) #define GLUT_WINDOW_ACCUM_BLUE_SIZE ((GLenum) 113) #define GLUT_WINDOW_ACCUM_ALPHA_SIZE ((GLenum) 114) #define GLUT_WINDOW_DOUBLEBUFFER ((GLenum) 115) #define GLUT_WINDOW_RGBA ((GLenum) 116) #define GLUT_WINDOW_PARENT ((GLenum) 117) #define GLUT_WINDOW_NUM_CHILDREN ((GLenum) 118) #define GLUT_WINDOW_COLORMAP_SIZE ((GLenum) 119) #if (GLUT_API_VERSION >= 2) #define GLUT_WINDOW_NUM_SAMPLES ((GLenum) 120) #define GLUT_WINDOW_STEREO ((GLenum) 121) #endif #if (GLUT_API_VERSION >= 3) #define GLUT_WINDOW_CURSOR ((GLenum) 122) #endif #define GLUT_SCREEN_WIDTH ((GLenum) 200) #define GLUT_SCREEN_HEIGHT ((GLenum) 201) #define GLUT_SCREEN_WIDTH_MM ((GLenum) 202) #define GLUT_SCREEN_HEIGHT_MM ((GLenum) 203) #define GLUT_MENU_NUM_ITEMS ((GLenum) 300) #define GLUT_DISPLAY_MODE_POSSIBLE ((GLenum) 400) #define GLUT_INIT_WINDOW_X ((GLenum) 500) #define GLUT_INIT_WINDOW_Y ((GLenum) 501) #define GLUT_INIT_WINDOW_WIDTH ((GLenum) 502) #define GLUT_INIT_WINDOW_HEIGHT ((GLenum) 503) #define GLUT_INIT_DISPLAY_MODE ((GLenum) 504) #if (GLUT_API_VERSION >= 2) #define GLUT_ELAPSED_TIME ((GLenum) 700) #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) #define GLUT_WINDOW_FORMAT_ID ((GLenum) 123) #endif #if (GLUT_API_VERSION >= 2) /* glutDeviceGet parameters. */ #define GLUT_HAS_KEYBOARD ((GLenum) 600) #define GLUT_HAS_MOUSE ((GLenum) 601) #define GLUT_HAS_SPACEBALL ((GLenum) 602) #define GLUT_HAS_DIAL_AND_BUTTON_BOX ((GLenum) 603) #define GLUT_HAS_TABLET ((GLenum) 604) #define GLUT_NUM_MOUSE_BUTTONS ((GLenum) 605) #define GLUT_NUM_SPACEBALL_BUTTONS ((GLenum) 606) #define GLUT_NUM_BUTTON_BOX_BUTTONS ((GLenum) 607) #define GLUT_NUM_DIALS ((GLenum) 608) #define GLUT_NUM_TABLET_BUTTONS ((GLenum) 609) #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) #define GLUT_DEVICE_IGNORE_KEY_REPEAT ((GLenum) 610) #define GLUT_DEVICE_KEY_REPEAT ((GLenum) 611) #define GLUT_HAS_JOYSTICK ((GLenum) 612) #define GLUT_OWNS_JOYSTICK ((GLenum) 613) #define GLUT_JOYSTICK_BUTTONS ((GLenum) 614) #define GLUT_JOYSTICK_AXES ((GLenum) 615) #define GLUT_JOYSTICK_POLL_RATE ((GLenum) 616) #endif #if (GLUT_API_VERSION >= 3) /* glutLayerGet parameters. */ #define GLUT_OVERLAY_POSSIBLE ((GLenum) 800) #define GLUT_LAYER_IN_USE ((GLenum) 801) #define GLUT_HAS_OVERLAY ((GLenum) 802) #define GLUT_TRANSPARENT_INDEX ((GLenum) 803) #define GLUT_NORMAL_DAMAGED ((GLenum) 804) #define GLUT_OVERLAY_DAMAGED ((GLenum) 805) #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) /* glutVideoResizeGet parameters. */ #define GLUT_VIDEO_RESIZE_POSSIBLE ((GLenum) 900) #define GLUT_VIDEO_RESIZE_IN_USE ((GLenum) 901) #define GLUT_VIDEO_RESIZE_X_DELTA ((GLenum) 902) #define GLUT_VIDEO_RESIZE_Y_DELTA ((GLenum) 903) #define GLUT_VIDEO_RESIZE_WIDTH_DELTA ((GLenum) 904) #define GLUT_VIDEO_RESIZE_HEIGHT_DELTA ((GLenum) 905) #define GLUT_VIDEO_RESIZE_X ((GLenum) 906) #define GLUT_VIDEO_RESIZE_Y ((GLenum) 907) #define GLUT_VIDEO_RESIZE_WIDTH ((GLenum) 908) #define GLUT_VIDEO_RESIZE_HEIGHT ((GLenum) 909) #endif /* glutUseLayer parameters. */ #define GLUT_NORMAL ((GLenum) 0) #define GLUT_OVERLAY ((GLenum) 1) /* glutGetModifiers return mask. */ #define GLUT_ACTIVE_SHIFT 1 #define GLUT_ACTIVE_CTRL 2 #define GLUT_ACTIVE_ALT 4 /* glutSetCursor parameters. */ /* Basic arrows. */ #define GLUT_CURSOR_RIGHT_ARROW 0 #define GLUT_CURSOR_LEFT_ARROW 1 /* Symbolic cursor shapes. */ #define GLUT_CURSOR_INFO 2 #define GLUT_CURSOR_DESTROY 3 #define GLUT_CURSOR_HELP 4 #define GLUT_CURSOR_CYCLE 5 #define GLUT_CURSOR_SPRAY 6 #define GLUT_CURSOR_WAIT 7 #define GLUT_CURSOR_TEXT 8 #define GLUT_CURSOR_CROSSHAIR 9 /* Directional cursors. */ #define GLUT_CURSOR_UP_DOWN 10 #define GLUT_CURSOR_LEFT_RIGHT 11 /* Sizing cursors. */ #define GLUT_CURSOR_TOP_SIDE 12 #define GLUT_CURSOR_BOTTOM_SIDE 13 #define GLUT_CURSOR_LEFT_SIDE 14 #define GLUT_CURSOR_RIGHT_SIDE 15 #define GLUT_CURSOR_TOP_LEFT_CORNER 16 #define GLUT_CURSOR_TOP_RIGHT_CORNER 17 #define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 18 #define GLUT_CURSOR_BOTTOM_LEFT_CORNER 19 /* Inherit from parent window. */ #define GLUT_CURSOR_INHERIT 100 /* Blank cursor. */ #define GLUT_CURSOR_NONE 101 /* Fullscreen crosshair (if available). */ #define GLUT_CURSOR_FULL_CROSSHAIR 102 #endif /* GLUT initialization sub-API. */ GLUTAPI void APIENTRY glutInit(int *argcp, char **argv); #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) GLUTAPI void APIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); #ifndef GLUT_BUILDING_LIB static void APIENTRY glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } #define glutInit glutInit_ATEXIT_HACK #endif #endif GLUTAPI void APIENTRY glutInitDisplayMode(unsigned int mode); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI void APIENTRY glutInitDisplayString(const char *string); #endif GLUTAPI void APIENTRY glutInitWindowPosition(int x, int y); GLUTAPI void APIENTRY glutInitWindowSize(int width, int height); GLUTAPI void APIENTRY glutMainLoop(void); /* GLUT window sub-API. */ GLUTAPI int APIENTRY glutCreateWindow(const char *title); #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) GLUTAPI int APIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); #ifndef GLUT_BUILDING_LIB static int APIENTRY glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } #define glutCreateWindow glutCreateWindow_ATEXIT_HACK #endif #endif GLUTAPI int APIENTRY glutCreateSubWindow(int win, int x, int y, int width, int height); GLUTAPI void APIENTRY glutDestroyWindow(int win); GLUTAPI void APIENTRY glutPostRedisplay(void); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) GLUTAPI void APIENTRY glutPostWindowRedisplay(int win); #endif GLUTAPI void APIENTRY glutSwapBuffers(void); GLUTAPI int APIENTRY glutGetWindow(void); GLUTAPI void APIENTRY glutSetWindow(int win); GLUTAPI void APIENTRY glutSetWindowTitle(const char *title); GLUTAPI void APIENTRY glutSetIconTitle(const char *title); GLUTAPI void APIENTRY glutPositionWindow(int x, int y); GLUTAPI void APIENTRY glutReshapeWindow(int width, int height); GLUTAPI void APIENTRY glutPopWindow(void); GLUTAPI void APIENTRY glutPushWindow(void); GLUTAPI void APIENTRY glutIconifyWindow(void); GLUTAPI void APIENTRY glutShowWindow(void); GLUTAPI void APIENTRY glutHideWindow(void); #if (GLUT_API_VERSION >= 3) GLUTAPI void APIENTRY glutFullScreen(void); GLUTAPI void APIENTRY glutSetCursor(int cursor); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI void APIENTRY glutWarpPointer(int x, int y); #endif /* GLUT overlay sub-API. */ GLUTAPI void APIENTRY glutEstablishOverlay(void); GLUTAPI void APIENTRY glutRemoveOverlay(void); GLUTAPI void APIENTRY glutUseLayer(GLenum layer); GLUTAPI void APIENTRY glutPostOverlayRedisplay(void); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) GLUTAPI void APIENTRY glutPostWindowOverlayRedisplay(int win); #endif GLUTAPI void APIENTRY glutShowOverlay(void); GLUTAPI void APIENTRY glutHideOverlay(void); #endif /* GLUT menu sub-API. */ GLUTAPI int APIENTRY glutCreateMenu(void (GLUTCALLBACK *func)(int)); #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) GLUTAPI int APIENTRY __glutCreateMenuWithExit(void (GLUTCALLBACK *func)(int), void (__cdecl *exitfunc)(int)); #ifndef GLUT_BUILDING_LIB static int APIENTRY glutCreateMenu_ATEXIT_HACK(void (GLUTCALLBACK *func)(int)) { return __glutCreateMenuWithExit(func, exit); } #define glutCreateMenu glutCreateMenu_ATEXIT_HACK #endif #endif GLUTAPI void APIENTRY glutDestroyMenu(int menu); GLUTAPI int APIENTRY glutGetMenu(void); GLUTAPI void APIENTRY glutSetMenu(int menu); GLUTAPI void APIENTRY glutAddMenuEntry(const char *label, int value); GLUTAPI void APIENTRY glutAddSubMenu(const char *label, int submenu); GLUTAPI void APIENTRY glutChangeToMenuEntry(int item, const char *label, int value); GLUTAPI void APIENTRY glutChangeToSubMenu(int item, const char *label, int submenu); GLUTAPI void APIENTRY glutRemoveMenuItem(int item); GLUTAPI void APIENTRY glutAttachMenu(int button); GLUTAPI void APIENTRY glutDetachMenu(int button); /* GLUT window callback sub-API. */ GLUTAPI void APIENTRY glutDisplayFunc(void (GLUTCALLBACK *func)(void)); GLUTAPI void APIENTRY glutReshapeFunc(void (GLUTCALLBACK *func)(int width, int height)); GLUTAPI void APIENTRY glutKeyboardFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y)); GLUTAPI void APIENTRY glutMouseFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y)); GLUTAPI void APIENTRY glutMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); GLUTAPI void APIENTRY glutPassiveMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); GLUTAPI void APIENTRY glutEntryFunc(void (GLUTCALLBACK *func)(int state)); GLUTAPI void APIENTRY glutVisibilityFunc(void (GLUTCALLBACK *func)(int state)); GLUTAPI void APIENTRY glutIdleFunc(void (GLUTCALLBACK *func)(void)); GLUTAPI void APIENTRY glutTimerFunc(unsigned int millis, void (GLUTCALLBACK *func)(int value), int value); GLUTAPI void APIENTRY glutMenuStateFunc(void (GLUTCALLBACK *func)(int state)); #if (GLUT_API_VERSION >= 2) GLUTAPI void APIENTRY glutSpecialFunc(void (GLUTCALLBACK *func)(int key, int x, int y)); GLUTAPI void APIENTRY glutSpaceballMotionFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); GLUTAPI void APIENTRY glutSpaceballRotateFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); GLUTAPI void APIENTRY glutSpaceballButtonFunc(void (GLUTCALLBACK *func)(int button, int state)); GLUTAPI void APIENTRY glutButtonBoxFunc(void (GLUTCALLBACK *func)(int button, int state)); GLUTAPI void APIENTRY glutDialsFunc(void (GLUTCALLBACK *func)(int dial, int value)); GLUTAPI void APIENTRY glutTabletMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); GLUTAPI void APIENTRY glutTabletButtonFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y)); #if (GLUT_API_VERSION >= 3) GLUTAPI void APIENTRY glutMenuStatusFunc(void (GLUTCALLBACK *func)(int status, int x, int y)); GLUTAPI void APIENTRY glutOverlayDisplayFunc(void (GLUTCALLBACK *func)(void)); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI void APIENTRY glutWindowStatusFunc(void (GLUTCALLBACK *func)(int state)); #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) GLUTAPI void APIENTRY glutKeyboardUpFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y)); GLUTAPI void APIENTRY glutSpecialUpFunc(void (GLUTCALLBACK *func)(int key, int x, int y)); GLUTAPI void APIENTRY glutJoystickFunc(void (GLUTCALLBACK *func)(unsigned int buttonMask, int x, int y, int z), int pollInterval); #endif #endif #endif /* GLUT color index sub-API. */ GLUTAPI void APIENTRY glutSetColor(int, GLfloat red, GLfloat green, GLfloat blue); GLUTAPI GLfloat APIENTRY glutGetColor(int ndx, int component); GLUTAPI void APIENTRY glutCopyColormap(int win); /* GLUT state retrieval sub-API. */ GLUTAPI int APIENTRY glutGet(GLenum type); GLUTAPI int APIENTRY glutDeviceGet(GLenum type); #if (GLUT_API_VERSION >= 2) /* GLUT extension support sub-API */ GLUTAPI int APIENTRY glutExtensionSupported(const char *name); #endif #if (GLUT_API_VERSION >= 3) GLUTAPI int APIENTRY glutGetModifiers(void); GLUTAPI int APIENTRY glutLayerGet(GLenum type); #endif /* GLUT font sub-API */ GLUTAPI void APIENTRY glutBitmapCharacter(void *font, int character); GLUTAPI int APIENTRY glutBitmapWidth(void *font, int character); GLUTAPI void APIENTRY glutStrokeCharacter(void *font, int character); GLUTAPI int APIENTRY glutStrokeWidth(void *font, int character); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI int APIENTRY glutBitmapLength(void *font, const unsigned char *string); GLUTAPI int APIENTRY glutStrokeLength(void *font, const unsigned char *string); #endif /* GLUT pre-built models sub-API */ GLUTAPI void APIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutWireCube(GLdouble size); GLUTAPI void APIENTRY glutSolidCube(GLdouble size); GLUTAPI void APIENTRY glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); GLUTAPI void APIENTRY glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); GLUTAPI void APIENTRY glutWireDodecahedron(void); GLUTAPI void APIENTRY glutSolidDodecahedron(void); GLUTAPI void APIENTRY glutWireTeapot(GLdouble size); GLUTAPI void APIENTRY glutSolidTeapot(GLdouble size); GLUTAPI void APIENTRY glutWireOctahedron(void); GLUTAPI void APIENTRY glutSolidOctahedron(void); GLUTAPI void APIENTRY glutWireTetrahedron(void); GLUTAPI void APIENTRY glutSolidTetrahedron(void); GLUTAPI void APIENTRY glutWireIcosahedron(void); GLUTAPI void APIENTRY glutSolidIcosahedron(void); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) /* GLUT video resize sub-API. */ GLUTAPI int APIENTRY glutVideoResizeGet(GLenum param); GLUTAPI void APIENTRY glutSetupVideoResizing(void); GLUTAPI void APIENTRY glutStopVideoResizing(void); GLUTAPI void APIENTRY glutVideoResize(int x, int y, int width, int height); GLUTAPI void APIENTRY glutVideoPan(int x, int y, int width, int height); /* GLUT debugging sub-API. */ GLUTAPI void APIENTRY glutReportErrors(void); #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) /* GLUT device control sub-API. */ /* glutSetKeyRepeat modes. */ #define GLUT_KEY_REPEAT_OFF 0 #define GLUT_KEY_REPEAT_ON 1 #define GLUT_KEY_REPEAT_DEFAULT 2 /* Joystick button masks. */ #define GLUT_JOYSTICK_BUTTON_A 1 #define GLUT_JOYSTICK_BUTTON_B 2 #define GLUT_JOYSTICK_BUTTON_C 4 #define GLUT_JOYSTICK_BUTTON_D 8 GLUTAPI void APIENTRY glutIgnoreKeyRepeat(int ignore); GLUTAPI void APIENTRY glutSetKeyRepeat(int repeatMode); GLUTAPI void APIENTRY glutForceJoystickFunc(void); /* GLUT game mode sub-API. */ /* glutGameModeGet. */ #define GLUT_GAME_MODE_ACTIVE ((GLenum) 0) #define GLUT_GAME_MODE_POSSIBLE ((GLenum) 1) #define GLUT_GAME_MODE_WIDTH ((GLenum) 2) #define GLUT_GAME_MODE_HEIGHT ((GLenum) 3) #define GLUT_GAME_MODE_PIXEL_DEPTH ((GLenum) 4) #define GLUT_GAME_MODE_REFRESH_RATE ((GLenum) 5) #define GLUT_GAME_MODE_DISPLAY_CHANGED ((GLenum) 6) GLUTAPI void APIENTRY glutGameModeString(const char *string); GLUTAPI int APIENTRY glutEnterGameMode(void); GLUTAPI void APIENTRY glutLeaveGameMode(void); GLUTAPI int APIENTRY glutGameModeGet(GLenum mode); #endif #ifdef __cplusplus } #endif #ifdef GLUT_APIENTRY_DEFINED # undef GLUT_APIENTRY_DEFINED # undef APIENTRY #endif #ifdef GLUT_WINGDIAPI_DEFINED # undef GLUT_WINGDIAPI_DEFINED # undef WINGDIAPI #endif #ifdef GLUT_DEFINED___CDECL # undef GLUT_DEFINED___CDECL # undef __cdecl #endif #ifdef GLUT_DEFINED__CRTIMP # undef GLUT_DEFINED__CRTIMP # undef _CRTIMP #endif #endif /* __glut_h__ */ Chipmunk-6.1.5/include/chipmunk/000755 000765 000000 00000000000 12151675775 017505 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/include/chipmunk/chipmunk.h000644 000765 000000 00000020506 12151675775 021477 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef CHIPMUNK_HEADER #define CHIPMUNK_HEADER #ifdef _MSC_VER #define _USE_MATH_DEFINES #endif #include #include #ifdef __cplusplus extern "C" { #endif #ifndef CP_ALLOW_PRIVATE_ACCESS #define CP_ALLOW_PRIVATE_ACCESS 0 #endif #if CP_ALLOW_PRIVATE_ACCESS == 1 #define CP_PRIVATE(__symbol__) __symbol__ #else #define CP_PRIVATE(__symbol__) __symbol__##_private #endif void cpMessage(const char *condition, const char *file, int line, int isError, int isHardError, const char *message, ...); #ifdef NDEBUG #define cpAssertWarn(__condition__, ...) #else #define cpAssertWarn(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 0, 0, __VA_ARGS__) #endif #ifdef NDEBUG #define cpAssertSoft(__condition__, ...) #else #define cpAssertSoft(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 1, 0, __VA_ARGS__) #endif // Hard assertions are important and cheap to execute. They are not disabled by compiling as debug. #define cpAssertHard(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 1, 1, __VA_ARGS__) #include "chipmunk_types.h" /// @defgroup misc Misc /// @{ /// Allocated size for various Chipmunk buffers #ifndef CP_BUFFER_BYTES #define CP_BUFFER_BYTES (32*1024) #endif #ifndef cpcalloc /// Chipmunk calloc() alias. #define cpcalloc calloc #endif #ifndef cprealloc /// Chipmunk realloc() alias. #define cprealloc realloc #endif #ifndef cpfree /// Chipmunk free() alias. #define cpfree free #endif typedef struct cpArray cpArray; typedef struct cpHashSet cpHashSet; typedef struct cpBody cpBody; typedef struct cpShape cpShape; typedef struct cpConstraint cpConstraint; typedef struct cpCollisionHandler cpCollisionHandler; typedef struct cpArbiter cpArbiter; typedef struct cpSpace cpSpace; #include "cpVect.h" #include "cpBB.h" #include "cpSpatialIndex.h" #include "cpBody.h" #include "cpShape.h" #include "cpPolyShape.h" #include "cpArbiter.h" #include "constraints/cpConstraint.h" #include "cpSpace.h" // Chipmunk 6.1.4 #define CP_VERSION_MAJOR 6 #define CP_VERSION_MINOR 1 #define CP_VERSION_RELEASE 4 /// Version string. extern const char *cpVersionString; /// @deprecated void cpInitChipmunk(void); /// Enables segment to segment shape collisions. void cpEnableSegmentToSegmentCollisions(void); /// Calculate the moment of inertia for a circle. /// @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0. cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset); /// Calculate area of a hollow circle. /// @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0. cpFloat cpAreaForCircle(cpFloat r1, cpFloat r2); /// Calculate the moment of inertia for a line segment. /// Beveling radius is not supported. cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b); /// Calculate the area of a fattened (capsule shaped) line segment. cpFloat cpAreaForSegment(cpVect a, cpVect b, cpFloat r); /// Calculate the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid. The offset is added to each vertex. cpFloat cpMomentForPoly(cpFloat m, int numVerts, const cpVect *verts, cpVect offset); /// Calculate the signed area of a polygon. A Clockwise winding gives positive area. /// This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes. cpFloat cpAreaForPoly(const int numVerts, const cpVect *verts); /// Calculate the natural centroid of a polygon. cpVect cpCentroidForPoly(const int numVerts, const cpVect *verts); /// Center the polygon on the origin. (Subtracts the centroid of the polygon from each vertex) void cpRecenterPoly(const int numVerts, cpVect *verts); /// Calculate the moment of inertia for a solid box. cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height); /// Calculate the moment of inertia for a solid box. cpFloat cpMomentForBox2(cpFloat m, cpBB box); /// Calculate the convex hull of a given set of points. Returns the count of points in the hull. /// @c result must be a pointer to a @c cpVect array with at least @c count elements. If @c result is @c NULL, then @c verts will be reduced instead. /// @c first is an optional pointer to an integer to store where the first vertex in the hull came from (i.e. verts[first] == result[0]) /// @c tol is the allowed amount to shrink the hull when simplifying it. A tolerance of 0.0 creates an exact hull. int cpConvexHull(int count, cpVect *verts, cpVect *result, int *first, cpFloat tol); #ifdef _MSC_VER #include "malloc.h" #endif /// Convenience macro to work with cpConvexHull. /// @c count and @c verts is the input array passed to cpConvexHull(). /// @c count_var and @c verts_var are the names of the variables the macro creates to store the result. /// The output vertex array is allocated on the stack using alloca() so it will be freed automatically, but cannot be returned from the current scope. #define CP_CONVEX_HULL(__count__, __verts__, __count_var__, __verts_var__) \ cpVect *__verts_var__ = (cpVect *)alloca(__count__*sizeof(cpVect)); \ int __count_var__ = cpConvexHull(__count__, __verts__, __verts_var__, NULL, 0.0); \ #if defined(__has_extension) #if __has_extension(blocks) // Define alternate block based alternatives for a few of the callback heavy functions. // Collision handlers are post-step callbacks are not included to avoid memory management issues. // If you want to use blocks for those and are aware of how to correctly manage the memory, the implementation is trivial. void cpSpaceEachBody_b(cpSpace *space, void (^block)(cpBody *body)); void cpSpaceEachShape_b(cpSpace *space, void (^block)(cpShape *shape)); void cpSpaceEachConstraint_b(cpSpace *space, void (^block)(cpConstraint *constraint)); void cpBodyEachShape_b(cpBody *body, void (^block)(cpShape *shape)); void cpBodyEachConstraint_b(cpBody *body, void (^block)(cpConstraint *constraint)); void cpBodyEachArbiter_b(cpBody *body, void (^block)(cpArbiter *arbiter)); typedef void (^cpSpaceNearestPointQueryBlock)(cpShape *shape, cpFloat distance, cpVect point); void cpSpaceNearestPointQuery_b(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryBlock block); typedef void (^cpSpaceSegmentQueryBlock)(cpShape *shape, cpFloat t, cpVect n); void cpSpaceSegmentQuery_b(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryBlock block); typedef void (^cpSpaceBBQueryBlock)(cpShape *shape); void cpSpaceBBQuery_b(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryBlock block); typedef void (^cpSpaceShapeQueryBlock)(cpShape *shape, cpContactPointSet *points); cpBool cpSpaceShapeQuery_b(cpSpace *space, cpShape *shape, cpSpaceShapeQueryBlock block); #endif #endif //@} #ifdef __cplusplus } static inline cpVect operator *(const cpVect v, const cpFloat s){return cpvmult(v, s);} static inline cpVect operator +(const cpVect v1, const cpVect v2){return cpvadd(v1, v2);} static inline cpVect operator -(const cpVect v1, const cpVect v2){return cpvsub(v1, v2);} static inline cpBool operator ==(const cpVect v1, const cpVect v2){return cpveql(v1, v2);} static inline cpVect operator -(const cpVect v){return cpvneg(v);} #endif #endif Chipmunk-6.1.5/include/chipmunk/chipmunk_ffi.h000644 000765 000000 00000012104 12151675775 022316 0ustar00slembckewheel000000 000000 #ifdef CHIPMUNK_FFI // Create non static inlined copies of Chipmunk functions, useful for working with dynamic FFIs // This file should only be included in chipmunk.c #ifdef _MSC_VER #if _MSC_VER >= 1600 #define MAKE_REF(name) decltype(name) *_##name = name #else #define MAKE_REF(name) #endif #else #define MAKE_REF(name) __typeof__(name) *_##name = name #endif #define MAKE_PROPERTIES_REF(struct, property) \ MAKE_REF(struct##Get##property); MAKE_REF(struct##Set##property) MAKE_REF(cpv); // makes a variable named _cpv that contains the function pointer for cpv() MAKE_REF(cpveql); MAKE_REF(cpvadd); MAKE_REF(cpvneg); MAKE_REF(cpvsub); MAKE_REF(cpvmult); MAKE_REF(cpvdot); MAKE_REF(cpvcross); MAKE_REF(cpvperp); MAKE_REF(cpvrperp); MAKE_REF(cpvproject); MAKE_REF(cpvforangle); MAKE_REF(cpvtoangle); MAKE_REF(cpvrotate); MAKE_REF(cpvunrotate); MAKE_REF(cpvlengthsq); MAKE_REF(cpvlength); MAKE_REF(cpvlerp); MAKE_REF(cpvnormalize); MAKE_REF(cpvnormalize_safe); MAKE_REF(cpvclamp); MAKE_REF(cpvlerpconst); MAKE_REF(cpvdist); MAKE_REF(cpvdistsq); MAKE_REF(cpvnear); MAKE_REF(cpfmax); MAKE_REF(cpfmin); MAKE_REF(cpfabs); MAKE_REF(cpfclamp); MAKE_REF(cpflerp); MAKE_REF(cpflerpconst); MAKE_REF(cpBBNew); MAKE_REF(cpBBNewForCircle); MAKE_REF(cpBBIntersects); MAKE_REF(cpBBContainsBB); MAKE_REF(cpBBContainsVect); MAKE_REF(cpBBMerge); MAKE_REF(cpBBExpand); MAKE_REF(cpBBArea); MAKE_REF(cpBBMergedArea); MAKE_REF(cpBBSegmentQuery); MAKE_REF(cpBBIntersectsSegment); MAKE_REF(cpBBClampVect); MAKE_REF(cpBodyGetMass); MAKE_REF(cpBodyGetMoment); MAKE_REF(cpBodyGetPos); MAKE_REF(cpBodyGetAngle); MAKE_REF(cpBodyGetRot); MAKE_PROPERTIES_REF(cpBody, Vel); MAKE_PROPERTIES_REF(cpBody, Force); MAKE_PROPERTIES_REF(cpBody, AngVel); MAKE_PROPERTIES_REF(cpBody, Torque); MAKE_PROPERTIES_REF(cpBody, VelLimit); MAKE_PROPERTIES_REF(cpBody, AngVelLimit); MAKE_PROPERTIES_REF(cpBody, UserData); MAKE_REF(cpBodyIsSleeping); MAKE_REF(cpBodyIsStatic); MAKE_REF(cpBodyIsRogue); MAKE_REF(cpBodyLocal2World); MAKE_REF(cpBodyWorld2Local); MAKE_REF(cpBodyKineticEnergy); MAKE_REF(cpShapeGetBB); MAKE_PROPERTIES_REF(cpShape, Body); MAKE_PROPERTIES_REF(cpShape, Sensor); MAKE_PROPERTIES_REF(cpShape, Elasticity); MAKE_PROPERTIES_REF(cpShape, Friction); MAKE_PROPERTIES_REF(cpShape, SurfaceVelocity); MAKE_PROPERTIES_REF(cpShape, UserData); MAKE_PROPERTIES_REF(cpShape, CollisionType); MAKE_PROPERTIES_REF(cpShape, Group); MAKE_PROPERTIES_REF(cpShape, Layers); MAKE_REF(cpArbiterGetShapes); MAKE_REF(cpArbiterGetBodies); MAKE_REF(cpArbiterIsFirstContact); MAKE_REF(cpArbiterGetCount); MAKE_REF(cpConstraintGetA); MAKE_REF(cpConstraintGetB); MAKE_PROPERTIES_REF(cpConstraint, MaxForce); MAKE_PROPERTIES_REF(cpConstraint, ErrorBias); MAKE_PROPERTIES_REF(cpConstraint, MaxBias); MAKE_PROPERTIES_REF(cpConstraint, UserData); MAKE_REF(cpConstraintGetImpulse); MAKE_PROPERTIES_REF(cpDampedRotarySpring, RestAngle); MAKE_PROPERTIES_REF(cpDampedRotarySpring, Stiffness); MAKE_PROPERTIES_REF(cpDampedRotarySpring, Damping); //MAKE_PROPERTIES_REF(cpDampedRotarySpring, SpringTorqueFunc); MAKE_PROPERTIES_REF(cpDampedSpring, Anchr1); MAKE_PROPERTIES_REF(cpDampedSpring, Anchr2); MAKE_PROPERTIES_REF(cpDampedSpring, RestLength); MAKE_PROPERTIES_REF(cpDampedSpring, Stiffness); MAKE_PROPERTIES_REF(cpDampedSpring, Damping); //MAKE_PROPERTIES_REF(cpDampedSpring, SpringForceFunc); MAKE_PROPERTIES_REF(cpGearJoint, Phase); MAKE_REF(cpGearJointGetRatio); MAKE_PROPERTIES_REF(cpGrooveJoint, Anchr2); MAKE_REF(cpGrooveJointGetGrooveA); MAKE_REF(cpGrooveJointGetGrooveB); MAKE_PROPERTIES_REF(cpPinJoint, Anchr1); MAKE_PROPERTIES_REF(cpPinJoint, Anchr2); MAKE_PROPERTIES_REF(cpPinJoint, Dist); MAKE_PROPERTIES_REF(cpPivotJoint, Anchr1); MAKE_PROPERTIES_REF(cpPivotJoint, Anchr2); MAKE_PROPERTIES_REF(cpRatchetJoint, Angle); MAKE_PROPERTIES_REF(cpRatchetJoint, Phase); MAKE_PROPERTIES_REF(cpRatchetJoint, Ratchet); MAKE_PROPERTIES_REF(cpRotaryLimitJoint, Min); MAKE_PROPERTIES_REF(cpRotaryLimitJoint, Max); MAKE_PROPERTIES_REF(cpSimpleMotor, Rate); MAKE_PROPERTIES_REF(cpSlideJoint, Anchr1); MAKE_PROPERTIES_REF(cpSlideJoint, Anchr2); MAKE_PROPERTIES_REF(cpSlideJoint, Min); MAKE_PROPERTIES_REF(cpSlideJoint, Max); MAKE_REF(cpSegmentQueryHitPoint); MAKE_REF(cpSegmentQueryHitDist); MAKE_REF(cpSpatialIndexDestroy); MAKE_REF(cpSpatialIndexCount); MAKE_REF(cpSpatialIndexEach); MAKE_REF(cpSpatialIndexContains); MAKE_REF(cpSpatialIndexInsert); MAKE_REF(cpSpatialIndexRemove); MAKE_REF(cpSpatialIndexReindex); MAKE_REF(cpSpatialIndexReindexObject); MAKE_REF(cpSpatialIndexSegmentQuery); MAKE_REF(cpSpatialIndexQuery); MAKE_REF(cpSpatialIndexReindexQuery); MAKE_PROPERTIES_REF(cpSpace, Iterations); MAKE_PROPERTIES_REF(cpSpace, Gravity); MAKE_PROPERTIES_REF(cpSpace, Damping); MAKE_PROPERTIES_REF(cpSpace, IdleSpeedThreshold); MAKE_PROPERTIES_REF(cpSpace, SleepTimeThreshold); MAKE_PROPERTIES_REF(cpSpace, CollisionSlop); MAKE_PROPERTIES_REF(cpSpace, CollisionBias); MAKE_PROPERTIES_REF(cpSpace, CollisionPersistence); MAKE_PROPERTIES_REF(cpSpace, EnableContactGraph); MAKE_PROPERTIES_REF(cpSpace, UserData); MAKE_REF(cpSpaceGetStaticBody); MAKE_REF(cpSpaceGetCurrentTimeStep); MAKE_REF(cpSpaceIsLocked); #endif Chipmunk-6.1.5/include/chipmunk/chipmunk_private.h000644 000765 000000 00000020267 12151675775 023235 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define CP_ALLOW_PRIVATE_ACCESS 1 #include "chipmunk.h" #define CP_HASH_COEF (3344921057ul) #define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF) //MARK: cpArray struct cpArray { int num, max; void **arr; }; cpArray *cpArrayNew(int size); void cpArrayFree(cpArray *arr); void cpArrayPush(cpArray *arr, void *object); void *cpArrayPop(cpArray *arr); void cpArrayDeleteObj(cpArray *arr, void *obj); cpBool cpArrayContains(cpArray *arr, void *ptr); void cpArrayFreeEach(cpArray *arr, void (freeFunc)(void*)); //MARK: Foreach loops static inline cpConstraint * cpConstraintNext(cpConstraint *node, cpBody *body) { return (node->a == body ? node->next_a : node->next_b); } #define CP_BODY_FOREACH_CONSTRAINT(bdy, var)\ for(cpConstraint *var = bdy->constraintList; var; var = cpConstraintNext(var, bdy)) static inline cpArbiter * cpArbiterNext(cpArbiter *node, cpBody *body) { return (node->body_a == body ? node->thread_a.next : node->thread_b.next); } #define CP_BODY_FOREACH_ARBITER(bdy, var)\ for(cpArbiter *var = bdy->arbiterList; var; var = cpArbiterNext(var, bdy)) #define CP_BODY_FOREACH_SHAPE(body, var)\ for(cpShape *var = body->shapeList; var; var = var->next) #define CP_BODY_FOREACH_COMPONENT(root, var)\ for(cpBody *var = root; var; var = var->node.next) //MARK: cpHashSet typedef cpBool (*cpHashSetEqlFunc)(void *ptr, void *elt); typedef void *(*cpHashSetTransFunc)(void *ptr, void *data); cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc); void cpHashSetSetDefaultValue(cpHashSet *set, void *default_value); void cpHashSetFree(cpHashSet *set); int cpHashSetCount(cpHashSet *set); void *cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data, cpHashSetTransFunc trans); void *cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr); void *cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr); typedef void (*cpHashSetIteratorFunc)(void *elt, void *data); void cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data); typedef cpBool (*cpHashSetFilterFunc)(void *elt, void *data); void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data); //MARK: Body Functions void cpBodyAddShape(cpBody *body, cpShape *shape); void cpBodyRemoveShape(cpBody *body, cpShape *shape); void cpBodyRemoveConstraint(cpBody *body, cpConstraint *constraint); //MARK: Shape/Collision Functions // TODO should move this to the cpVect API. It's pretty useful. static inline cpVect cpClosetPointOnSegment(const cpVect p, const cpVect a, const cpVect b) { cpVect delta = cpvsub(a, b); cpFloat t = cpfclamp01(cpvdot(delta, cpvsub(p, b))/cpvlengthsq(delta)); return cpvadd(b, cpvmult(delta, t)); } cpShape* cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body); static inline cpBool cpShapeActive(cpShape *shape) { return shape->prev || (shape->body && shape->body->shapeList == shape); } int cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr); // TODO doesn't really need to be inline, but need a better place to put this function static inline cpSplittingPlane cpSplittingPlaneNew(cpVect a, cpVect b) { cpVect n = cpvnormalize(cpvperp(cpvsub(b, a))); cpSplittingPlane plane = {n, cpvdot(n, a)}; return plane; } static inline cpFloat cpSplittingPlaneCompare(cpSplittingPlane plane, cpVect v) { return cpvdot(plane.n, v) - plane.d; } void cpLoopIndexes(cpVect *verts, int count, int *start, int *end); static inline cpFloat cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d) { cpVect *verts = poly->tVerts; cpFloat min = cpvdot(n, verts[0]); for(int i=1; inumVerts; i++){ min = cpfmin(min, cpvdot(n, verts[i])); } return min - d; } static inline cpBool cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v) { cpSplittingPlane *planes = poly->tPlanes; for(int i=0; inumVerts; i++){ cpFloat dist = cpSplittingPlaneCompare(planes[i], v); if(dist > 0.0f) return cpFalse; } return cpTrue; } static inline cpBool cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n) { cpSplittingPlane *planes = poly->tPlanes; for(int i=0; inumVerts; i++){ if(cpvdot(planes[i].n, n) < 0.0f) continue; cpFloat dist = cpSplittingPlaneCompare(planes[i], v); if(dist > 0.0f) return cpFalse; } return cpTrue; } //MARK: Spatial Index Functions cpSpatialIndex *cpSpatialIndexInit(cpSpatialIndex *index, cpSpatialIndexClass *klass, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex); //MARK: Space Functions extern cpCollisionHandler cpDefaultCollisionHandler; void cpSpaceProcessComponents(cpSpace *space, cpFloat dt); void cpSpacePushFreshContactBuffer(cpSpace *space); cpContact *cpContactBufferGetArray(cpSpace *space); void cpSpacePushContacts(cpSpace *space, int count); typedef struct cpPostStepCallback { cpPostStepFunc func; void *key; void *data; } cpPostStepCallback; cpPostStepCallback *cpSpaceGetPostStepCallback(cpSpace *space, void *key); cpBool cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space); void cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter); void cpSpaceActivateBody(cpSpace *space, cpBody *body); void cpSpaceLock(cpSpace *space); void cpSpaceUnlock(cpSpace *space, cpBool runPostStep); static inline cpCollisionHandler * cpSpaceLookupHandler(cpSpace *space, cpCollisionType a, cpCollisionType b) { cpCollisionType types[] = {a, b}; return (cpCollisionHandler *)cpHashSetFind(space->collisionHandlers, CP_HASH_PAIR(a, b), types); } static inline void cpSpaceUncacheArbiter(cpSpace *space, cpArbiter *arb) { cpShape *a = arb->a, *b = arb->b; cpShape *shape_pair[] = {a, b}; cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b); cpHashSetRemove(space->cachedArbiters, arbHashID, shape_pair); cpArrayDeleteObj(space->arbiters, arb); } void cpShapeUpdateFunc(cpShape *shape, void *unused); void cpSpaceCollideShapes(cpShape *a, cpShape *b, cpSpace *space); //MARK: Arbiters struct cpContact { cpVect p, n; cpFloat dist; cpVect r1, r2; cpFloat nMass, tMass, bounce; cpFloat jnAcc, jtAcc, jBias; cpFloat bias; cpHashValue hash; }; cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash); cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b); static inline void cpArbiterCallSeparate(cpArbiter *arb, cpSpace *space) { // The handler needs to be looked up again as the handler cached on the arbiter may have been deleted since the last step. cpCollisionHandler *handler = cpSpaceLookupHandler(space, arb->a->collision_type, arb->b->collision_type); handler->separate(arb, space, handler->data); } static inline struct cpArbiterThread * cpArbiterThreadForBody(cpArbiter *arb, cpBody *body) { return (arb->body_a == body ? &arb->thread_a : &arb->thread_b); } void cpArbiterUnthread(cpArbiter *arb); void cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, struct cpCollisionHandler *handler, cpShape *a, cpShape *b); void cpArbiterPreStep(cpArbiter *arb, cpFloat dt, cpFloat bias, cpFloat slop); void cpArbiterApplyCachedImpulse(cpArbiter *arb, cpFloat dt_coef); void cpArbiterApplyImpulse(cpArbiter *arb); Chipmunk-6.1.5/include/chipmunk/chipmunk_types.h000644 000765 000000 00000010712 12151675775 022721 0ustar00slembckewheel000000 000000 #include #ifdef __APPLE__ #include "TargetConditionals.h" #endif #if ((TARGET_OS_IPHONE == 1) || (TARGET_OS_MAC == 1)) && (!defined CP_USE_CGPOINTS) #define CP_USE_CGPOINTS 1 #endif #if CP_USE_CGPOINTS == 1 #if TARGET_OS_IPHONE #import #elif TARGET_OS_MAC #include #endif #if defined(__LP64__) && __LP64__ #define CP_USE_DOUBLES 1 #else #define CP_USE_DOUBLES 0 #endif #endif #ifndef CP_USE_DOUBLES // use doubles by default for higher precision #define CP_USE_DOUBLES 1 #endif /// @defgroup basicTypes Basic Types /// Most of these types can be configured at compile time. /// @{ #if CP_USE_DOUBLES /// Chipmunk's floating point type. /// Can be reconfigured at compile time. typedef double cpFloat; #define cpfsqrt sqrt #define cpfsin sin #define cpfcos cos #define cpfacos acos #define cpfatan2 atan2 #define cpfmod fmod #define cpfexp exp #define cpfpow pow #define cpffloor floor #define cpfceil ceil #else typedef float cpFloat; #define cpfsqrt sqrtf #define cpfsin sinf #define cpfcos cosf #define cpfacos acosf #define cpfatan2 atan2f #define cpfmod fmodf #define cpfexp expf #define cpfpow powf #define cpffloor floorf #define cpfceil ceilf #endif #ifndef INFINITY #ifdef _MSC_VER union MSVC_EVIL_FLOAT_HACK { unsigned __int8 Bytes[4]; float Value; }; static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}}; #define INFINITY (INFINITY_HACK.Value) #endif #ifdef __GNUC__ #define INFINITY (__builtin_inf()) #endif #ifndef INFINITY #define INFINITY (1e1000) #endif #endif #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 #endif #ifndef M_E #define M_E 2.71828182845904523536028747135266250 #endif /// Return the max of two cpFloats. static inline cpFloat cpfmax(cpFloat a, cpFloat b) { return (a > b) ? a : b; } /// Return the min of two cpFloats. static inline cpFloat cpfmin(cpFloat a, cpFloat b) { return (a < b) ? a : b; } /// Return the absolute value of a cpFloat. static inline cpFloat cpfabs(cpFloat f) { return (f < 0) ? -f : f; } /// Clamp @c f to be between @c min and @c max. static inline cpFloat cpfclamp(cpFloat f, cpFloat min, cpFloat max) { return cpfmin(cpfmax(f, min), max); } /// Clamp @c f to be between 0 and 1. static inline cpFloat cpfclamp01(cpFloat f) { return cpfmax(0.0f, cpfmin(f, 1.0f)); } /// Linearly interpolate (or extrapolate) between @c f1 and @c f2 by @c t percent. static inline cpFloat cpflerp(cpFloat f1, cpFloat f2, cpFloat t) { return f1*(1.0f - t) + f2*t; } /// Linearly interpolate from @c f1 to @c f2 by no more than @c d. static inline cpFloat cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d) { return f1 + cpfclamp(f2 - f1, -d, d); } /// Hash value type. typedef uintptr_t cpHashValue; // Oh C, how we love to define our own boolean types to get compiler compatibility /// Chipmunk's boolean type. #ifdef CP_BOOL_TYPE typedef CP_BOOL_TYPE cpBool; #else typedef int cpBool; #endif #ifndef cpTrue /// true value. #define cpTrue 1 #endif #ifndef cpFalse /// false value. #define cpFalse 0 #endif #ifdef CP_DATA_POINTER_TYPE typedef CP_DATA_POINTER_TYPE cpDataPointer; #else /// Type used for user data pointers. typedef void * cpDataPointer; #endif #ifdef CP_COLLISION_TYPE_TYPE typedef CP_COLLISION_TYPE_TYPE cpCollisionType; #else /// Type used for cpSpace.collision_type. typedef uintptr_t cpCollisionType; #endif #ifdef CP_GROUP_TYPE typedef CP_GROUP_TYPE cpGroup; #else /// Type used for cpShape.group. typedef uintptr_t cpGroup; #endif #ifdef CP_LAYERS_TYPE typedef CP_LAYERS_TYPE cpLayers; #else /// Type used for cpShape.layers. typedef unsigned int cpLayers; #endif #ifdef CP_TIMESTAMP_TYPE typedef CP_TIMESTAMP_TYPE cpTimestamp; #else /// Type used for various timestamps in Chipmunk. typedef unsigned int cpTimestamp; #endif #ifndef CP_NO_GROUP /// Value for cpShape.group signifying that a shape is in no group. #define CP_NO_GROUP ((cpGroup)0) #endif #ifndef CP_ALL_LAYERS /// Value for cpShape.layers signifying that a shape is in every layer. #define CP_ALL_LAYERS (~(cpLayers)0) #endif /// @} // CGPoints are structurally the same, and allow // easy interoperability with other Cocoa libraries #if CP_USE_CGPOINTS typedef CGPoint cpVect; #else /// Chipmunk's 2D vector type. /// @addtogroup cpVect typedef struct cpVect{cpFloat x,y;} cpVect; #endif typedef struct cpMat2x2 { // Row major [[a, b][c d]] cpFloat a, b, c, d; } cpMat2x2; Chipmunk-6.1.5/include/chipmunk/chipmunk_unsafe.h000644 000765 000000 00000005165 12151675775 023044 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* This header defines a number of "unsafe" operations on Chipmunk objects. * In this case "unsafe" is referring to operations which may reduce the * physical accuracy or numerical stability of the simulation, but will not * cause crashes. * * The prime example is mutating collision shapes. Chipmunk does not support * this directly. Mutating shapes using this API will caused objects in contact * to be pushed apart using Chipmunk's overlap solver, but not using real * persistent velocities. Probably not what you meant, but perhaps close enough. */ /// @defgroup unsafe Chipmunk Unsafe Shape Operations /// These functions are used for mutating collision shapes. /// Chipmunk does not have any way to get velocity information on changing shapes, /// so the results will be unrealistic. You must explicity include the chipmunk_unsafe.h header to use them. /// @{ #ifndef CHIPMUNK_UNSAFE_HEADER #define CHIPMUNK_UNSAFE_HEADER #ifdef __cplusplus extern "C" { #endif /// Set the radius of a circle shape. void cpCircleShapeSetRadius(cpShape *shape, cpFloat radius); /// Set the offset of a circle shape. void cpCircleShapeSetOffset(cpShape *shape, cpVect offset); /// Set the endpoints of a segment shape. void cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b); /// Set the radius of a segment shape. void cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius); /// Set the vertexes of a poly shape. void cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset); #ifdef __cplusplus } #endif #endif /// @} Chipmunk-6.1.5/include/chipmunk/constraints/000755 000765 000000 00000000000 12151675775 022054 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/include/chipmunk/cpArbiter.h000644 000765 000000 00000021122 12151675775 021567 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpArbiter cpArbiter /// The cpArbiter struct controls pairs of colliding shapes. /// They are also used in conjuction with collision handler callbacks /// allowing you to retrieve information on the collision and control it. /// @{ /// Collision begin event function callback type. /// Returning false from a begin callback causes the collision to be ignored until /// the the separate callback is called when the objects stop colliding. typedef cpBool (*cpCollisionBeginFunc)(cpArbiter *arb, cpSpace *space, void *data); /// Collision pre-solve event function callback type. /// Returning false from a pre-step callback causes the collision to be ignored until the next step. typedef cpBool (*cpCollisionPreSolveFunc)(cpArbiter *arb, cpSpace *space, void *data); /// Collision post-solve event function callback type. typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, cpSpace *space, void *data); /// Collision separate event function callback type. typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, cpSpace *space, void *data); /// @private struct cpCollisionHandler { cpCollisionType a; cpCollisionType b; cpCollisionBeginFunc begin; cpCollisionPreSolveFunc preSolve; cpCollisionPostSolveFunc postSolve; cpCollisionSeparateFunc separate; void *data; }; typedef struct cpContact cpContact; #define CP_MAX_CONTACTS_PER_ARBITER 4 /// @private typedef enum cpArbiterState { // Arbiter is active and its the first collision. cpArbiterStateFirstColl, // Arbiter is active and its not the first collision. cpArbiterStateNormal, // Collision has been explicitly ignored. // Either by returning false from a begin collision handler or calling cpArbiterIgnore(). cpArbiterStateIgnore, // Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps. cpArbiterStateCached, } cpArbiterState; /// @private struct cpArbiterThread { // Links to next and previous arbiters in the contact graph. struct cpArbiter *next, *prev; }; /// A colliding pair of shapes. struct cpArbiter { /// Calculated value to use for the elasticity coefficient. /// Override in a pre-solve collision handler for custom behavior. cpFloat e; /// Calculated value to use for the friction coefficient. /// Override in a pre-solve collision handler for custom behavior. cpFloat u; /// Calculated value to use for applying surface velocities. /// Override in a pre-solve collision handler for custom behavior. cpVect surface_vr; /// User definable data pointer. /// The value will persist for the pair of shapes until the separate() callback is called. /// NOTE: If you need to clean up this pointer, you should implement the separate() callback to do it. cpDataPointer data; CP_PRIVATE(cpShape *a); CP_PRIVATE(cpShape *b); CP_PRIVATE(cpBody *body_a); CP_PRIVATE(cpBody *body_b); CP_PRIVATE(struct cpArbiterThread thread_a); CP_PRIVATE(struct cpArbiterThread thread_b); CP_PRIVATE(int numContacts); CP_PRIVATE(cpContact *contacts); CP_PRIVATE(cpTimestamp stamp); CP_PRIVATE(cpCollisionHandler *handler); CP_PRIVATE(cpBool swappedColl); CP_PRIVATE(cpArbiterState state); }; #define CP_DefineArbiterStructGetter(type, member, name) \ static inline type cpArbiterGet##name(const cpArbiter *arb){return arb->member;} #define CP_DefineArbiterStructSetter(type, member, name) \ static inline void cpArbiterSet##name(cpArbiter *arb, type value){arb->member = value;} #define CP_DefineArbiterStructProperty(type, member, name) \ CP_DefineArbiterStructGetter(type, member, name) \ CP_DefineArbiterStructSetter(type, member, name) CP_DefineArbiterStructProperty(cpFloat, e, Elasticity) CP_DefineArbiterStructProperty(cpFloat, u, Friction) // Get the relative surface velocity of the two shapes in contact. cpVect cpArbiterGetSurfaceVelocity(cpArbiter *arb); // Override the relative surface velocity of the two shapes in contact. // By default this is calculated to be the difference of the two // surface velocities clamped to the tangent plane. void cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect vr); CP_DefineArbiterStructProperty(cpDataPointer, data, UserData) /// Calculate the total impulse that was applied by this arbiter. /// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback. cpVect cpArbiterTotalImpulse(const cpArbiter *arb); /// Calculate the total impulse including the friction that was applied by this arbiter. /// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback. cpVect cpArbiterTotalImpulseWithFriction(const cpArbiter *arb); /// Calculate the amount of energy lost in a collision including static, but not dynamic friction. /// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback. cpFloat cpArbiterTotalKE(const cpArbiter *arb); /// Causes a collision pair to be ignored as if you returned false from a begin callback. /// If called from a pre-step callback, you will still need to return false /// if you want it to be ignored in the current step. void cpArbiterIgnore(cpArbiter *arb); /// Return the colliding shapes involved for this arbiter. /// The order of their cpSpace.collision_type values will match /// the order set when the collision handler was registered. static inline void cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape **b) { if(arb->CP_PRIVATE(swappedColl)){ (*a) = arb->CP_PRIVATE(b), (*b) = arb->CP_PRIVATE(a); } else { (*a) = arb->CP_PRIVATE(a), (*b) = arb->CP_PRIVATE(b); } } /// A macro shortcut for defining and retrieving the shapes from an arbiter. #define CP_ARBITER_GET_SHAPES(__arb__, __a__, __b__) cpShape *__a__, *__b__; cpArbiterGetShapes(__arb__, &__a__, &__b__); /// Return the colliding bodies involved for this arbiter. /// The order of the cpSpace.collision_type the bodies are associated with values will match /// the order set when the collision handler was registered. static inline void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody **b) { CP_ARBITER_GET_SHAPES(arb, shape_a, shape_b); (*a) = shape_a->body; (*b) = shape_b->body; } /// A macro shortcut for defining and retrieving the bodies from an arbiter. #define CP_ARBITER_GET_BODIES(__arb__, __a__, __b__) cpBody *__a__, *__b__; cpArbiterGetBodies(__arb__, &__a__, &__b__); /// A struct that wraps up the important collision data for an arbiter. typedef struct cpContactPointSet { /// The number of contact points in the set. int count; /// The array of contact points. struct { /// The position of the contact point. cpVect point; /// The normal of the contact point. cpVect normal; /// The depth of the contact point. cpFloat dist; } points[CP_MAX_CONTACTS_PER_ARBITER]; } cpContactPointSet; /// Return a contact set from an arbiter. cpContactPointSet cpArbiterGetContactPointSet(const cpArbiter *arb); /// Replace the contact point set for an arbiter. /// This can be a very powerful feature, but use it with caution! void cpArbiterSetContactPointSet(cpArbiter *arb, cpContactPointSet *set); /// Returns true if this is the first step a pair of objects started colliding. cpBool cpArbiterIsFirstContact(const cpArbiter *arb); /// Get the number of contact points for this arbiter. int cpArbiterGetCount(const cpArbiter *arb); /// Get the normal of the @c ith contact point. cpVect cpArbiterGetNormal(const cpArbiter *arb, int i); /// Get the position of the @c ith contact point. cpVect cpArbiterGetPoint(const cpArbiter *arb, int i); /// Get the depth of the @c ith contact point. cpFloat cpArbiterGetDepth(const cpArbiter *arb, int i); /// @} Chipmunk-6.1.5/include/chipmunk/cpBB.h000644 000765 000000 00000010573 12151675775 020472 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpBBB cpBB /// Chipmunk's axis-aligned 2D bounding box type along with a few handy routines. /// @{ /// Chipmunk's axis-aligned 2D bounding box type. (left, bottom, right, top) typedef struct cpBB{ cpFloat l, b, r ,t; } cpBB; /// Convenience constructor for cpBB structs. static inline cpBB cpBBNew(const cpFloat l, const cpFloat b, const cpFloat r, const cpFloat t) { cpBB bb = {l, b, r, t}; return bb; } /// Constructs a cpBB for a circle with the given position and radius. static inline cpBB cpBBNewForCircle(const cpVect p, const cpFloat r) { return cpBBNew(p.x - r, p.y - r, p.x + r, p.y + r); } /// Returns true if @c a and @c b intersect. static inline cpBool cpBBIntersects(const cpBB a, const cpBB b) { return (a.l <= b.r && b.l <= a.r && a.b <= b.t && b.b <= a.t); } /// Returns true if @c other lies completely within @c bb. static inline cpBool cpBBContainsBB(const cpBB bb, const cpBB other) { return (bb.l <= other.l && bb.r >= other.r && bb.b <= other.b && bb.t >= other.t); } /// Returns true if @c bb contains @c v. static inline cpBool cpBBContainsVect(const cpBB bb, const cpVect v) { return (bb.l <= v.x && bb.r >= v.x && bb.b <= v.y && bb.t >= v.y); } /// Returns a bounding box that holds both bounding boxes. static inline cpBB cpBBMerge(const cpBB a, const cpBB b){ return cpBBNew( cpfmin(a.l, b.l), cpfmin(a.b, b.b), cpfmax(a.r, b.r), cpfmax(a.t, b.t) ); } /// Returns a bounding box that holds both @c bb and @c v. static inline cpBB cpBBExpand(const cpBB bb, const cpVect v){ return cpBBNew( cpfmin(bb.l, v.x), cpfmin(bb.b, v.y), cpfmax(bb.r, v.x), cpfmax(bb.t, v.y) ); } /// Returns the area of the bounding box. static inline cpFloat cpBBArea(cpBB bb) { return (bb.r - bb.l)*(bb.t - bb.b); } /// Merges @c a and @c b and returns the area of the merged bounding box. static inline cpFloat cpBBMergedArea(cpBB a, cpBB b) { return (cpfmax(a.r, b.r) - cpfmin(a.l, b.l))*(cpfmax(a.t, b.t) - cpfmin(a.b, b.b)); } /// Returns the fraction along the segment query the cpBB is hit. Returns INFINITY if it doesn't hit. static inline cpFloat cpBBSegmentQuery(cpBB bb, cpVect a, cpVect b) { cpFloat idx = 1.0f/(b.x - a.x); cpFloat tx1 = (bb.l == a.x ? -INFINITY : (bb.l - a.x)*idx); cpFloat tx2 = (bb.r == a.x ? INFINITY : (bb.r - a.x)*idx); cpFloat txmin = cpfmin(tx1, tx2); cpFloat txmax = cpfmax(tx1, tx2); cpFloat idy = 1.0f/(b.y - a.y); cpFloat ty1 = (bb.b == a.y ? -INFINITY : (bb.b - a.y)*idy); cpFloat ty2 = (bb.t == a.y ? INFINITY : (bb.t - a.y)*idy); cpFloat tymin = cpfmin(ty1, ty2); cpFloat tymax = cpfmax(ty1, ty2); if(tymin <= txmax && txmin <= tymax){ cpFloat min = cpfmax(txmin, tymin); cpFloat max = cpfmin(txmax, tymax); if(0.0 <= max && min <= 1.0) return cpfmax(min, 0.0); } return INFINITY; } /// Return true if the bounding box intersects the line segment with ends @c a and @c b. static inline cpBool cpBBIntersectsSegment(cpBB bb, cpVect a, cpVect b) { return (cpBBSegmentQuery(bb, a, b) != INFINITY); } /// Clamp a vector to a bounding box. static inline cpVect cpBBClampVect(const cpBB bb, const cpVect v) { return cpv(cpfclamp(v.x, bb.l, bb.r), cpfclamp(v.y, bb.b, bb.t)); } // TODO edge case issue /// Wrap a vector to a bounding box. cpVect cpBBWrapVect(const cpBB bb, const cpVect v); // wrap a vector to a bbox ///@} Chipmunk-6.1.5/include/chipmunk/cpBody.h000644 000765 000000 00000022562 12151675775 021105 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpBody cpBody /// Chipmunk's rigid body type. Rigid bodies hold the physical properties of an object like /// it's mass, and position and velocity of it's center of gravity. They don't have an shape on their own. /// They are given a shape by creating collision shapes (cpShape) that point to the body. /// @{ /// Rigid body velocity update function type. typedef void (*cpBodyVelocityFunc)(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt); /// Rigid body position update function type. typedef void (*cpBodyPositionFunc)(cpBody *body, cpFloat dt); /// Used internally to track information on the collision graph. /// @private typedef struct cpComponentNode { cpBody *root; cpBody *next; cpFloat idleTime; } cpComponentNode; /// Chipmunk's rigid body struct. struct cpBody { /// Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity) cpBodyVelocityFunc velocity_func; /// Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition) cpBodyPositionFunc position_func; /// Mass of the body. /// Must agree with cpBody.m_inv! Use cpBodySetMass() when changing the mass for this reason. cpFloat m; /// Mass inverse. cpFloat m_inv; /// Moment of inertia of the body. /// Must agree with cpBody.i_inv! Use cpBodySetMoment() when changing the moment for this reason. cpFloat i; /// Moment of inertia inverse. cpFloat i_inv; /// Position of the rigid body's center of gravity. cpVect p; /// Velocity of the rigid body's center of gravity. cpVect v; /// Force acting on the rigid body's center of gravity. cpVect f; /// Rotation of the body around it's center of gravity in radians. /// Must agree with cpBody.rot! Use cpBodySetAngle() when changing the angle for this reason. cpFloat a; /// Angular velocity of the body around it's center of gravity in radians/second. cpFloat w; /// Torque applied to the body around it's center of gravity. cpFloat t; /// Cached unit length vector representing the angle of the body. /// Used for fast rotations using cpvrotate(). cpVect rot; /// User definable data pointer. /// Generally this points to your the game object class so you can access it /// when given a cpBody reference in a callback. cpDataPointer data; /// Maximum velocity allowed when updating the velocity. cpFloat v_limit; /// Maximum rotational rate (in radians/second) allowed when updating the angular velocity. cpFloat w_limit; CP_PRIVATE(cpVect v_bias); CP_PRIVATE(cpFloat w_bias); CP_PRIVATE(cpSpace *space); CP_PRIVATE(cpShape *shapeList); CP_PRIVATE(cpArbiter *arbiterList); CP_PRIVATE(cpConstraint *constraintList); CP_PRIVATE(cpComponentNode node); }; /// Allocate a cpBody. cpBody* cpBodyAlloc(void); /// Initialize a cpBody. cpBody* cpBodyInit(cpBody *body, cpFloat m, cpFloat i); /// Allocate and initialize a cpBody. cpBody* cpBodyNew(cpFloat m, cpFloat i); /// Initialize a static cpBody. cpBody* cpBodyInitStatic(cpBody *body); /// Allocate and initialize a static cpBody. cpBody* cpBodyNewStatic(void); /// Destroy a cpBody. void cpBodyDestroy(cpBody *body); /// Destroy and free a cpBody. void cpBodyFree(cpBody *body); /// Check that the properties of a body is sane. (Only in debug mode) #ifdef NDEBUG #define cpBodyAssertSane(body) #else void cpBodySanityCheck(cpBody *body); #define cpBodyAssertSane(body) cpBodySanityCheck(body) #endif // Defined in cpSpace.c /// Wake up a sleeping or idle body. void cpBodyActivate(cpBody *body); /// Wake up any sleeping or idle bodies touching a static body. void cpBodyActivateStatic(cpBody *body, cpShape *filter); /// Force a body to fall asleep immediately. void cpBodySleep(cpBody *body); /// Force a body to fall asleep immediately along with other bodies in a group. void cpBodySleepWithGroup(cpBody *body, cpBody *group); /// Returns true if the body is sleeping. static inline cpBool cpBodyIsSleeping(const cpBody *body) { return (CP_PRIVATE(body->node).root != ((cpBody*)0)); } /// Returns true if the body is static. static inline cpBool cpBodyIsStatic(const cpBody *body) { return CP_PRIVATE(body->node).idleTime == INFINITY; } /// Returns true if the body has not been added to a space. /// Note: Static bodies are a subtype of rogue bodies. static inline cpBool cpBodyIsRogue(const cpBody *body) { return (body->CP_PRIVATE(space) == ((cpSpace*)0)); } #define CP_DefineBodyStructGetter(type, member, name) \ static inline type cpBodyGet##name(const cpBody *body){return body->member;} #define CP_DefineBodyStructSetter(type, member, name) \ static inline void cpBodySet##name(cpBody *body, const type value){ \ cpBodyActivate(body); \ body->member = value; \ cpBodyAssertSane(body); \ } #define CP_DefineBodyStructProperty(type, member, name) \ CP_DefineBodyStructGetter(type, member, name) \ CP_DefineBodyStructSetter(type, member, name) // TODO add to docs CP_DefineBodyStructGetter(cpSpace*, CP_PRIVATE(space), Space) CP_DefineBodyStructGetter(cpFloat, m, Mass) /// Set the mass of a body. void cpBodySetMass(cpBody *body, cpFloat m); CP_DefineBodyStructGetter(cpFloat, i, Moment) /// Set the moment of a body. void cpBodySetMoment(cpBody *body, cpFloat i); CP_DefineBodyStructGetter(cpVect, p, Pos) /// Set the position of a body. void cpBodySetPos(cpBody *body, cpVect pos); CP_DefineBodyStructProperty(cpVect, v, Vel) CP_DefineBodyStructProperty(cpVect, f, Force) CP_DefineBodyStructGetter(cpFloat, a, Angle) /// Set the angle of a body. void cpBodySetAngle(cpBody *body, cpFloat a); CP_DefineBodyStructProperty(cpFloat, w, AngVel) CP_DefineBodyStructProperty(cpFloat, t, Torque) CP_DefineBodyStructGetter(cpVect, rot, Rot) CP_DefineBodyStructProperty(cpFloat, v_limit, VelLimit) CP_DefineBodyStructProperty(cpFloat, w_limit, AngVelLimit) CP_DefineBodyStructProperty(cpDataPointer, data, UserData) /// Default Integration functions. void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt); void cpBodyUpdatePosition(cpBody *body, cpFloat dt); /// Convert body relative/local coordinates to absolute/world coordinates. static inline cpVect cpBodyLocal2World(const cpBody *body, const cpVect v) { return cpvadd(body->p, cpvrotate(v, body->rot)); } /// Convert body absolute/world coordinates to relative/local coordinates. static inline cpVect cpBodyWorld2Local(const cpBody *body, const cpVect v) { return cpvunrotate(cpvsub(v, body->p), body->rot); } /// Set the forces and torque or a body to zero. void cpBodyResetForces(cpBody *body); /// Apply an force (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates). void cpBodyApplyForce(cpBody *body, const cpVect f, const cpVect r); /// Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates). void cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r); /// Get the velocity on a body (in world units) at a point on the body in world coordinates. cpVect cpBodyGetVelAtWorldPoint(cpBody *body, cpVect point); /// Get the velocity on a body (in world units) at a point on the body in local coordinates. cpVect cpBodyGetVelAtLocalPoint(cpBody *body, cpVect point); /// Get the kinetic energy of a body. static inline cpFloat cpBodyKineticEnergy(const cpBody *body) { // Need to do some fudging to avoid NaNs cpFloat vsq = cpvdot(body->v, body->v); cpFloat wsq = body->w*body->w; return (vsq ? vsq*body->m : 0.0f) + (wsq ? wsq*body->i : 0.0f); } /// Body/shape iterator callback function type. typedef void (*cpBodyShapeIteratorFunc)(cpBody *body, cpShape *shape, void *data); /// Call @c func once for each shape attached to @c body and added to the space. void cpBodyEachShape(cpBody *body, cpBodyShapeIteratorFunc func, void *data); /// Body/constraint iterator callback function type. typedef void (*cpBodyConstraintIteratorFunc)(cpBody *body, cpConstraint *constraint, void *data); /// Call @c func once for each constraint attached to @c body and added to the space. void cpBodyEachConstraint(cpBody *body, cpBodyConstraintIteratorFunc func, void *data); /// Body/arbiter iterator callback function type. typedef void (*cpBodyArbiterIteratorFunc)(cpBody *body, cpArbiter *arbiter, void *data); /// Call @c func once for each arbiter that is currently active on the body. void cpBodyEachArbiter(cpBody *body, cpBodyArbiterIteratorFunc func, void *data); ///@} Chipmunk-6.1.5/include/chipmunk/cpPolyShape.h000644 000765 000000 00000005365 12151675775 022116 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpPolyShape cpPolyShape /// @{ /// @private typedef struct cpSplittingPlane { cpVect n; cpFloat d; } cpSplittingPlane; /// @private typedef struct cpPolyShape { cpShape shape; int numVerts; cpVect *verts, *tVerts; cpSplittingPlane *planes, *tPlanes; } cpPolyShape; /// Allocate a polygon shape. cpPolyShape* cpPolyShapeAlloc(void); /// Initialize a polygon shape. /// A convex hull will be created from the vertexes. cpPolyShape* cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, const cpVect *verts, cpVect offset); /// Allocate and initialize a polygon shape. /// A convex hull will be created from the vertexes. cpShape* cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset); /// Initialize a box shaped polygon shape. cpPolyShape* cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height); /// Initialize an offset box shaped polygon shape. cpPolyShape* cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box); /// Allocate and initialize a box shaped polygon shape. cpShape* cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height); /// Allocate and initialize an offset box shaped polygon shape. cpShape* cpBoxShapeNew2(cpBody *body, cpBB box); /// Check that a set of vertexes is convex and has a clockwise winding. /// NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate! cpBool cpPolyValidate(const cpVect *verts, const int numVerts); /// Get the number of verts in a polygon shape. int cpPolyShapeGetNumVerts(cpShape *shape); /// Get the @c ith vertex of a polygon shape. cpVect cpPolyShapeGetVert(cpShape *shape, int idx); /// @} Chipmunk-6.1.5/include/chipmunk/cpShape.h000644 000765 000000 00000020033 12151675775 021237 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpShape cpShape /// The cpShape struct defines the shape of a rigid body. /// @{ typedef struct cpShapeClass cpShapeClass; /// Nearest point query info struct. typedef struct cpNearestPointQueryInfo { /// The nearest shape, NULL if no shape was within range. cpShape *shape; /// The closest point on the shape's surface. (in world space coordinates) cpVect p; /// The distance to the point. The distance is negative if the point is inside the shape. cpFloat d; } cpNearestPointQueryInfo; /// Segment query info struct. typedef struct cpSegmentQueryInfo { /// The shape that was hit, NULL if no collision occured. cpShape *shape; /// The normalized distance along the query segment in the range [0, 1]. cpFloat t; /// The normal of the surface hit. cpVect n; } cpSegmentQueryInfo; /// @private typedef enum cpShapeType{ CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES } cpShapeType; typedef cpBB (*cpShapeCacheDataImpl)(cpShape *shape, cpVect p, cpVect rot); typedef void (*cpShapeDestroyImpl)(cpShape *shape); typedef void (*cpShapeNearestPointQueryImpl)(cpShape *shape, cpVect p, cpNearestPointQueryInfo *info); typedef void (*cpShapeSegmentQueryImpl)(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info); /// @private struct cpShapeClass { cpShapeType type; cpShapeCacheDataImpl cacheData; cpShapeDestroyImpl destroy; cpShapeNearestPointQueryImpl nearestPointQuery; cpShapeSegmentQueryImpl segmentQuery; }; /// Opaque collision shape struct. struct cpShape { CP_PRIVATE(const cpShapeClass *klass); /// The rigid body this collision shape is attached to. cpBody *body; /// The current bounding box of the shape. cpBB bb; /// Sensor flag. /// Sensor shapes call collision callbacks but don't produce collisions. cpBool sensor; /// Coefficient of restitution. (elasticity) cpFloat e; /// Coefficient of friction. cpFloat u; /// Surface velocity used when solving for friction. cpVect surface_v; /// User definable data pointer. /// Generally this points to your the game object class so you can access it /// when given a cpShape reference in a callback. cpDataPointer data; /// Collision type of this shape used when picking collision handlers. cpCollisionType collision_type; /// Group of this shape. Shapes in the same group don't collide. cpGroup group; // Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero. cpLayers layers; CP_PRIVATE(cpSpace *space); CP_PRIVATE(cpShape *next); CP_PRIVATE(cpShape *prev); CP_PRIVATE(cpHashValue hashid); }; /// Destroy a shape. void cpShapeDestroy(cpShape *shape); /// Destroy and Free a shape. void cpShapeFree(cpShape *shape); /// Update, cache and return the bounding box of a shape based on the body it's attached to. cpBB cpShapeCacheBB(cpShape *shape); /// Update, cache and return the bounding box of a shape with an explicit transformation. cpBB cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot); /// Test if a point lies within a shape. cpBool cpShapePointQuery(cpShape *shape, cpVect p); /// Perform a nearest point query. It finds the closest point on the surface of shape to a specific point. /// The value returned is the distance between the points. A negative distance means the point is inside the shape. cpFloat cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *out); /// Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure. cpBool cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info); /// Get the hit point for a segment query. static inline cpVect cpSegmentQueryHitPoint(const cpVect start, const cpVect end, const cpSegmentQueryInfo info) { return cpvlerp(start, end, info.t); } /// Get the hit distance for a segment query. static inline cpFloat cpSegmentQueryHitDist(const cpVect start, const cpVect end, const cpSegmentQueryInfo info) { return cpvdist(start, end)*info.t; } #define CP_DefineShapeStructGetter(type, member, name) \ static inline type cpShapeGet##name(const cpShape *shape){return shape->member;} #define CP_DefineShapeStructSetter(type, member, name, activates) \ static inline void cpShapeSet##name(cpShape *shape, type value){ \ if(activates && shape->body) cpBodyActivate(shape->body); \ shape->member = value; \ } #define CP_DefineShapeStructProperty(type, member, name, activates) \ CP_DefineShapeStructGetter(type, member, name) \ CP_DefineShapeStructSetter(type, member, name, activates) CP_DefineShapeStructGetter(cpSpace*, CP_PRIVATE(space), Space) CP_DefineShapeStructGetter(cpBody*, body, Body) void cpShapeSetBody(cpShape *shape, cpBody *body); CP_DefineShapeStructGetter(cpBB, bb, BB) CP_DefineShapeStructProperty(cpBool, sensor, Sensor, cpTrue) CP_DefineShapeStructProperty(cpFloat, e, Elasticity, cpFalse) CP_DefineShapeStructProperty(cpFloat, u, Friction, cpTrue) CP_DefineShapeStructProperty(cpVect, surface_v, SurfaceVelocity, cpTrue) CP_DefineShapeStructProperty(cpDataPointer, data, UserData, cpFalse) CP_DefineShapeStructProperty(cpCollisionType, collision_type, CollisionType, cpTrue) CP_DefineShapeStructProperty(cpGroup, group, Group, cpTrue) CP_DefineShapeStructProperty(cpLayers, layers, Layers, cpTrue) /// When initializing a shape, it's hash value comes from a counter. /// Because the hash value may affect iteration order, you can reset the shape ID counter /// when recreating a space. This will make the simulation be deterministic. void cpResetShapeIdCounter(void); #define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(const cpShape *shape) /// @} /// @defgroup cpCircleShape cpCircleShape /// @private typedef struct cpCircleShape { cpShape shape; cpVect c, tc; cpFloat r; } cpCircleShape; /// Allocate a circle shape. cpCircleShape* cpCircleShapeAlloc(void); /// Initialize a circle shape. cpCircleShape* cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset); /// Allocate and initialize a circle shape. cpShape* cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset); CP_DeclareShapeGetter(cpCircleShape, cpVect, Offset); CP_DeclareShapeGetter(cpCircleShape, cpFloat, Radius); /// @} /// @defgroup cpSegmentShape cpSegmentShape /// @private typedef struct cpSegmentShape { cpShape shape; cpVect a, b, n; cpVect ta, tb, tn; cpFloat r; cpVect a_tangent, b_tangent; } cpSegmentShape; /// Allocate a segment shape. cpSegmentShape* cpSegmentShapeAlloc(void); /// Initialize a segment shape. cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius); /// Allocate and initialize a segment shape. cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius); void cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next); CP_DeclareShapeGetter(cpSegmentShape, cpVect, A); CP_DeclareShapeGetter(cpSegmentShape, cpVect, B); CP_DeclareShapeGetter(cpSegmentShape, cpVect, Normal); CP_DeclareShapeGetter(cpSegmentShape, cpFloat, Radius); /// @} Chipmunk-6.1.5/include/chipmunk/cpSpace.h000644 000765 000000 00000032672 12151675775 021246 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpSpace cpSpace /// @{ typedef struct cpContactBufferHeader cpContactBufferHeader; typedef void (*cpSpaceArbiterApplyImpulseFunc)(cpArbiter *arb); /// Basic Unit of Simulation in Chipmunk struct cpSpace { /// Number of iterations to use in the impulse solver to solve contacts. int iterations; /// Gravity to pass to rigid bodies when integrating velocity. cpVect gravity; /// Damping rate expressed as the fraction of velocity bodies retain each second. /// A value of 0.9 would mean that each body's velocity will drop 10% per second. /// The default value is 1.0, meaning no damping is applied. /// @note This damping value is different than those of cpDampedSpring and cpDampedRotarySpring. cpFloat damping; /// Speed threshold for a body to be considered idle. /// The default value of 0 means to let the space guess a good threshold based on gravity. cpFloat idleSpeedThreshold; /// Time a group of bodies must remain idle in order to fall asleep. /// Enabling sleeping also implicitly enables the the contact graph. /// The default value of INFINITY disables the sleeping algorithm. cpFloat sleepTimeThreshold; /// Amount of encouraged penetration between colliding shapes. /// Used to reduce oscillating contacts and keep the collision cache warm. /// Defaults to 0.1. If you have poor simulation quality, /// increase this number as much as possible without allowing visible amounts of overlap. cpFloat collisionSlop; /// Determines how fast overlapping shapes are pushed apart. /// Expressed as a fraction of the error remaining after each second. /// Defaults to pow(1.0 - 0.1, 60.0) meaning that Chipmunk fixes 10% of overlap each frame at 60Hz. cpFloat collisionBias; /// Number of frames that contact information should persist. /// Defaults to 3. There is probably never a reason to change this value. cpTimestamp collisionPersistence; /// Rebuild the contact graph during each step. Must be enabled to use the cpBodyEachArbiter() function. /// Disabled by default for a small performance boost. Enabled implicitly when the sleeping feature is enabled. cpBool enableContactGraph; /// User definable data pointer. /// Generally this points to your game's controller or game state /// class so you can access it when given a cpSpace reference in a callback. cpDataPointer data; /// The designated static body for this space. /// You can modify this body, or replace it with your own static body. /// By default it points to a statically allocated cpBody in the cpSpace struct. cpBody *staticBody; CP_PRIVATE(cpTimestamp stamp); CP_PRIVATE(cpFloat curr_dt); CP_PRIVATE(cpArray *bodies); CP_PRIVATE(cpArray *rousedBodies); CP_PRIVATE(cpArray *sleepingComponents); CP_PRIVATE(cpSpatialIndex *staticShapes); CP_PRIVATE(cpSpatialIndex *activeShapes); CP_PRIVATE(cpArray *arbiters); CP_PRIVATE(cpContactBufferHeader *contactBuffersHead); CP_PRIVATE(cpHashSet *cachedArbiters); CP_PRIVATE(cpArray *pooledArbiters); CP_PRIVATE(cpArray *constraints); CP_PRIVATE(cpArray *allocatedBuffers); CP_PRIVATE(int locked); CP_PRIVATE(cpHashSet *collisionHandlers); CP_PRIVATE(cpCollisionHandler defaultHandler); CP_PRIVATE(cpBool skipPostStep); CP_PRIVATE(cpArray *postStepCallbacks); CP_PRIVATE(cpBody _staticBody); }; /// Allocate a cpSpace. cpSpace* cpSpaceAlloc(void); /// Initialize a cpSpace. cpSpace* cpSpaceInit(cpSpace *space); /// Allocate and initialize a cpSpace. cpSpace* cpSpaceNew(void); /// Destroy a cpSpace. void cpSpaceDestroy(cpSpace *space); /// Destroy and free a cpSpace. void cpSpaceFree(cpSpace *space); #define CP_DefineSpaceStructGetter(type, member, name) \ static inline type cpSpaceGet##name(const cpSpace *space){return space->member;} #define CP_DefineSpaceStructSetter(type, member, name) \ static inline void cpSpaceSet##name(cpSpace *space, type value){space->member = value;} #define CP_DefineSpaceStructProperty(type, member, name) \ CP_DefineSpaceStructGetter(type, member, name) \ CP_DefineSpaceStructSetter(type, member, name) CP_DefineSpaceStructProperty(int, iterations, Iterations) CP_DefineSpaceStructProperty(cpVect, gravity, Gravity) CP_DefineSpaceStructProperty(cpFloat, damping, Damping) CP_DefineSpaceStructProperty(cpFloat, idleSpeedThreshold, IdleSpeedThreshold) CP_DefineSpaceStructProperty(cpFloat, sleepTimeThreshold, SleepTimeThreshold) CP_DefineSpaceStructProperty(cpFloat, collisionSlop, CollisionSlop) CP_DefineSpaceStructProperty(cpFloat, collisionBias, CollisionBias) CP_DefineSpaceStructProperty(cpTimestamp, collisionPersistence, CollisionPersistence) CP_DefineSpaceStructProperty(cpBool, enableContactGraph, EnableContactGraph) CP_DefineSpaceStructProperty(cpDataPointer, data, UserData) CP_DefineSpaceStructGetter(cpBody*, staticBody, StaticBody) CP_DefineSpaceStructGetter(cpFloat, CP_PRIVATE(curr_dt), CurrentTimeStep) /// returns true from inside a callback and objects cannot be added/removed. static inline cpBool cpSpaceIsLocked(cpSpace *space) { return space->CP_PRIVATE(locked); } /// Set a default collision handler for this space. /// The default collision handler is invoked for each colliding pair of shapes /// that isn't explicitly handled by a specific collision handler. /// You can pass NULL for any function you don't want to implement. void cpSpaceSetDefaultCollisionHandler( cpSpace *space, cpCollisionBeginFunc begin, cpCollisionPreSolveFunc preSolve, cpCollisionPostSolveFunc postSolve, cpCollisionSeparateFunc separate, void *data ); /// Set a collision handler to be used whenever the two shapes with the given collision types collide. /// You can pass NULL for any function you don't want to implement. void cpSpaceAddCollisionHandler( cpSpace *space, cpCollisionType a, cpCollisionType b, cpCollisionBeginFunc begin, cpCollisionPreSolveFunc preSolve, cpCollisionPostSolveFunc postSolve, cpCollisionSeparateFunc separate, void *data ); /// Unset a collision handler. void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b); /// Add a collision shape to the simulation. /// If the shape is attached to a static body, it will be added as a static shape. cpShape* cpSpaceAddShape(cpSpace *space, cpShape *shape); /// Explicity add a shape as a static shape to the simulation. cpShape* cpSpaceAddStaticShape(cpSpace *space, cpShape *shape); /// Add a rigid body to the simulation. cpBody* cpSpaceAddBody(cpSpace *space, cpBody *body); /// Add a constraint to the simulation. cpConstraint* cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint); /// Remove a collision shape from the simulation. void cpSpaceRemoveShape(cpSpace *space, cpShape *shape); /// Remove a collision shape added using cpSpaceAddStaticShape() from the simulation. void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape); /// Remove a rigid body from the simulation. void cpSpaceRemoveBody(cpSpace *space, cpBody *body); /// Remove a constraint from the simulation. void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint); /// Test if a collision shape has been added to the space. cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape); /// Test if a rigid body has been added to the space. cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body); /// Test if a constraint has been added to the space. cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint); /// Convert a dynamic rogue body to a static one. /// This will convert any shapes attached to the body into static shapes, but does not handle constraints. /// If the body is active, you must remove it from the space first. void cpSpaceConvertBodyToStatic(cpSpace *space, cpBody *body); /// Convert a body to a dynamic rogue body. /// This will convert any static shapes attached to the body into regular ones. /// If you want the body to be active after the transition, you must add it to the space also. void cpSpaceConvertBodyToDynamic(cpSpace *space, cpBody *body, cpFloat mass, cpFloat moment); /// Post Step callback function type. typedef void (*cpPostStepFunc)(cpSpace *space, void *key, void *data); /// Schedule a post-step callback to be called when cpSpaceStep() finishes. /// You can only register one callback per unique value for @c key. /// Returns true only if @c key has never been scheduled before. /// It's possible to pass @c NULL for @c func if you only want to mark @c key as being used. cpBool cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data); /// Point query callback function type. typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data); /// Query the space at a point and call @c func for each shape found. void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data); /// Query the space at a point and return the first shape found. Returns NULL if no shapes were found. cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group); /// Nearest point query callback function type. typedef void (*cpSpaceNearestPointQueryFunc)(cpShape *shape, cpFloat distance, cpVect point, void *data); /// Query the space at a point and call @c func for each shape found. void cpSpaceNearestPointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryFunc func, void *data); /// Query the space at a point and return the nearest shape found. Returns NULL if no shapes were found. cpShape *cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out); /// Segment query callback function type. typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data); /// Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected. void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data); /// Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit. cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out); /// Rectangle Query callback function type. typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data); /// Perform a fast rectangle query on the space calling @c func for each shape found. /// Only the shape's bounding boxes are checked for overlap, not their full shape. void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data); /// Shape query callback function type. typedef void (*cpSpaceShapeQueryFunc)(cpShape *shape, cpContactPointSet *points, void *data); /// Query a space for any shapes overlapping the given shape and call @c func for each shape found. cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data); /// Call cpBodyActivate() for any shape that is overlaps the given shape. void cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape); /// Space/body iterator callback function type. typedef void (*cpSpaceBodyIteratorFunc)(cpBody *body, void *data); /// Call @c func for each body in the space. void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data); /// Space/body iterator callback function type. typedef void (*cpSpaceShapeIteratorFunc)(cpShape *shape, void *data); /// Call @c func for each shape in the space. void cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data); /// Space/constraint iterator callback function type. typedef void (*cpSpaceConstraintIteratorFunc)(cpConstraint *constraint, void *data); /// Call @c func for each shape in the space. void cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data); /// Update the collision detection info for the static shapes in the space. void cpSpaceReindexStatic(cpSpace *space); /// Update the collision detection data for a specific shape in the space. void cpSpaceReindexShape(cpSpace *space, cpShape *shape); /// Update the collision detection data for all shapes attached to a body. void cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body); /// Switch the space to use a spatial has as it's spatial index. void cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count); /// Step the space forward in time by @c dt. void cpSpaceStep(cpSpace *space, cpFloat dt); /// @} Chipmunk-6.1.5/include/chipmunk/cpSpatialIndex.h000644 000765 000000 00000022723 12151675775 022574 0ustar00slembckewheel000000 000000 /* Copyright (c) 2010 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** @defgroup cpSpatialIndex cpSpatialIndex Spatial indexes are data structures that are used to accelerate collision detection and spatial queries. Chipmunk provides a number of spatial index algorithms to pick from and they are programmed in a generic way so that you can use them for holding more than just cpShape structs. It works by using @c void pointers to the objects you add and using a callback to ask your code for bounding boxes when it needs them. Several types of queries can be performed an index as well as reindexing and full collision information. All communication to the spatial indexes is performed through callback functions. Spatial indexes should be treated as opaque structs. This meanns you shouldn't be reading any of the struct fields. @{ */ //MARK: Spatial Index /// Spatial index bounding box callback function type. /// The spatial index calls this function and passes you a pointer to an object you added /// when it needs to get the bounding box associated with that object. typedef cpBB (*cpSpatialIndexBBFunc)(void *obj); /// Spatial index/object iterator callback function type. typedef void (*cpSpatialIndexIteratorFunc)(void *obj, void *data); /// Spatial query callback function type. typedef void (*cpSpatialIndexQueryFunc)(void *obj1, void *obj2, void *data); /// Spatial segment query callback function type. typedef cpFloat (*cpSpatialIndexSegmentQueryFunc)(void *obj1, void *obj2, void *data); typedef struct cpSpatialIndexClass cpSpatialIndexClass; typedef struct cpSpatialIndex cpSpatialIndex; /// @private struct cpSpatialIndex { cpSpatialIndexClass *klass; cpSpatialIndexBBFunc bbfunc; cpSpatialIndex *staticIndex, *dynamicIndex; }; //MARK: Spatial Hash typedef struct cpSpaceHash cpSpaceHash; /// Allocate a spatial hash. cpSpaceHash* cpSpaceHashAlloc(void); /// Initialize a spatial hash. cpSpatialIndex* cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex); /// Allocate and initialize a spatial hash. cpSpatialIndex* cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex); /// Change the cell dimensions and table size of the spatial hash to tune it. /// The cell dimensions should roughly match the average size of your objects /// and the table size should be ~10 larger than the number of objects inserted. /// Some trial and error is required to find the optimum numbers for efficiency. void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells); //MARK: AABB Tree typedef struct cpBBTree cpBBTree; /// Allocate a bounding box tree. cpBBTree* cpBBTreeAlloc(void); /// Initialize a bounding box tree. cpSpatialIndex* cpBBTreeInit(cpBBTree *tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex); /// Allocate and initialize a bounding box tree. cpSpatialIndex* cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex); /// Perform a static top down optimization of the tree. void cpBBTreeOptimize(cpSpatialIndex *index); /// Bounding box tree velocity callback function. /// This function should return an estimate for the object's velocity. typedef cpVect (*cpBBTreeVelocityFunc)(void *obj); /// Set the velocity function for the bounding box tree to enable temporal coherence. void cpBBTreeSetVelocityFunc(cpSpatialIndex *index, cpBBTreeVelocityFunc func); //MARK: Single Axis Sweep typedef struct cpSweep1D cpSweep1D; /// Allocate a 1D sort and sweep broadphase. cpSweep1D* cpSweep1DAlloc(void); /// Initialize a 1D sort and sweep broadphase. cpSpatialIndex* cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex); /// Allocate and initialize a 1D sort and sweep broadphase. cpSpatialIndex* cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex); //MARK: Spatial Index Implementation typedef void (*cpSpatialIndexDestroyImpl)(cpSpatialIndex *index); typedef int (*cpSpatialIndexCountImpl)(cpSpatialIndex *index); typedef void (*cpSpatialIndexEachImpl)(cpSpatialIndex *index, cpSpatialIndexIteratorFunc func, void *data); typedef cpBool (*cpSpatialIndexContainsImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid); typedef void (*cpSpatialIndexInsertImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid); typedef void (*cpSpatialIndexRemoveImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid); typedef void (*cpSpatialIndexReindexImpl)(cpSpatialIndex *index); typedef void (*cpSpatialIndexReindexObjectImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid); typedef void (*cpSpatialIndexReindexQueryImpl)(cpSpatialIndex *index, cpSpatialIndexQueryFunc func, void *data); typedef void (*cpSpatialIndexQueryImpl)(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data); typedef void (*cpSpatialIndexSegmentQueryImpl)(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data); struct cpSpatialIndexClass { cpSpatialIndexDestroyImpl destroy; cpSpatialIndexCountImpl count; cpSpatialIndexEachImpl each; cpSpatialIndexContainsImpl contains; cpSpatialIndexInsertImpl insert; cpSpatialIndexRemoveImpl remove; cpSpatialIndexReindexImpl reindex; cpSpatialIndexReindexObjectImpl reindexObject; cpSpatialIndexReindexQueryImpl reindexQuery; cpSpatialIndexQueryImpl query; cpSpatialIndexSegmentQueryImpl segmentQuery; }; /// Destroy and free a spatial index. void cpSpatialIndexFree(cpSpatialIndex *index); /// Collide the objects in @c dynamicIndex against the objects in @c staticIndex using the query callback function. void cpSpatialIndexCollideStatic(cpSpatialIndex *dynamicIndex, cpSpatialIndex *staticIndex, cpSpatialIndexQueryFunc func, void *data); /// Destroy a spatial index. static inline void cpSpatialIndexDestroy(cpSpatialIndex *index) { if(index->klass) index->klass->destroy(index); } /// Get the number of objects in the spatial index. static inline int cpSpatialIndexCount(cpSpatialIndex *index) { return index->klass->count(index); } /// Iterate the objects in the spatial index. @c func will be called once for each object. static inline void cpSpatialIndexEach(cpSpatialIndex *index, cpSpatialIndexIteratorFunc func, void *data) { index->klass->each(index, func, data); } /// Returns true if the spatial index contains the given object. /// Most spatial indexes use hashed storage, so you must provide a hash value too. static inline cpBool cpSpatialIndexContains(cpSpatialIndex *index, void *obj, cpHashValue hashid) { return index->klass->contains(index, obj, hashid); } /// Add an object to a spatial index. /// Most spatial indexes use hashed storage, so you must provide a hash value too. static inline void cpSpatialIndexInsert(cpSpatialIndex *index, void *obj, cpHashValue hashid) { index->klass->insert(index, obj, hashid); } /// Remove an object from a spatial index. /// Most spatial indexes use hashed storage, so you must provide a hash value too. static inline void cpSpatialIndexRemove(cpSpatialIndex *index, void *obj, cpHashValue hashid) { index->klass->remove(index, obj, hashid); } /// Perform a full reindex of a spatial index. static inline void cpSpatialIndexReindex(cpSpatialIndex *index) { index->klass->reindex(index); } /// Reindex a single object in the spatial index. static inline void cpSpatialIndexReindexObject(cpSpatialIndex *index, void *obj, cpHashValue hashid) { index->klass->reindexObject(index, obj, hashid); } /// Perform a rectangle query against the spatial index, calling @c func for each potential match. static inline void cpSpatialIndexQuery(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data) { index->klass->query(index, obj, bb, func, data); } /// Perform a segment query against the spatial index, calling @c func for each potential match. static inline void cpSpatialIndexSegmentQuery(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data) { index->klass->segmentQuery(index, obj, a, b, t_exit, func, data); } /// Simultaneously reindex and find all colliding objects. /// @c func will be called once for each potentially overlapping pair of objects found. /// If the spatial index was initialized with a static index, it will collide it's objects against that as well. static inline void cpSpatialIndexReindexQuery(cpSpatialIndex *index, cpSpatialIndexQueryFunc func, void *data) { index->klass->reindexQuery(index, func, data); } ///@} Chipmunk-6.1.5/include/chipmunk/cpVect.h000644 000765 000000 00000014352 12151675775 021107 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpVect cpVect /// Chipmunk's 2D vector type along with a handy 2D vector math lib. /// @{ /// Constant for the zero vector. static const cpVect cpvzero = {0.0f,0.0f}; /// Convenience constructor for cpVect structs. static inline cpVect cpv(const cpFloat x, const cpFloat y) { cpVect v = {x, y}; return v; } /// Spherical linearly interpolate between v1 and v2. cpVect cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t); /// Spherical linearly interpolate between v1 towards v2 by no more than angle a radians cpVect cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a); /// Returns a string representation of v. Intended mostly for debugging purposes and not production use. /// @attention The string points to a static local and is reset every time the function is called. /// If you want to print more than one vector you will have to split up your printing onto separate lines. char* cpvstr(const cpVect v); /// Check if two vectors are equal. (Be careful when comparing floating point numbers!) static inline cpBool cpveql(const cpVect v1, const cpVect v2) { return (v1.x == v2.x && v1.y == v2.y); } /// Add two vectors static inline cpVect cpvadd(const cpVect v1, const cpVect v2) { return cpv(v1.x + v2.x, v1.y + v2.y); } /// Subtract two vectors. static inline cpVect cpvsub(const cpVect v1, const cpVect v2) { return cpv(v1.x - v2.x, v1.y - v2.y); } /// Negate a vector. static inline cpVect cpvneg(const cpVect v) { return cpv(-v.x, -v.y); } /// Scalar multiplication. static inline cpVect cpvmult(const cpVect v, const cpFloat s) { return cpv(v.x*s, v.y*s); } /// Vector dot product. static inline cpFloat cpvdot(const cpVect v1, const cpVect v2) { return v1.x*v2.x + v1.y*v2.y; } /// 2D vector cross product analog. /// The cross product of 2D vectors results in a 3D vector with only a z component. /// This function returns the magnitude of the z value. static inline cpFloat cpvcross(const cpVect v1, const cpVect v2) { return v1.x*v2.y - v1.y*v2.x; } /// Returns a perpendicular vector. (90 degree rotation) static inline cpVect cpvperp(const cpVect v) { return cpv(-v.y, v.x); } /// Returns a perpendicular vector. (-90 degree rotation) static inline cpVect cpvrperp(const cpVect v) { return cpv(v.y, -v.x); } /// Returns the vector projection of v1 onto v2. static inline cpVect cpvproject(const cpVect v1, const cpVect v2) { return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2)); } /// Returns the unit length vector for the given angle (in radians). static inline cpVect cpvforangle(const cpFloat a) { return cpv(cpfcos(a), cpfsin(a)); } /// Returns the angular direction v is pointing in (in radians). static inline cpFloat cpvtoangle(const cpVect v) { return cpfatan2(v.y, v.x); } /// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector. static inline cpVect cpvrotate(const cpVect v1, const cpVect v2) { return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x); } /// Inverse of cpvrotate(). static inline cpVect cpvunrotate(const cpVect v1, const cpVect v2) { return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y); } /// Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths. static inline cpFloat cpvlengthsq(const cpVect v) { return cpvdot(v, v); } /// Returns the length of v. static inline cpFloat cpvlength(const cpVect v) { return cpfsqrt(cpvdot(v, v)); } /// Linearly interpolate between v1 and v2. static inline cpVect cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t) { return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t)); } /// Returns a normalized copy of v. static inline cpVect cpvnormalize(const cpVect v) { return cpvmult(v, 1.0f/cpvlength(v)); } /// Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors. static inline cpVect cpvnormalize_safe(const cpVect v) { return (v.x == 0.0f && v.y == 0.0f ? cpvzero : cpvnormalize(v)); } /// Clamp v to length len. static inline cpVect cpvclamp(const cpVect v, const cpFloat len) { return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v; } /// Linearly interpolate between v1 towards v2 by distance d. static inline cpVect cpvlerpconst(cpVect v1, cpVect v2, cpFloat d) { return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d)); } /// Returns the distance between v1 and v2. static inline cpFloat cpvdist(const cpVect v1, const cpVect v2) { return cpvlength(cpvsub(v1, v2)); } /// Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances. static inline cpFloat cpvdistsq(const cpVect v1, const cpVect v2) { return cpvlengthsq(cpvsub(v1, v2)); } /// Returns true if the distance between v1 and v2 is less than dist. static inline cpBool cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist) { return cpvdistsq(v1, v2) < dist*dist; } /// @} /// @defgroup cpMat2x2 cpMat2x2 /// 2x2 matrix type used for tensors and such. /// @{ static inline cpMat2x2 cpMat2x2New(cpFloat a, cpFloat b, cpFloat c, cpFloat d) { cpMat2x2 m = {a, b, c, d}; return m; } static inline cpVect cpMat2x2Transform(cpMat2x2 m, cpVect v) { return cpv(v.x*m.a + v.y*m.b, v.x*m.c + v.y*m.d); } ///@} Chipmunk-6.1.5/include/chipmunk/constraints/cpConstraint.h000644 000765 000000 00000014012 12151675775 024672 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpConstraint cpConstraint /// @{ typedef struct cpConstraintClass cpConstraintClass; typedef void (*cpConstraintPreStepImpl)(cpConstraint *constraint, cpFloat dt); typedef void (*cpConstraintApplyCachedImpulseImpl)(cpConstraint *constraint, cpFloat dt_coef); typedef void (*cpConstraintApplyImpulseImpl)(cpConstraint *constraint, cpFloat dt); typedef cpFloat (*cpConstraintGetImpulseImpl)(cpConstraint *constraint); /// @private struct cpConstraintClass { cpConstraintPreStepImpl preStep; cpConstraintApplyCachedImpulseImpl applyCachedImpulse; cpConstraintApplyImpulseImpl applyImpulse; cpConstraintGetImpulseImpl getImpulse; }; /// Callback function type that gets called before solving a joint. typedef void (*cpConstraintPreSolveFunc)(cpConstraint *constraint, cpSpace *space); /// Callback function type that gets called after solving a joint. typedef void (*cpConstraintPostSolveFunc)(cpConstraint *constraint, cpSpace *space); /// Opaque cpConstraint struct. struct cpConstraint { CP_PRIVATE(const cpConstraintClass *klass); /// The first body connected to this constraint. cpBody *a; /// The second body connected to this constraint. cpBody *b; CP_PRIVATE(cpSpace *space); CP_PRIVATE(cpConstraint *next_a); CP_PRIVATE(cpConstraint *next_b); /// The maximum force that this constraint is allowed to use. /// Defaults to infinity. cpFloat maxForce; /// The rate at which joint error is corrected. /// Defaults to pow(1.0 - 0.1, 60.0) meaning that it will /// correct 10% of the error every 1/60th of a second. cpFloat errorBias; /// The maximum rate at which joint error is corrected. /// Defaults to infinity. cpFloat maxBias; /// Function called before the solver runs. /// Animate your joint anchors, update your motor torque, etc. cpConstraintPreSolveFunc preSolve; /// Function called after the solver runs. /// Use the applied impulse to perform effects like breakable joints. cpConstraintPostSolveFunc postSolve; /// User definable data pointer. /// Generally this points to your the game object class so you can access it /// when given a cpConstraint reference in a callback. cpDataPointer data; }; /// Destroy a constraint. void cpConstraintDestroy(cpConstraint *constraint); /// Destroy and free a constraint. void cpConstraintFree(cpConstraint *constraint); /// @private static inline void cpConstraintActivateBodies(cpConstraint *constraint) { cpBody *a = constraint->a; if(a) cpBodyActivate(a); cpBody *b = constraint->b; if(b) cpBodyActivate(b); } /// @private #define CP_DefineConstraintStructGetter(type, member, name) \ static inline type cpConstraint##Get##name(const cpConstraint *constraint){return constraint->member;} /// @private #define CP_DefineConstraintStructSetter(type, member, name) \ static inline void cpConstraint##Set##name(cpConstraint *constraint, type value){ \ cpConstraintActivateBodies(constraint); \ constraint->member = value; \ } /// @private #define CP_DefineConstraintStructProperty(type, member, name) \ CP_DefineConstraintStructGetter(type, member, name) \ CP_DefineConstraintStructSetter(type, member, name) CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space) CP_DefineConstraintStructGetter(cpBody*, a, A) CP_DefineConstraintStructGetter(cpBody*, b, B) CP_DefineConstraintStructProperty(cpFloat, maxForce, MaxForce) CP_DefineConstraintStructProperty(cpFloat, errorBias, ErrorBias) CP_DefineConstraintStructProperty(cpFloat, maxBias, MaxBias) CP_DefineConstraintStructProperty(cpConstraintPreSolveFunc, preSolve, PreSolveFunc) CP_DefineConstraintStructProperty(cpConstraintPostSolveFunc, postSolve, PostSolveFunc) CP_DefineConstraintStructProperty(cpDataPointer, data, UserData) // Get the last impulse applied by this constraint. static inline cpFloat cpConstraintGetImpulse(cpConstraint *constraint) { return constraint->CP_PRIVATE(klass)->getImpulse(constraint); } /// @} #define cpConstraintCheckCast(constraint, struct) \ cpAssertHard(constraint->CP_PRIVATE(klass) == struct##GetClass(), "Constraint is not a "#struct) #define CP_DefineConstraintGetter(struct, type, member, name) \ static inline type struct##Get##name(const cpConstraint *constraint){ \ cpConstraintCheckCast(constraint, struct); \ return ((struct *)constraint)->member; \ } #define CP_DefineConstraintSetter(struct, type, member, name) \ static inline void struct##Set##name(cpConstraint *constraint, type value){ \ cpConstraintCheckCast(constraint, struct); \ cpConstraintActivateBodies(constraint); \ ((struct *)constraint)->member = value; \ } #define CP_DefineConstraintProperty(struct, type, member, name) \ CP_DefineConstraintGetter(struct, type, member, name) \ CP_DefineConstraintSetter(struct, type, member, name) #include "cpPinJoint.h" #include "cpSlideJoint.h" #include "cpPivotJoint.h" #include "cpGrooveJoint.h" #include "cpDampedSpring.h" #include "cpDampedRotarySpring.h" #include "cpRotaryLimitJoint.h" #include "cpRatchetJoint.h" #include "cpGearJoint.h" #include "cpSimpleMotor.h" Chipmunk-6.1.5/include/chipmunk/constraints/cpDampedRotarySpring.h000644 000765 000000 00000004622 12151675775 026332 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpDampedRotarySpring cpDampedRotarySpring /// @{ typedef cpFloat (*cpDampedRotarySpringTorqueFunc)(struct cpConstraint *spring, cpFloat relativeAngle); const cpConstraintClass *cpDampedRotarySpringGetClass(void); /// @private typedef struct cpDampedRotarySpring { cpConstraint constraint; cpFloat restAngle; cpFloat stiffness; cpFloat damping; cpDampedRotarySpringTorqueFunc springTorqueFunc; cpFloat target_wrn; cpFloat w_coef; cpFloat iSum; cpFloat jAcc; } cpDampedRotarySpring; /// Allocate a damped rotary spring. cpDampedRotarySpring* cpDampedRotarySpringAlloc(void); /// Initialize a damped rotary spring. cpDampedRotarySpring* cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); /// Allocate and initialize a damped rotary spring. cpConstraint* cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping); CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, restAngle, RestAngle) CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, stiffness, Stiffness) CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, damping, Damping) CP_DefineConstraintProperty(cpDampedRotarySpring, cpDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpDampedSpring.h000644 000765 000000 00000005022 12151675775 025124 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpDampedSpring cpDampedSpring /// @{ typedef struct cpDampedSpring cpDampedSpring; typedef cpFloat (*cpDampedSpringForceFunc)(cpConstraint *spring, cpFloat dist); const cpConstraintClass *cpDampedSpringGetClass(void); /// @private struct cpDampedSpring { cpConstraint constraint; cpVect anchr1, anchr2; cpFloat restLength; cpFloat stiffness; cpFloat damping; cpDampedSpringForceFunc springForceFunc; cpFloat target_vrn; cpFloat v_coef; cpVect r1, r2; cpFloat nMass; cpVect n; cpFloat jAcc; }; /// Allocate a damped spring. cpDampedSpring* cpDampedSpringAlloc(void); /// Initialize a damped spring. cpDampedSpring* cpDampedSpringInit(cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping); /// Allocate and initialize a damped spring. cpConstraint* cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping); CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1) CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr2, Anchr2) CP_DefineConstraintProperty(cpDampedSpring, cpFloat, restLength, RestLength) CP_DefineConstraintProperty(cpDampedSpring, cpFloat, stiffness, Stiffness) CP_DefineConstraintProperty(cpDampedSpring, cpFloat, damping, Damping) CP_DefineConstraintProperty(cpDampedSpring, cpDampedSpringForceFunc, springForceFunc, SpringForceFunc) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpGearJoint.h000644 000765 000000 00000003637 12151675775 024443 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpGearJoint cpGearJoint /// @{ const cpConstraintClass *cpGearJointGetClass(void); /// @private typedef struct cpGearJoint { cpConstraint constraint; cpFloat phase, ratio; cpFloat ratio_inv; cpFloat iSum; cpFloat bias; cpFloat jAcc; } cpGearJoint; /// Allocate a gear joint. cpGearJoint* cpGearJointAlloc(void); /// Initialize a gear joint. cpGearJoint* cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio); /// Allocate and initialize a gear joint. cpConstraint* cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio); CP_DefineConstraintProperty(cpGearJoint, cpFloat, phase, Phase) CP_DefineConstraintGetter(cpGearJoint, cpFloat, ratio, Ratio) /// Set the ratio of a gear joint. void cpGearJointSetRatio(cpConstraint *constraint, cpFloat value); /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpGrooveJoint.h000644 000765 000000 00000004330 12151675775 025015 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpGrooveJoint cpGrooveJoint /// @{ const cpConstraintClass *cpGrooveJointGetClass(void); /// @private typedef struct cpGrooveJoint { cpConstraint constraint; cpVect grv_n, grv_a, grv_b; cpVect anchr2; cpVect grv_tn; cpFloat clamp; cpVect r1, r2; cpMat2x2 k; cpVect jAcc; cpVect bias; } cpGrooveJoint; /// Allocate a groove joint. cpGrooveJoint* cpGrooveJointAlloc(void); /// Initialize a groove joint. cpGrooveJoint* cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2); /// Allocate and initialize a groove joint. cpConstraint* cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2); CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_a, GrooveA) /// Set endpoint a of a groove joint's groove void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value); CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_b, GrooveB) /// Set endpoint b of a groove joint's groove void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value); CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpPinJoint.h000644 000765 000000 00000003602 12151675775 024303 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpPinJoint cpPinJoint /// @{ const cpConstraintClass *cpPinJointGetClass(void); /// @private typedef struct cpPinJoint { cpConstraint constraint; cpVect anchr1, anchr2; cpFloat dist; cpVect r1, r2; cpVect n; cpFloat nMass; cpFloat jnAcc; cpFloat bias; } cpPinJoint; /// Allocate a pin joint. cpPinJoint* cpPinJointAlloc(void); /// Initialize a pin joint. cpPinJoint* cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2); /// Allocate and initialize a pin joint. cpConstraint* cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2); CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1) CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr2, Anchr2) CP_DefineConstraintProperty(cpPinJoint, cpFloat, dist, Dist) ///@} Chipmunk-6.1.5/include/chipmunk/constraints/cpPivotJoint.h000644 000765 000000 00000003711 12151675775 024657 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpPivotJoint cpPivotJoint /// @{ const cpConstraintClass *cpPivotJointGetClass(void); /// @private typedef struct cpPivotJoint { cpConstraint constraint; cpVect anchr1, anchr2; cpVect r1, r2; cpMat2x2 k; cpVect jAcc; cpVect bias; } cpPivotJoint; /// Allocate a pivot joint cpPivotJoint* cpPivotJointAlloc(void); /// Initialize a pivot joint. cpPivotJoint* cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2); /// Allocate and initialize a pivot joint. cpConstraint* cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot); /// Allocate and initialize a pivot joint with specific anchors. cpConstraint* cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2); CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr1, Anchr1) CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr2, Anchr2) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpRatchetJoint.h000644 000765 000000 00000003653 12151675775 025155 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpRatchetJoint cpRatchetJoint /// @{ const cpConstraintClass *cpRatchetJointGetClass(void); /// @private typedef struct cpRatchetJoint { cpConstraint constraint; cpFloat angle, phase, ratchet; cpFloat iSum; cpFloat bias; cpFloat jAcc; } cpRatchetJoint; /// Allocate a ratchet joint. cpRatchetJoint* cpRatchetJointAlloc(void); /// Initialize a ratched joint. cpRatchetJoint* cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet); /// Allocate and initialize a ratchet joint. cpConstraint* cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet); CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, angle, Angle) CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, phase, Phase) CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, ratchet, Ratchet) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpRotaryLimitJoint.h000644 000765 000000 00000003633 12151675775 026040 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpRotaryLimitJoint cpRotaryLimitJoint /// @{ const cpConstraintClass *cpRotaryLimitJointGetClass(void); /// @private typedef struct cpRotaryLimitJoint { cpConstraint constraint; cpFloat min, max; cpFloat iSum; cpFloat bias; cpFloat jAcc; } cpRotaryLimitJoint; /// Allocate a damped rotary limit joint. cpRotaryLimitJoint* cpRotaryLimitJointAlloc(void); /// Initialize a damped rotary limit joint. cpRotaryLimitJoint* cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max); /// Allocate and initialize a damped rotary limit joint. cpConstraint* cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max); CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, min, Min) CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, max, Max) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpSimpleMotor.h000644 000765 000000 00000003314 12151675775 025023 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpSimpleMotor cpSimpleMotor /// @{ const cpConstraintClass *cpSimpleMotorGetClass(void); /// @private typedef struct cpSimpleMotor { cpConstraint constraint; cpFloat rate; cpFloat iSum; cpFloat jAcc; } cpSimpleMotor; /// Allocate a simple motor. cpSimpleMotor* cpSimpleMotorAlloc(void); /// initialize a simple motor. cpSimpleMotor* cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate); /// Allocate and initialize a simple motor. cpConstraint* cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate); CP_DefineConstraintProperty(cpSimpleMotor, cpFloat, rate, Rate) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/cpSlideJoint.h000644 000765 000000 00000004027 12151675775 024617 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /// @defgroup cpSlideJoint cpSlideJoint /// @{ const cpConstraintClass *cpSlideJointGetClass(void); /// @private typedef struct cpSlideJoint { cpConstraint constraint; cpVect anchr1, anchr2; cpFloat min, max; cpVect r1, r2; cpVect n; cpFloat nMass; cpFloat jnAcc; cpFloat bias; } cpSlideJoint; /// Allocate a slide joint. cpSlideJoint* cpSlideJointAlloc(void); /// Initialize a slide joint. cpSlideJoint* cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max); /// Allocate and initialize a slide joint. cpConstraint* cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max); CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr1, Anchr1) CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr2, Anchr2) CP_DefineConstraintProperty(cpSlideJoint, cpFloat, min, Min) CP_DefineConstraintProperty(cpSlideJoint, cpFloat, max, Max) /// @} Chipmunk-6.1.5/include/chipmunk/constraints/util.h000644 000765 000000 00000007734 12151675775 023215 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // These are utility routines to use when creating custom constraints. // I'm not sure if this should be part of the private API or not. // I should probably clean up the naming conventions if it is... #define CP_DefineClassGetter(t) const cpConstraintClass * t##GetClass(void){return (cpConstraintClass *)&klass;} void cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b); static inline cpVect relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){ cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w)); cpVect v2_sum = cpvadd(b->v, cpvmult(cpvperp(r2), b->w)); return cpvsub(v2_sum, v1_sum); } static inline cpFloat normal_relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n){ return cpvdot(relative_velocity(a, b, r1, r2), n); } static inline void apply_impulse(cpBody *body, cpVect j, cpVect r){ body->v = cpvadd(body->v, cpvmult(j, body->m_inv)); body->w += body->i_inv*cpvcross(r, j); } static inline void apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j) { apply_impulse(a, cpvneg(j), r1); apply_impulse(b, j, r2); } static inline void apply_bias_impulse(cpBody *body, cpVect j, cpVect r) { body->CP_PRIVATE(v_bias) = cpvadd(body->CP_PRIVATE(v_bias), cpvmult(j, body->m_inv)); body->CP_PRIVATE(w_bias) += body->i_inv*cpvcross(r, j); } static inline void apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j) { apply_bias_impulse(a, cpvneg(j), r1); apply_bias_impulse(b, j, r2); } static inline cpFloat k_scalar_body(cpBody *body, cpVect r, cpVect n) { cpFloat rcn = cpvcross(r, n); return body->m_inv + body->i_inv*rcn*rcn; } static inline cpFloat k_scalar(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n) { cpFloat value = k_scalar_body(a, r1, n) + k_scalar_body(b, r2, n); cpAssertSoft(value != 0.0, "Unsolvable collision or constraint."); return value; } static inline cpMat2x2 k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2) { cpFloat m_sum = a->m_inv + b->m_inv; // start with Identity*m_sum cpFloat k11 = m_sum, k12 = 0.0f; cpFloat k21 = 0.0f, k22 = m_sum; // add the influence from r1 cpFloat a_i_inv = a->i_inv; cpFloat r1xsq = r1.x * r1.x * a_i_inv; cpFloat r1ysq = r1.y * r1.y * a_i_inv; cpFloat r1nxy = -r1.x * r1.y * a_i_inv; k11 += r1ysq; k12 += r1nxy; k21 += r1nxy; k22 += r1xsq; // add the influnce from r2 cpFloat b_i_inv = b->i_inv; cpFloat r2xsq = r2.x * r2.x * b_i_inv; cpFloat r2ysq = r2.y * r2.y * b_i_inv; cpFloat r2nxy = -r2.x * r2.y * b_i_inv; k11 += r2ysq; k12 += r2nxy; k21 += r2nxy; k22 += r2xsq; // invert cpFloat det = k11*k22 - k12*k21; cpAssertSoft(det != 0.0, "Unsolvable constraint."); cpFloat det_inv = 1.0f/det; return cpMat2x2New( k22*det_inv, -k12*det_inv, -k21*det_inv, k11*det_inv ); } static inline cpFloat bias_coef(cpFloat errorBias, cpFloat dt) { return 1.0f - cpfpow(errorBias, dt); } Chipmunk-6.1.5/doc/examples/000755 000765 000000 00000000000 12151675775 016627 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/doc/examples.html000644 000765 000000 00000021206 12151675775 017516 0ustar00slembckewheel000000 000000 Chipmunk Game Dynamics Documentation

Example Code Snippets:

Getting a Transformation from a Rigid Body:

You can quickly and easily build a transformation matrix from a Chipmunk body. The following code is for OpenGL, but it should be trivial to modify for DirectX or affine transforms. (Note that OpenGL matrices are column-major)

cpVect pos = body->p;
cpVect rot = body->rot;

GLFloat matrix[16] = {
   rot.x, rot.y, 0.0f, 0.0f,
  -rot.y, rot.x, 0.0f, 0.0f,
   0.0f,   0.0f, 1.0f, 0.0f,
   pos.x, pos.y, 0.0f, 1.0f,
};

glMultMatrixf(matrix.farr);

Collision Callbacks:

This snippet demonstrates several Chipmunk collision callback features. It defines a collision handler that is called when collision shapes start touching and also a post-step callback to remove the collision shape and body.

static void
postStepRemove(cpSpace *space, cpShape *shape, void *unused)
{
  cpSpaceRemoveBody(space, shape->body);
  cpBodyFree(shape->body);
  
  cpSpaceRemoveShape(space, shape);
  cpShapeFree(shape);
}

static int
begin(cpArbiter *arb, cpSpace *space, void *unused)
{
  // Get the cpShapes involved in the collision
  // The order will be the same as you defined in the handler definition
  // a->collision_type will be BULLET_TYPE and b->collision_type will be MONSTER_TYPE
  cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
  
  // Alternatively you can use the CP_ARBITER_GET_SHAPES() macro
  // It defines and sets the variables for you.
  //CP_ARBITER_GET_SHAPES(arb, a, b);
  
  // Add a post step callback to safely remove the body and shape from the space.
  // Calling cpSpaceRemove*() directly from a collision handler callback can cause crashes.
  cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL);
  
  // The object is dead, don’t process the collision further
  return 0;
}

#define BULLET_TYPE 1
#define MONSTER_TYPE 2

// Define a collision handler for bullets and monsters
// Kill the monster by removing it’s shape and body from the space as soon as it’s hit by a bullet 
cpSpaceAddCollisionHandler(space, BULLET_TYPE, MONSTER_TYPE, begin, NULL, NULL, NULL, NULL);

For more callback examples, see the One Way Platform Demo, Sensors Demo, or the Player Demo.

Query Examples:

The following example is taken directly from ChipmunkDemo.c. When the mouse is clicked, a point query is performed to see if there is a shape under the mouse. If there is, it adds a joint to the body that links it to the mouse's movement.

static void
click(int button, int state, int x, int y)
{
  if(button == GLUT_LEFT_BUTTON){
    if(state == GLUT_DOWN){
      cpVect point = mouseToSpace(x, y);
    
      cpShape *shape = cpSpacePointQueryFirst(space, point, GRABABLE_MASK_BIT, 0);
      if(shape){
        cpBody *body = shape->body;
        mouseJoint = cpPivotJointNew2(mouseBody, body, cpvzero, cpBodyWorld2Local(body, point));
        mouseJoint->maxForce = 50000.0f;
        mouseJoint->biasCoef = 0.15f;
        cpSpaceAddConstraint(space, mouseJoint);
      }
    } else if(mouseJoint){
      cpSpaceRemoveConstraint(space, mouseJoint);
      cpConstraintFree(mouseJoint);
      mouseJoint = NULL;
    }
  }
}

Perform a segment query to see if a laser beam hits a shape. We want to draw particles at both the position where the beam enters and exits the shape.

cpVect a = cpv(...), b = cpv(...);

cpSegmentQueryInfo info = {};
if(cpSpaceSegmentQueryFirst(space, a, b, -1, 0, &info)){
  cpSegmentQueryInfo info2;
  cpShapeSegmentQuery(info.shape, b, a, &info2);
  
  cpVect enterPoint = cpSegmentQueryHitPoint(a, b, info);
  cpVect exitPoint = cpSegmentQueryHitPoint(b, a, info2);
}
Chipmunk-6.1.5/doc/images/000755 000765 000000 00000000000 12151675775 016256 5ustar00slembckewheel000000 000000 Chipmunk-6.1.5/doc/index.html000644 000765 000000 00000407443 12152211306 016773 0ustar00slembckewheel000000 000000 Chipmunk Game Dynamics Manual

Hide/Show Outline

Chipmunk Physics 6.1.4

First of all, Chipmunk is a 2D rigid body physics library distributed under the MIT license. It is intended to be blazingly fast, portable, numerically stable, and easy to use. For this reason it’s been used in hundreds of games across just about every system you can name. This includes top quality titles such as Night Sky for the Wii and many #1 sellers on the iPhone App Store! I’ve put thousands of hours of work over many years to make Chipmunk what it is today. If you find Chipmunk has saved you a lot of time, please consider donating. You’ll make an indie game developer very happy!

First of all, I would like to give a Erin Catto a big thank you, as Chipmunk’s impulse solver was directly inspired by his example code way back in 2006. (Now a full fledged physics engine all it’s own: Box2D.org). His contact persistence idea allows for stable stacks of objects with very few iterations of the solver. My previous solver produced mushy piles of objects or required a large amount of CPU to operate stably.

Why a C Library?

A lot of people ask me why I wrote Chipmunk in C instead of pick your favorite language here. I tend to get really excited about different programming languages. Depending on the month, take your pick of Scheme, OCaml, Ruby, Objective-C, ooc, Lua, Io… the list goes on. The one common factor between most any language is that they are usually dead simple to make bindings to C code. I also wanted Chipmunk to be fast, portable, easy to optimize and easy to debug. Writing Chipmunk in C made it simpler to achieve all of those goals.

That said, I’ve never developed a whole game in C and I probably never will. There are much more interesting and fun languages than C with all sorts of nice features like garbage collection, closures and all sorts of unique object oriented runtimes. Check out the Bindings and Ports page to see if you can use Chipmunk from your language of choice. Because Chipmunk is written in a subset of C99 it compiles cleanly as C, C++, Objective-C and Objective-C++ code, making it easy to integrate into projects in those languages.

If you are writing iPhone games using Chipmunk, you should check out the Objective-Chipmunk wrapper that we’ve developed for Chipmunk. It integrates with the Objective-C memory model and provides a number of high level APIs that make writing physics based games for the iPhone even easier. While we do charge for Objective-Chipmunk, it will almost certainly save you more time than the small cost to license it. As a bonus, you’ll be helping to ensure that we can afford to continue to work on Chipmunk improvements.

Limitations of a C API:

Chipmunk does provide overloaded operators for *, +, and - (unary and binary) if you are using C++, but falls back to using functions such as cpvadd() and cpvsub() for C code. This is a little harder to read, but works OK once you get used to it. Most of the interesting vector operations that are possible don’t have a symbol for them anyway (at least not on a keyboard).

Another problem for a C API is access restriction. There are many structs, fields and functions in Chipmunk that are only meant to be used internally. To work around this, I have a separate header full of Chipmunk’s private API, chipmunk_private.h. I also use a macro, CP_PRIVATE() to mangle names in public structures. While you can feel free to include this header or use the macro in your own code to access the private API, be aware that the fields and functions may be renamed or disappear without warning and I have no plans to document or support usage of the private API.

Get it, Compile it:

If you haven’t downloaded it yet, you can always download the newest version of Chipmunk here. Inside you’ll find a command line build script that works with CMake, a XCode project and project files for Visual Studio ’09 and ’10.

Debug or Release?

Debug mode might be slightly slower, but will include a lot of error checking assertions that can help you find bugs quicker such as removing objects twice or doing things that might cause unsolvable collisions. I highly recommend you use a debug build until you are ready to ship the game and only then switch to a release build.

XCode (Mac/iPhone)

The included XCode project has targets for building a static library for the Mac or iOS. Additionally, you might want to just run the macosx/iphonestatic.command or macosx/macstatic.command to build you a directory with the headers and debug/release static libraries that you can just drop right into your projects. Including Chipmunk in your project with all the correct compiler flags applied couldn’t be simpler. The iPhone script generates a “fat” library that can be used with both the iOS simulator and devices. The device version is compiled as release, and the simulator version is compiled as debug.

MSVC

I rarely use MSVC, but others have chipped in to help me maintain Visual Studio project files. The MSVC 10 project should work, as I usually remember to test that before making a stable release. The MSVC 9 project may not as I don’t have access to that version. Let me know if there are any issues.

Command Line

The CMake build script should work on any system (Unix/Win/Mac) as long as you have CMake installed. It can even generate XCode or MSVC projects if you want (see CMake’s documentation for more information).

To compile a Chipmunk debug build on the command line, all you need to do is run:

cmake -D CMAKE_BUILD_TYPE=Debug .
make

If the -D CMAKE_BUILD_TYPE=Debug option is left out, it will make a release build instead.

Hello Chipmunk (World)

Hello world Chipmunk style. Create a simple simulation where a ball falls onto a static line segment, then rolls off. Print out the coordinates of the ball.

Support:

The best way to get support is to visit the Chipmunk Forums. There are plenty of people around using Chipmunk on the just about every platform I’ve ever heard of. If you are working on a commercial project, Howling Moon Software (my company) is available for contracting. We can help with implementing custom Chipmunk behaviors, as well as priority bug fixes and performance tuning.

Contact:

If you find any bugs in Chipmunk, errors or broken links in this document, or have a question or comment about Chipmunk you can contact me at slembcke(at)gmail(dot)com. (email or GTalk)

License:

Chipmunk is licensed under the MIT license.

Copyright (c) 2007-2011 Scott Lembcke

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

This means that you do not have to buy a license or pay to use Chipmunk in commercial projects. (Though we really appreciate donations)

Links:

  • Chipmunk Forums – The official forum Chipmunk Physics forum.
  • Howling Moon Software – My software company.
  • Chipmunk Pro – An enhanced version of Chipmunk that we maintain with some specific optimizations for ARM or multi-core platforms, automatic geometry manipulation from images or procedural data, and API wrappers for Objective-C.
  • Games – A small list of games done with Chipmunk. At least a few of the ones we know of.

Chipmunk Basics:

Overview:

There are 4 basic object types you will use in Chipmunk.

  • Rigid Bodies: A rigid body holds the physical properties of an object. (mass, position, rotation, velocity, etc.) It does not have a shape until you attach one or more collision shapes to it. If you’ve done physics with particles before, rigid bodies differ in that they are able to rotate. Rigid bodies generally tend to have a 1:1 correlation to sprites in a game. You should structure your game so that you use the position and rotation of the rigid body for drawing your sprite.
  • Collision Shapes: By attaching shapes to bodies, you can define the a body’s shape. You can attach as many shapes to a single body as you need to in order to define a complex shape. Shapes contain the surface properties of an object such as how much friction or elasticity it has.
  • Constraints/Joints: Constraints and joints describe how bodies are attached to each other.
  • Spaces: Spaces are containers for simulating objects in Chipmunk. You add bodies, shapes and joints to a space and then update the space as a whole. They control how all the rigid bodies, shapes, and constraints interact together.

There is often confusion between rigid bodies and their collision shapes in Chipmunk and how they relate to sprites. A sprite would be a visual representation of an object, while a collision shape is an invisible property that defines how objects should collide. Both the sprite’s and the collision shape’s position and rotation are controlled by the motion of a rigid body. Generally you want to create a game object type that ties these things all together.

Memory Management the Chipmunk way:

For most of the structures you will use, Chipmunk uses a more or less standard and straightforward set of memory management functions. Take the cpSpace struct for example:

  • cpSpaceNew() – Allocates and initializes a cpSpace struct. It calls cpSpaceAlloc() then cpSpaceInit().
  • cpSpaceFree(cpSpace *space) – Destroys and frees the cpSpace struct.

You are responsible for freeing any structs that you allocate. Chipmunk does not do reference counting or garbage collection. If you call a new function, you must call the matching free function or you will leak memory.

Additionally if you need more control over allocation and initialization because you are allocating temporary structs on the stack, writting a language binding, or working in a low memory environment you can also use the following functions. Most people will never have any need to use these functions.

  • cpSpaceAlloc() – Allocates but does not initialize a cpSpace struct. All allocation functions look more or less like this: return (cpSpace *)cpcalloc(1, sizeof(cpSpace)); You can write your own allocation functions if you want. It is not a requirement that the memory be zeroed.
  • cpSpaceInit(cpSpace *space) – Initializes a cpSpace struct.
  • cpSpaceDestroy(cpSpace *space) – Frees all memory allocated by cpSpaceInit(), but does not free the cpSpace struct itself.

Like calls to the new and free functions. Any memory allocated by an alloc function must be freed by cpfree() or similar. Any call to an init function must be matched with it’s destroy function.

To further ease integration with garbage collectors or other memory management constraints, Chipmunk has a number of compile time defines (cpcalloc(), cprealloc(), and cpfree()) that can be overriden. If you aren’t using Chipmunk from a garbage collected language, I’d highly recommend using libGC. It provides nearly transparent garbage collection for C based languages.

Basic Types:

chipmunk_types.h defines a number of basic types that Chipmunk uses. These can be changed at compile time to better suit your needs:

  • cpFloat: Floating point type. Defaults to double.
  • cpVect: 2D vector type. cpVect documentation
  • cpBool: Like every good C library that wants good cross language compatibility, you end up defining your own boolean type. :-\ Defaults to int.
  • cpDataPointer: Pointer type defined for callbacks and the user definable data pointer on most Chipmunk structs. Defaults to void*.
  • cpCollisionType: Unique identifier for collision shape types. Defaults to unsigned int. Defined type must support the == operator.
  • cpGroup: Unique identifier for collision groups. Defaults to unsigned int. A CP_NO_GROUP value is defined that can be used when you don’t want to specify a group. Defined type must support the equality == operator.
  • cpLayers: Type used as the layers bitmask. Defaults to unsigned int. A CP_ALL_LAYERS value is defined that has all layer bits set. Defined type must support the bitwise AND & operator.

If you are writting a game engine or language binding on top of Chipmunk, you might want to choose to use object references instead of integers for collision type and group. I often use class pointers for collision types and game object pointers for groups. It’s much simpler than keeping a table of enumerations around.

Note: On the iPhone, cpFloat is defined as float and cpVect is an alias for CGPoint for performance and compatibility reasons.

Math the Chipmunk way:

First of all, Chipmunk uses double precision floating point numbers throughout it’s calculations by default. This is likely to be faster on most modern desktop processors, and means you have to worry less about floating point round off errors. You can change the floating point type used by Chipmunk when compiling the library. Look in chipmunk_types.h.

Chipmunk defines a number of aliases for common math functions so that you can choose to use floats or doubles for Chipmunk’s floating point type. In your own code, there probably isn’t a strong reason to use these aliases unless you expect you might want to change Chipmunk’s floating point type later and a 2% performance hit from using the wrong float/double version of math functions will matter.

There are a few unique functions you will probably find very useful:

  • cpFloat cpfclamp(cpFloat f, cpFloat min, cpFloat max) – Clamp f to be between min and max.
  • cpFloat cpflerp(cpFloat f1, cpFloat f2, cpFloat t) – Linearly interpolate between f1 and f2.
  • cpFloat cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d) – Linearly interpolate from f1 towards f2 by no more than d.

Floating point infinity is defined as INFINITY. This is defined by many math libraries, but is not actually part of the C standard library.

Chipmunk Vectors: cpVect

Struct Definition, Constants and Constructors:

typedef struct cpVect{
	cpFloat x, y;
} cpVect

2D vector packed into a struct. No surprises here.

static const cpVect cpvzero = {0.0f,0.0f};

Constant for the zero vector.

cpVect cpv(const cpFloat x, const cpFloat y)

Convenience constructor for creating new cpVect structs.

Operations:

  • cpBool cpveql(const cpVect v1, const cpVect v2) – Check if two vectors are equal. Chipmunk provides an overloaded == operator when used in C++ programs. (Be careful when comparing floating point numbers!)
  • cpVect cpvadd(const cpVect v1, const cpVect v2) – Add two vectors. Chipmunk provides an overloaded + operator when used in C++ programs.
  • cpVect cpvsub(const cpVect v1, const cpVect v2) – Subtract two vectors. Chipmunk provides an overloaded - operator when used in C++ programs.
  • cpVect cpvneg(const cpVect v) – Negate a vector. Chipmunk provides an overloaded unary negation operator - when used in C++ programs.
  • cpVect cpvmult(const cpVect v, const cpFloat s) – Scalar multiplication. Chipmunk provides an overloaded * operator when used in C++ programs.
  • cpFloat cpvdot(const cpVect v1, const cpVect v2) – Vector dot product.
  • cpFloat cpvcross(const cpVect v1, const cpVect v2) – 2D vector cross product analog. The cross product of 2D vectors results in a 3D vector with only a z component. This function returns the value along the z-axis.
  • cpVect cpvperp(const cpVect v) – Returns a perpendicular vector. (90 degree rotation)
  • cpVect cpvrperp(const cpVect v) – Returns a perpendicular vector. (-90 degree rotation)
  • cpVect cpvproject(const cpVect v1, const cpVect v2) – Returns the vector projection of v1 onto v2.
  • cpVect cpvrotate(const cpVect v1, const cpVect v2) – Uses complex multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
  • cpVect cpvunrotate(const cpVect v1, const cpVect v2) – Inverse of cpvrotate().
  • cpFloat cpvlength(const cpVect v) – Returns the length of v.
  • cpFloat cpvlengthsq(const cpVect v) – Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.
  • cpVect cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t) – Linearly interpolate between v1 and v2.
  • cpVect cpvlerpconst(cpVect v1, cpVect v2, cpFloat d) – Linearly interpolate between v1 towards v2 by distance d.
  • cpVect cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t) – Spherical linearly interpolate between v1 and v2.
  • cpVect cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a) – Spherical linearly interpolate between v1 towards v2 by no more than angle a in radians.
  • cpVect cpvnormalize(const cpVect v) – Returns a normalized copy of v.
  • cpVect cpvnormalize_safe(const cpVect v) – Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors.
  • cpVect cpvclamp(const cpVect v, const cpFloat len) – Clamp v to length len.
  • cpFloat cpvdist(const cpVect v1, const cpVect v2) – Returns the distance between v1 and v2.
  • cpFloat cpvdistsq(const cpVect v1, const cpVect v2) – Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
  • cpBool cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist) – Returns true if the distance between v1 and v2 is less than dist.
  • cpVect cpvforangle(const cpFloat a) – Returns the unit length vector for the given angle (in radians).
  • cpFloat cpvtoangle(const cpVect v) – Returns the angular direction v is pointing in (in radians).

Chipmunk Axis Aligned Bounding Boxes: cpBB

Struct Definition and Constructors:

typedef struct cpBB{
	cpFloat l, b, r ,t;
} cpBB

Simple bounding box struct. Stored as left, bottom, right, top values.

cpBB cpBBNew(const cpFloat l, const cpFloat b, const cpFloat r, const cpFloat t)

Convenience constructor for cpBB structs. Like cpv() this function returns a copy and not a malloced pointer.

cpBB cpBBNewForCircle(const cpVect p, const cpFloat r)

Convenience constructor for making a cpBB fitting a circle at position p with radius r.

Operations:

  • cpBool cpBBIntersects(const cpBB a, const cpBB b) – Returns true if the bounding boxes intersect.
  • cpBool cpBBContainsBB(const cpBB bb, const cpBB other) – Returns true if bb completely contains other.
  • cpBool cpBBContainsVect(const cpBB bb, const cpVect v) – Returns true if bb contains v.
  • cpBB cpBBMerge(const cpBB a, const cpBB b) – Return the minimal bounding box that contains both a and b.
  • cpBB cpBBExpand(const cpBB bb, const cpVect v) – Return the minimal bounding box that contains both bb and v.
  • cpFloat cpBBArea(cpBB bb) – Return the area of bb.
  • cpFloat cpBBMergedArea(cpBB a, cpBB b) – Merges a and b then returns the area of the merged bounding box.
  • cpFloat cpBBSegmentQuery(cpBB bb, cpVect a, cpVect b) – Returns the fraction along the segment query the cpBB is hit. Returns INFINITY if it doesn’t hit.
  • cpBool cpBBIntersectsSegment(cpBB bb, cpVect a, cpVect b) – Returns true if the segment defined by endpoints a and b intersect bb.
  • cpVect cpBBClampVect(const cpBB bb, const cpVect v) – Returns a copy of v clamped to the bounding box.
  • cpVect cpBBWrapVect(const cpBB bb, const cpVect v) – Returns a copy of v wrapped to the bounding box.

Chipmunk Rigid Bodies: cpBody

Rogue and Static Bodies:

Normally when you create a rigid body, you add it to a space so the space will start simulating it. This means it will update it’s position and velocity, apply forces to it, be affected by gravity, etc. A body that isn’t added to a space (and not simulated) is called a rogue body. The most important use for rogue bodies are as static bodies, but you can also use them to implement directly controlled objects such as moving platforms.

Static bodies are rogue bodies, but with a special flag set on them to let Chipmunk know that they never move unless you tell it. Static bodies have two purposes. Originally they were added for the sleeping feature. Because static bodies don’t move, Chipmunk knows that it’s safe to let objects that are touching or jointed to them fall asleep. Objects touching or jointed to regular rogue bodies are never allowed to sleep. The second purpose for static bodies is that Chipmunk knows shapes attached to them never need to have their collision detection data updated. Chipmunk also doesn’t need to bother checking for collisions between static objects. Generally all of your level geometry will be attached to a static body except for things like moving platforms or doors.

In previous versions of Chipmunk before 5.3 you would create an infinite mass rogue body to attach static shapes to using cpSpaceAddStaticShape(). You don’t need to do any of that anymore, and shouldn’t if you want to use the sleeping feature. Each space has a dedicated static body that you can use to attach your static shapes to. Chipmunk also automatically adds shapes attached to static bodies as static shapes.

Memory Management Functions:

cpBody *cpBodyAlloc(void)
cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i)
cpBody *cpBodyNew(cpFloat m, cpFloat i)

void cpBodyDestroy(cpBody *body)
void cpBodyFree(cpBody *body)

Standard set of Chipmunk memory management functions. m and i are the mass and moment of inertia for the body. Guessing the mass for a body is usually fine, but guessing a moment of inertia can lead to a very poor simulation. Be careful not to free a body before any shapes or constraints attached to it have been removed from a space.

Creating Additional Static Bodies:

While every cpSpace has a built in static body that you can use, it can be convenient to make your own as well. One potential use is in a level editor. By attaching chunks of your level to static bodies, you can still move and rotate the chunks independently of each other. Then all you have to do is call cpSpaceRehashStatic() to rebuild the static collision detection data when you are done.

For more information on rogue and static bodies, see Chipmunk Spaces.

cpBody *cpBodyAlloc(void);
cpBody *cpBodyInitStatic(cpBody *body)
cpBody *cpBodyNewStatic()

Create additional static bodies with infinite mass and moment of inertia.

Properties:

Chipmunk provides getter/setter functions for a number of properties on rigid bodies. Setting most properties automatically wakes the rigid bodies up if they were sleeping. You can also set the fields directly on the cpBody struct if you wish. They are documented in the headers.

cpFloat cpBodyGetMass(const cpBody *body)
void cpBodySetMass(cpBody *body, cpFloat m)

Mass of the body.

cpFloat cpBodyGetMoment(const cpBody *body)
void cpBodySetMoment(cpBody *body, cpFloat i)

Moment of inertia (MoI or sometimes just moment) of the body. The moment is like the rotational mass of a body. See below for function to help calculate the moment.

cpVect cpBodyGetPos(const cpBody *body)
void cpBodySetPos(cpBody *body, cpVect pos)

Position of the center of gravity of the body. When changing the position you may also want to call cpSpaceReindexShapesForBody() to update the collision detection information for the attached shapes if plan to make any queries against the space.

cpVect cpBodyGetVel(const cpBody *body)
void cpBodySetVel(cpBody *body, const cpVect value)

Linear velocity of the center of gravity of the body.

cpVect cpBodyGetForce(const cpBody *body)
void cpBodySetForce(cpBody *body, const cpVect value)

Force applied to the center of gravity of the body.

cpFloat cpBodyGetAngle(const cpBody *body)
void cpBodySetAngle(cpBody *body, cpFloat a)

Rotation of the body in radians. When changing the rotation you may also want to call cpSpaceReindexShapesForBody() to update the collision detection information for the attached shapes if plan to make any queries against the space.

cpFloat cpBodyGetAngVel(const cpBody *body)
void cpBodySetAngVel(cpBody *body, const cpFloat value)

The angular velocity of the body in radians per second.

cpFloat cpBodyGetTorque(const cpBody *body)
void cpBodySetTorque(cpBody *body, const cpFloat value)

The torque applied to the body.

cpVect cpBodyGetRot(const cpBody *body)

The rotation vector for the body. Can be used with cpvrotate() or cpvunrotate() to perform fast rotations.

cpFloat cpBodyGetVelLimit(const cpBody *body)
void cpBodySetVelLimit(cpBody *body, const cpFloat value)

Velocity limit of the body. Defaults to INFINITY unless you set it specifically. Can be used to limit falling speeds, etc.

cpFloat cpBodyGetAngVelLimit(const cpBody *body)
void cpBodySetAngVelLimit(cpBody *body, const cpFloat value)

Angular velocity limit of the body in radians per second. Defaults to INFINITY unless you set it specifically.

cpSpace* cpBodyGetSpace(const cpBody *body)

Get the cpSpace that body has been added to.

cpDataPointer cpBodyGetUserData(const cpBody *body)
void cpBodySetUserData(cpBody *body, const cpDataPointer value)

User data pointer. Use this pointer to get a reference to the game object that owns this body from callbacks.

Moment of Inertia and Area Helper Functions:

Use the following functions to approximate the moment of inertia for your body, adding the results together if you want to use more than one.

  • cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset) – Calculate the moment of inertia for a hollow circle, r1 and r2 are the inner and outer diameters in no particular order. (A solid circle has an inner diameter of 0)
  • cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b) – Calculate the moment of inertia for a line segment. The endpoints a and b are relative to the body.
  • cpFloat cpMomentForPoly(cpFloat m, int numVerts, const cpVect *verts, cpVect offset) – Calculate the moment of inertia for a solid polygon shape assuming it’s center of gravity is at it’s centroid. The offset is added to each vertex.
  • cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height) – Calculate the moment of inertia for a solid box centered on the body.

Use the following functions to get the area for common Chipmunk shapes if you want to approximate masses or density or whatnot.

  • cpFloat cpAreaForCircle(cpFloat r1, cpFloat r2) – Area of a hollow circle.
  • cpFloat cpAreaForSegment(cpVect a, cpVect b, cpFloat r) – Area of a beveled segment. (Will always be zero if radius is zero)
  • cpFloat cpAreaForPoly(const int numVerts, const cpVect *verts) – Signed area of a polygon shape. Returns a negative number for polygons with a backwards winding.

Coordinate Conversion Functions:

Many things are defined in coordinates local to a body meaning that the (0,0) is at the center of gravity of the body and the axis rotate along with the body.

  • cpVect cpBodyLocal2World(const cpBody *body, const cpVect v) – Convert from body local coordinates to world space coordinates.
  • cpVect cpBodyWorld2Local(const cpBody *body, const cpVect v) – Convert from world space coordinates to body local coordinates.

Applying Forces and Torques:

People are sometimes confused by the difference between a force and an impulse. An impulse is basically a very large force applied over a very short period of time, like a ball hitting a wall or cannon firing. Chipmunk treats impulses as if they occur instantaneously by simply adding directly to the velocity of an object. Both impulses and forces are affected the mass of an object. Double the mass of the object and halve the effect.

  • void cpBodyResetForces(cpBody *body) – Zero both the forces and torques currently applied to the body.
  • void cpBodyApplyForce(cpBody *body, const cpVect f, const cpVect r) – Add the force f to body at a relative offset r from the center of gravity.
  • void cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r) – Add the impulse j to body at a relative offset r from the center of gravity.

Note: Both the cpBodyApplyForce() cpBodyApplyImpulse() functions take a force or impulse in absolute coordinates and applies it at a relative offset in absolute coordinates. (The offset is relative to the center of gravity, but is not rotated with the body)

Sleeping Functions:

Chipmunk supports a sleeping feature so that it stops using CPU time simulating groups of objects that stop moving. Read more about it in the cpSpace section.

  • cpBool cpBodyIsSleeping(const cpBody *body) – Returns true if body is sleeping.
  • void cpBodyActivate(cpBody *body) – Reset the idle timer on a body. If it was sleeping, wake it and any other bodies it was touching.
  • void cpBodySleep(cpBody *body) – Forces a body to fall asleep immediately even if it’s in midair. Cannot be called from a callback.
  • void cpBodyActivateStatic(cpBody *body, cpShape *filter) – Similar in function to cpBodyActivate(). Activates all bodies touching body. If filter is not NULL, then only bodies touching through filter will be awoken.
void cpBodySleepWithGroup(cpBody *body, cpBody *group)

When objects in Chipmunk sleep, they sleep as a group of all objects that are touching or jointed together. When an object is woken up, all of the objects in it’s group are woken up. cpBodySleepWithGroup() allows you group sleeping objects together. It acts identically to cpBodySleep() if you pass NULL as group by starting a new group. If you pass a sleeping body for group, body will be awoken when group is awoken. You can use this to initialize levels and start stacks of objects in a pre-sleeping state.

Iterators

typedef void (*cpBodyShapeIteratorFunc)(cpBody *body, cpShape *shape, void *data)
void cpBodyEachShape(cpBody *body, cpBodyShapeIteratorFunc func, void *data)

Call func once for each shape that is attached to body and added to a space. data is passed along as a context value. It is safe to remove shapes using these callbacks.

typedef void (*cpBodyConstraintIteratorFunc)(cpBody *body, cpConstraint *constraint, void *data)
void cpBodyEachConstraint(cpBody *body, cpBodyConstraintIteratorFunc func, void *data)

Call func once for each constraint that is attached to body and added to a space. data is passed along as a context value. It is safe to remove constraints using thes callbacks.

typedef void (*cpBodyArbiterIteratorFunc)(cpBody *body, cpArbiter *arbiter, void *data)
void cpBodyEachArbiter(cpBody *body, cpBodyArbiterIteratorFunc func, void *data)

This one is more interesting. Calls func once for each collision pair that body is involved in. Calling cpArbiterGet[Bodies|Shapes]() or CP_ARBITER_GET_[BODIES|SHAPES]() will return the body or shape for body as the first argument. You can use this to check all sorts of collision information for a body like if it’s touching the ground, another particular object, how much collision force is being applied to an object, etc. Sensor shapes and arbiters that have been rejected by a collision handler callback or cpArbiterIgnore() are not tracked by the contact graph.

Note: If your compiler supports blocks (such as Clang), there are an alternate set of functions you can call. cpBodyEachShape_b(), etc. See chipmunk.h for more information.

Integration Callbacks:

This section is a stub. For now you can look at the Planet demo for an example of how to use integration callbacks to implement planetary gravity.

Misc Functions:

  • cpBool cpBodyIsStatic(const cpBody *body) – Returns true if body is a static body. Either cpSpace.staticBody, a body created with cpBodyNewStatic() or cpBodyInitStatic().
  • cpBool cpBodyIsRogue(const cpBody *body) – Returns true if body has never been added to a space.

Notes:

  • Use forces to modify the rigid bodies if possible. This will be the most stable.
  • Modifying a body’s velocity shouldn’t necessarily be avoided, but applying large changes every frame can cause strange results in the simulation. Experiment freely, but be warned.
  • Don’t modify a body’s position every step unless you really know what you are doing. Otherwise you’re likely to get the position/velocity badly out of sync.
  • If you free a body before calling cpSpaceRemoveShape() on the shapes attached to it, you will cause crashes.

Chipmunk Collision Shapes: cpShape

There are currently 3 collision shape types:

  • Circles: Fastest and simplest collision shape.
  • Line segments: Meant mainly as a static shape. Can be beveled in order to give them a thickness.
  • Convex polygons: Slowest, but most flexible collision shape.

You can add as many shapes to a body as you wish. That is why the two types are separate. This should give you the flexibility to make any shape you want as well providing different areas of the same object with different friction, elasticity or callback values.

When creating different types of shapes, you will always be given a cpShape* pointer back. This is because Chipmunk shapes are meant to be opaque types. Think of the specific collision types such as cpCircleShape, cpSegmentShape and cpPolyShape as private subclasses of cpShape. You can still read some properties from them using the getter functions, but you are not intended to cast cpShape pointers to their specific types.

Notes:

  • Chipmunk didn’t support segment/segment collisions until v6.1.2. For compatibility reasons, you must explicitly and globally enable them by calling cpEnableSegmentToSegmentCollisions(). (Thanks to LegoCylon for his help with this)

Properties:

Chipmunk provides getter/setter functions for a number of properties on collision shapes. Setting most properties automatically wakes the rigid body they are attached to up if it was sleeping. You can also set some of the fields directly on the cpShape struct if you wish. They are documented in the headers.

cpBody * cpShapeGetBody(const cpShape *shape)
void cpShapeSetBody(cpShape *shape, cpBody *body)

The rigid body the shape is attached to. Can only be set when the shape is not added to a space.

cpBB cpShapeGetBB(const cpShape *shape)

The bounding box of the shape. Only guaranteed to be valid after cpShapeCacheBB() or cpSpaceStep() is called. Moving a body that a shape is connected to does not update it’s bounding box. For shapes used for queries that aren’t attached to bodies, you can also use cpShapeUpdate().

cpBool cpShapeGetSensor(const cpShape *shape)
void cpShapeSetSensor(cpShape *shape, cpBool value)

A boolean value if this shape is a sensor or not. Sensors only call collision callbacks, and never generate real collisions.

cpFloat cpShapeGetElasticity(const cpShape *shape)
void cpShapeSetElasticity(cpShape *shape, cpFloat value)

Elasticity of the shape. A value of 0.0 gives no bounce, while a value of 1.0 will give a “perfect” bounce. However due to inaccuracies in the simulation using 1.0 or greater is not recommended however. The elasticity for a collision is found by multiplying the elasticity of the individual shapes together.

cpFloat cpShapeGetFriction(const cpShape *shape)
void cpShapeSetFriction(cpShape *shape, cpFloat value)

Friction coefficient. Chipmunk uses the Coulomb friction model, a value of 0.0 is frictionless. The friction for a collision is found by multiplying the friction of the individual shapes together. Tables of friction coefficients.

cpVect cpShapeGetSurfaceVelocity(const cpShape *shape)
void cpShapeSetSurfaceVelocity(cpShape *shape, cpVect value)

The surface velocity of the object. Useful for creating conveyor belts or players that move around. This value is only used when calculating friction, not resolving the collision.

cpCollisionType cpShapeGetCollisionType(const cpShape *shape)
void cpShapeSetCollisionType(cpShape *shape, cpCollisionType value)

You can assign types to Chipmunk collision shapes that trigger callbacks when objects of certain types touch. See the callbacks section for more information.

cpGroup cpShapeGetGroup(const cpShape *shape)
void cpShapeSetGroup(cpShape *shape, cpGroup value)

Shapes in the same non-zero group do not generate collisions. Useful when creating an object out of many shapes that you don’t want to self collide. Defaults to CP_NO_GROUP.

cpLayers cpShapeGetLayers(const cpShape *shape)
void cpShapeSetLayers(cpShape *shape, cpLayers value)

Shapes only collide if they are in the same bit-planes. i.e. (a->layers & b->layers) != 0 By default, a shape occupies all bit-planes. Wikipedia has a nice article on bitmasks if you are unfamiliar with how to use them. Defaults to CP_ALL_LAYERS.

cpSpace* cpShapeGetSpace(const cpShape *shape)

Get the cpSpace that shape has been added to.

cpDataPointer cpShapeGetUserData(const cpShape *shape)
void cpShapeSetUserData(cpShape *shape, cpDataPointer value)

A user definable data pointer. If you set this to point at the game object the shapes is for, then you can access your game object from Chipmunk callbacks.

Filtering Collisions:

Chipmunk has two primary means of ignoring collisions: groups and layers.

Groups are meant to ignore collisions between parts on a complex object. A ragdoll is a good example. When jointing an arm onto the torso, you’ll want them to allow them to overlap. Groups allow you to do exactly that. Shapes that have the same group don’t generate collisions. So by placing all of the shapes in a ragdoll in the same group, you’ll prevent it from colliding against other parts of itself.

Layers allow you to separate collision shapes into mutually exclusive planes. Shapes can be in more than one layer, and shapes only collide with other shapes that are in at least one of the same layers. As a simple example, say shape A is in layer 1, shape B is in layer 2, and shape C is in layer 1 and 2. Shape A and B won’t collide with each other, but shape C will collide with both A and B.

Layers can also be used to set up rule based collisions. Say you have four types of shapes in your game. The player, the enemies, player bullets and enemy bullets. The are that the player should collide with enemies, and bullets shouldn’t collide with the type (player or enemy) that fired them. Making a chart would look like this:

Player Enemy Player Bullet Enemy Bullet
Player (1) (2)
Enemy (3)
Player Bullet
Enemy Bullet

The ‘-’s are for redundant spots in the chart, and the numbers are spots where types should collide. You can use a layer for each rule that you want to define. Then add the layers to each type: The player should be in layers 1 and 2, the enemy should be in layers 1 and 3, the player bullets should be in layer 3, and the enemy bullets should be in layer 2. Treating layers as rules this way, you can define up to 32 rules. The default cpLayers type is unsigned int which has a resolution of 32 bits on most systems. You can redefine the cpLayers type in chipmunk_types.h if you need more bits to work with.

There is one last way of filtering collisions using collision handlers. See the section on callbacks for more information. While collision handlers can be more flexible, they are also the slowest method. So you try to use groups or layers first.

Memory Management Functions:

void cpShapeDestroy(cpShape *shape)
void cpShapeFree(cpShape *shape)

Destroy and Free functions are shared by all shape types. Allocation and initialization functions are specific to each shape type. See below.

Misc Functions:

  • cpBB cpShapeCacheBB(cpShape *shape) – Synchronizes shape with the body its attached to.
  • cpBB cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot) – Sets the position and rotation of the shape to
  • void cpResetShapeIdCounter(void) – Chipmunk keeps a counter so that every new shape is given a unique hash value to be used in the spatial hash. Because this affects the order in which the collisions are found and handled, you can reset the shape counter every time you populate a space with new shapes. If you don’t, there might be (very) slight differences in the simulation.

Working With Circle Shapes:

cpCircleShape *cpCircleShapeAlloc(void)
cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)
cpShape *cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)

body is the body to attach the circle to, offset is the offset from the body’s center of gravity in body local coordinates.

cpVect cpCircleShapeGetOffset(cpShape *circleShape)
cpFloat cpCircleShapeGetRadius(cpShape *circleShape)

Getters for circle shape properties. Passing as non-circle shape will throw an assertion.

Working With Segment Shapes:

cpSegmentShape* cpSegmentShapeAlloc(void)
cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius)
cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius)

body is the body to attach the segment to, a and b are the endpoints, and radius is the thickness of the segment.

cpVect cpSegmentShapeGetA(cpShape *shape)
cpVect cpSegmentShapeGetA(cpShape *shape)
cpVect cpSegmentShapeGetNormal(cpShape *shape)
cpFloat cpSegmentShapeGetRadius(cpShape *shape)

Getters for segment shape properties. Passing a non-segment shape will throw an assertion.

Working With Polygon Shapes:

cpPolyShape *cpPolyShapeAlloc(void)
cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)
cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)

body is the body to attach the poly to, verts is an array of cpVect structs defining a convex hull with a clockwise winding, offset is the offset from the body’s center of gravity in body local coordinates. An assertion will be thrown the vertexes are not convex or do not have a clockwise winding.

int cpPolyShapeGetNumVerts(cpShape *shape)
cpVect cpPolyShapeGetVert(cpShape *shape, int index)

Getters for poly shape properties. Passing a non-poly shape or an index that does not exist will throw an assertion.

Boxes:

Because boxes are so common in physics games, Chipmunk provides shortcuts to create box shaped polygons. The boxes will always be centered at the center of gravity of the body you are attaching them to. If you want to create an off-center box, you will need to use cpPolyShapeNew() or cpPolyShapeInit().

cpPolyShape *cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height)
cpShape *cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height)

Poly Shape Helper Functions:

  • cpBool cpPolyValidate(const cpVect *verts, const int numVerts) – Check if a vertex array is convex and with the correct winding.
  • cpVect cpCentroidForPoly(const int numVerts, const cpVect *verts) – Calculate the centroid for a polygon.
  • void cpRecenterPoly(const int numVerts, cpVect *verts) – Center a polygon to (0,0). Subtracts the centroid from each vertex.

Convex Hull Helper Functions:

int cpConvexHull(int count, cpVect *verts, cpVect *result, int *first, cpFloat tol)

Calculate the convex hull of a given set of points. Returns the count of points in the hull. result must be a pointer to a cpVect array with at least count elements. If result is NULL, then verts array wil be reduced instead. first is an optional pointer to an integer to store where the first vertex in the hull came from (i.e. verts[first] == result[0]) tol is the allowed amount to shrink the hull when simplifying it. A tolerance of 0.0 creates an exact hull.

#define CP_CONVEX_HULL(inputCount, inputVerts, outputCount_varName, outputVerts_varName)

Convenience macro for using cpConvexHull(). Creates an array on the stack using alloca() and then calls cpConvexHull(). Because the output array is created on the stack it doesn’t need to be freed.

Modifying cpShapes:

The short answer is that you can’t because the changes would be only picked up as a change to the position of the shape’s surface, but not it’s velocity. The long answer is that you can using the “unsafe” API as long as you realize that doing so will not result in realistic physical behavior. These extra functions are defined in a separate header chipmunk_unsafe.h.

Notes:

  • You can attach multiple collision shapes to a rigid body. This should allow you to create almost any shape you could possibly need.
  • Shapes attached to the same rigid body will never generate collisions. You don’t have to worry about overlap when attaching multiple shapes to a rigid body.
  • Make sure you add both the body and it’s collision shapes to a space. The exception is when you want to have an externally body or a body that you integrate yourself. In that case, only add the shape.

Chipmunk Spaces: cpSpace

Spaces in Chipmunk are the basic unit of simulation. You add rigid bodies, shapes and constraints to it and then step them all forward through time together.

What Are Iterations, and Why Should I care?

Chipmunk uses an iterative solver to figure out the forces between objects in the space. What this means is that it builds a big list of all of the collisions, joints, and other constraints between the bodies and makes several passes over the list considering each one individually. The number of passes it makes is the iteration count, and each iteration makes the solution more accurate. If you use too many iterations, the physics should look nice and solid, but may use up too much CPU time. If you use too few iterations, the simulation may seem mushy or bouncy when the objects should be solid. Setting the number of iterations lets you balance between CPU usage and the accuracy of the physics. Chipmunk’s default of 10 iterations is sufficient for most simple games.

Sleeping

New in Chipmunk 5.3 is the ability of spaces to disable entire groups of objects that have stopped moving to save CPU time as well as battery life. In order to use this feature you must do 2 things. The first is that you must attach all your static geometry to static bodies. Objects cannot fall asleep if they are touching a non-static rogue body even if it’s shapes were added as static shapes. The second is that you must enable sleeping explicitly by choosing a time threshold value for cpSpace.sleepTimeThreshold. If you do not set cpSpace.idleSpeedThreshold explicitly, a value will be chosen automatically based on the current amount of gravity.

Properties:

int cpSpaceGetIterations(const cpSpace *space)
void cpSpaceSetIterations(cpSpace *space, int value)

Iterations allow you to control the accuracy of the solver. Defaults to 10. See above for more information.

cpVect cpSpaceGetGravity(const cpSpace *space)
void cpSpaceSetGravity(cpSpace *space, cpVect value)

Global gravity applied to the space. Defaults to cpvzero. Can be overridden on a per body basis by writing custom integration functions.

cpFloat cpSpaceGetDamping(const cpSpace *space)
void cpSpaceSetDamping(cpSpace *space, cpFloat value)

Amount of simple damping to apply to the space. A value of 0.9 means that each body will lose 10% of it’s velocity per second. Defaults to 1. Like gravity can be overridden on a per body basis.

cpFloat cpSpaceGetIdleSpeedThreshold(const cpSpace *space)
void cpSpaceSetIdleSpeedThreshold(cpSpace *space, cpFloat value)

Speed threshold for a body to be considered idle. The default value of 0 means to let the space guess a good threshold based on gravity.

cpFloat cpSpaceGetSleepTimeThreshold(const cpSpace *space)
void cpSpaceSetSleepTimeThreshold(cpSpace *space, cpFloat value)

Time a group of bodies must remain idle in order to fall asleep. The default value of INFINITY disables the sleeping feature.

cpFloat cpSpaceGetCollisionSlop(const cpSpace *space)
void cpSpaceSetCollisionSlop(cpSpace *space, cpFloat value)

Amount of overlap between shapes that is allowed. It’s encouraged to set this as high as you can without noticable overlapping as it improves the stability. It defaults to 0.1.

cpFloat cpSpaceGetCollisionBias(const cpSpace *space)
void cpSpaceSetCollisionBias(cpSpace *space, cpFloat value)

Chipmunk allows fast moving objects to overlap, then fixes the overlap over time. Overlapping objects are unavoidable even if swept collisions are supported, and this is an efficient and stable way to deal with overlapping objects. The bias value controls what percentage of overlap remains unfixed after a second and defaults to ~0.2%. Valid values are in the range from 0 to 1, but using 0 is not recommended for stability reasons. The default value is calculated as cpfpow(1.0f - 0.1f, 60.0f) meaning that Chipmunk attempts to correct 10% of error ever 1/60th of a second. Note: Very very few games will need to change this value.

cpTimestamp cpSpaceGetCollisionPersistence(const cpSpace *space)
void cpSpaceSetCollisionPersistence(cpSpace *space, cpTimestamp value)

The number of frames the space keeps collision solutions around for. Helps prevent jittering contacts from getting worse. This defaults to 3 and very very very few games will need to change this value.

cpFloat cpSpaceGetCurrentTimeStep(const cpSpace *space)

Retrieves the current (if you are in a callback from cpSpaceStep()) or most recent (outside of a cpSpaceStep() call) timestep.

cpFloat cpSpaceIsLocked(const cpSpace *space)

Returns true when in a callback meaning that you cannot add/remove objects from the space. Can be used to choose to create a post-step callback instead.

cpDataPointer cpSpaceGetUserData(const cpSpace *space)
void cpSpaceSetUserData(cpSpace *space, cpDataPointer value)

A user definable data pointer. It’s useful to point this at the gamestate object or scene management object that owns the space.

cpBody * cpSpaceGetStaticBody(const cpSpace *space)

A dedicated static body for the space. You don’t have to use it, but because it’s memory is managed automatically with the space it’s very convenient. You can set its user data pointer to something helpful if you want for callbacks.

Memory Management Functions:

cpSpace* cpSpaceAlloc(void)
cpSpace* cpSpaceInit(cpSpace *space)
cpSpace* cpSpaceNew()

void cpSpaceDestroy(cpSpace *space)
void cpSpaceFree(cpSpace *space)

More standard Chipmunk memory functions.

void cpSpaceFreeChildren(cpSpace *space)

This function will free all of the shapes, bodies and joints that have been added to space. Does not free space. You will still need to call cpSpaceFree() on your own. You will probably never use this in a real game, as your gamestate or game controller should manage removing and freeing objects from the space.

Operations:

cpShape *cpSpaceAddShape(cpSpace *space, cpShape *shape)
cpShape *cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
cpBody *cpSpaceAddBody(cpSpace *space, cpBody *body)
cpConstraint *cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)

void cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
void cpSpaceRemoveBody(cpSpace *space, cpBody *body)
void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)

cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape)
cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body)
cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint)

These functions add and remove shapes, bodies and constraints from space. The add/remove functions cannot be called from within a callback other than a postStep() callback (which is different than a postSolve() callback!). Attempting to add or remove objects from the space while cpSpaceStep() is still executing will throw an assertion. See the callbacks section for more information. The add functions return the thing being added so that you can create and add something in one line. Be careful not to free bodies before removing shapes and constraints attached to them or you will cause crashes.. The contains functions allow you to check if an object has been added to the space or not.

Deprecated:

cpShape *cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)

Shapes attached to static bodies are automatically treated as static. There isn’t really a good reason to explicitly add static shapes anymore.

  • void cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape) – Use cpBodyActivateStatic() instead.

Spatial Indexing:

Chipmunk 6 officially supports 2 spatial indexes. The default is an axis-aligned bounding box tree inspired by the one used in the Bullet Physics library, but extended with my own collision pair caching to give the tree very good temporal coherence. The tree requires no tuning, and most games will find that they get much better performance using it. The other available index available is a spatial hash, which can be much faster when you have a very large number (1000s) of objects that are all the same size.

Occasionally, you might want to update the collision detection data for a shape. If you move a static shape or a static body you must do this to let Chipmunk know it needs to have it’s collision detection data updated. You may also want to manually update the collision data for normal shapes if you move them and still want to perform queries.

  • void cpSpaceReindexShape(cpSpace *space, cpShape *shape) – Reindex a specific shape.
  • void cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body) – Reindex all the shapes for a certain body.
  • void cpSpaceReindexStatic(cpSpace *space) – Reindex all static shapes. Generally updating only the shapes that changed is faster.

Iterators:

typedef void (*cpSpaceBodyIteratorFunc)(cpBody *body, void *data)
void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data)

Call func for each body in the space also passing along your data pointer. Sleeping bodies are included, but static and rogue bodies are not as they aren’t added to the space.

typedef void (*cpSpaceShapeIteratorFunc)(cpShape *shape, void *data)
void cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data)

Call func for each shape in the space also passing along your data pointer. Sleeping and static shapes are included.

typedef void (*cpSpaceConstraintIteratorFunc)(cpConstraint *constraint, void *data)
void cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data)

Call func for each constraint in the space also passing along your data pointer.

Note: If your compiler supports blocks (such as Clang), there are an alternate set of functions you can call. cpSpaceEachBody_b(), etc. See chipmunk.h for more information.

Simulating the Space:

void cpSpaceStep(cpSpace *space, cpFloat dt)

Update the space for the given time step. Using a fixed time step is highly recommended. Doing so can greatly increase the quality of the simulation. The easiest way to do constant timesteps is to simple step forward by 1/60th of a second (or whatever your target framerate is) for each frame regardless of how long it took to render. This works fine for many games, but a better way to do it is to separate your physics timestep and rendering. This is a good article on how to do that.

Enabling and Tuning the Spatial Hash:

If you have thousands of objects that are all approximately the same size, the spatial hash may be for you.

void cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count)

Switch the space to use a spatial hash instead of the bounding box tree.

The spatial hash data is fairly size sensitive. dim is the size of the hash cells. Setting dim to the average collision shape size is likely to give the best performance. Setting dim too small will cause the shape to be inserted into many cells, setting it too low will cause too many objects into the same hash slot.

count is the suggested minimum number of cells in the hash table. If there are too few cells, the spatial hash will return many false positives. Too many cells will be hard on the cache and waste memory. the Setting count to ~10x the number of objects in the space is probably a good starting point. Tune from there if necessary.

Using the spatial has visualization in the demo program you can see what I mean. The grey squares represent cells in the spatial hash. The darker the cell, the more objects have been mapped into that cell. A good dim size is when your objects fit nicely into the grid:

Notice the light grey meaning that each cell doesn’t have too many objects mapped onto it.

When you use too small a size, Chipmunk has to insert each object into a lot of cells. This can get expensive.

Notice that the grey cells are very small compared to the collision shapes.

When you use too big of a size, a lot of shapes will fit into each cell. Each shape has to be checked against every other shape in the cell, so this makes for a lot of unnecessary collision checks.

Notice the dark grey cells meaning that many objects are mapped onto them.

Chipmunk 6 also has an experimental single axis sort and sweep implementation. It can be very efficient on mobile games if your world is very long and flat like a racing game. See the code for cpSpaceUseSpatialHash() if you want to try enabling it.

Notes:

  • When removing objects from the space, make sure you remove any other objects that reference it. For instance, when you remove a body, remove the joints and shapes attached to it.
  • The number of iterations, and the size of the time step determine the quality of the simulation. More iterations, or smaller time steps increase the quality. Keep in mind that higher quality also means higher CPU usage.
  • Because static shapes are only rehashed when you request it, it’s possible to use a much higher count argument to cpHashResizeStaticHash() than to cpSpaceResizeActiveHash(). Doing so will use more memory but can improve performance if you have a lot of static shapes.

Chipmunk Constraints: cpConstraint

A constraint is something that describes how two bodies interact with each other. (how they constrain each other) Constraints can be simple joints that allow bodies to pivot around each other like the bones in your body, or they can be more abstract like the gear joint or motors.

What constraints are and what they are not:

Constraints in Chipmunk are all velocity based constraints. This means that they act primarily by synchronizing the velocity of two bodies. A pivot joint holds two anchor points on two separate bodies together by defining equations that say that the velocity of the anchor points must be the same and calculating impulses to apply to the bodies to try and keep it that way. A constraint takes a velocity as it’s primary input and produces a velocity change as it’s output. Some constraints, (joints in particular) apply velocity changes to correct differences in positions. More about this in the next section.

A spring connected between two bodies is not a constraint. It’s very constraint-like as it creates forces that affect the velocities of the two bodies, but a spring takes distances as input and produces forces as it’s output. If a spring is not a constraint, then why do I have two varieties of spring constraints you ask? The reason is because they are damped springs. The damping associated with the spring is a true constraint that creates velocity changes based on the relative velocities of the two bodies it links. As it is convenient to put a damper and a spring together most of the time, I figured I might as well just apply the spring force as part of the constraint instead of having a damper constraint and having the user calculate and apply their own spring forces separately.

Properties:

cpBody * cpConstraintGetA(const cpConstraint *constraint)
cpBody * cpConstraintGetB(const cpConstraint *constraint)

Getters for the two bodies the constraint is attached to.

cpFloat cpConstraintGetMaxForce(const cpConstraint *constraint)
void cpConstraintSetMaxForce(cpConstraint *constraint, cpFloat value)

The maximum force that the constraint can use to act on the two bodies. Defaults to INFINITY.

cpFloat cpConstraintGetErrorBias(const cpConstraint *constraint)
void cpConstraintSetErrorBias(cpConstraint *constraint, cpFloat value)

The percentage of joint error that remains unfixed after a second. This works exactly the same as the collision bias property of a space, but applies to fixing error (stretching) of joints instead of overlapping collisions.

cpFloat cpConstraintGetMaxBias(const cpConstraint *constraint)
void cpConstraintSetMaxBias(cpConstraint *constraint, cpFloat value)

The maximum speed at which the constraint can apply error correction. Defaults to INFINITY.

cpSpace* cpConstraintGetSpace(const cpConstraint *constraint)

Get the cpSpace that constraint has been added to.

cpDataPointer cpConstraintGetUserData(const cpConstraint *constraint)
void cpConstraintSetUserData(cpConstraint *constraint, cpDataPointer value)

User data pointer. Use this pointer to get a reference to the game object that owns this constraint from callbacks.

cpFloat cpConstraintGetImpulse(cpConstraint *constraint)

The most recent impulse that constraint applied. To convert this to a force, divide by the timestep passed to cpSpaceStep(). You can use this to implement breakable joints to check if the force they attempted to apply exceeded a certain threshold.

To access properties of specific joint types, use the getter and setter functions provided (ex: cpPinJointGetAnchr1()). See the lists of properties for more information.

Error correction by Feedback:

Joints in Chipmunk are not perfect. A pin joint can’t maintain the exact correct distance between it’s anchor points, nor can a pivot joint hold it’s anchor points completely together. Instead, they are designed to deal with this by correcting themselves over time. In Chipmunk 5, you have a fair amount of extra control over how joints correct themselves and can even use this ability to create physical effects that allow you to use joints in unique ways:

  • Servo motors – Ex: open/close doors or rotate things without going over a maximum force.
  • Winches – Pull one object towards another at a constant speed without going over a maximum force.
  • Mouse manipulation – Interact with objects smoothly given coarse/shaky mouse input.

There are three properties of cpConstraint structs that control the error correction, maxForce, maxBias, and biasCoef. maxForce is pretty self explanatory, a joint or constraint will not be able to use more than this amount of force in order to function. If it needs more force to be able to hold itself together, it will fall apart. maxBias is the maximum speed at which error correction can be applied. If you change a property on a joint so that the joint will have to correct itself, it normally does so very quickly. By setting a maxSpeed you can make the joint work like a servo, correcting itself at a constant rate over a longer period of time. Lastly, biasCoef is the percentage of error corrected every step before clamping to a maximum speed. You can use this to make joints correct themselves smoothly instead of at a constant speed, but is probably the least useful of the three properties by far.

Constraints and Collision Shapes:

Neither constraints or collision shapes have any knowledge of the other. When connecting joints to a body the anchor points don’t need to be inside of any shapes attached to the body and it often makes sense that they shouldn’t. Also, adding a constraint between two bodies doesn’t prevent their collision shapes from colliding. In fact, this is the primary reason that the collision group property exists.

Video Tour of Current Joint Types. (Requires connection to YouTube)

Shared Memory Management Functions:

void cpConstraintDestroy(cpConstraint *constraint)
void cpConstraintFree(cpConstraint *constraint)

Destroy and Free functions are shared by all joint types. Allocation and initialization functions are specific to each joint type.

Constraint Types:

Pin Joints:

cpPinJoint *cpPinJointAlloc(void)
cpPinJoint *cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
cpConstraint *cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)

a and b are the two bodies to connect, and anchr1 and anchr2 are the anchor points on those bodies. The distance between the two anchor points is measured when the joint is created. If you want to set a specific distance, use the setter function to override it.

Properties

  • cpVect cpPinJointGetAnchr1(const cpConstraint *constraint)
  • void cpPinJointSetAnchr1(cpConstraint *constraint, cpVect value)
  • cpVect cpPinJointGetAnchr2(const cpConstraint *constraint)
  • void cpPinJointSetAnchr2(cpConstraint *constraint, cpVect value)
  • cpFloat cpPinJointGetDist(const cpConstraint *constraint)
  • void cpPinJointSetDist(cpConstraint *constraint, cpFloat value)

Slide Joints:

cpSlideJoint *cpSlideJointAlloc(void)

cpSlideJoint *cpSlideJointInit(
	cpSlideJoint *joint, cpBody *a, cpBody *b,
	cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max
)

cpConstraint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)

a and b are the two bodies to connect, anchr1 and anchr2 are the anchor points on those bodies, and min and max define the allowed distances of the anchor points.

Properties

  • cpVect cpSlideJointGetAnchr1(const cpConstraint *constraint)
  • void cpSlideJointSetAnchr1(cpConstraint *constraint, cpVect value)
  • cpVect cpSlideJointGetAnchr2(const cpConstraint *constraint)
  • void cpSlideJointSetAnchr2(cpConstraint *constraint, cpVect value)
  • cpFloat cpSlideJointGetMin(const cpConstraint *constraint)
  • void cpSlideJointSetMin(cpConstraint *constraint, cpFloat value)
  • cpFloat cpSlideJointGetMax(const cpConstraint *constraint)
  • void cpSlideJointSetMax(cpConstraint *constraint, cpFloat value)

Pivot Joints:

cpPivotJoint *cpPivotJointAlloc(void)
cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect pivot)
cpConstraint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)
cpConstraint *cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)

a and b are the two bodies to connect, and pivot is the point in world coordinates of the pivot. Because the pivot location is given in world coordinates, you must have the bodies moved into the correct positions already. Alternatively you can specify the joint based on a pair of anchor points, but make sure you have the bodies in the right place as the joint will fix itself as soon as you start simulating the space.

Properties

  • cpVect cpPivotJointGetAnchr1(const cpConstraint *constraint)
  • void cpPivotJointSetAnchr1(cpConstraint *constraint, cpVect value)
  • cpVect cpPivotJointGetAnchr2(const cpConstraint *constraint)
  • void cpPivotJointSetAnchr2(cpConstraint *constraint, cpVect value)

Groove Joint:

cpGrooveJoint *cpGrooveJointAlloc(void)

cpGrooveJoint *cpGrooveJointInit(
	cpGrooveJoint *joint, cpBody *a, cpBody *b,
	cpVect groove_a, cpVect groove_b, cpVect anchr2
)

cpConstraint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)

The groove goes from groov_a to groove_b on body a, and the pivot is attached to anchr2 on body b. All coordinates are body local.

Properties

  • cpVect cpGrooveJointGetGrooveA(const cpConstraint *constraint)
  • void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value)
  • cpVect cpGrooveJointGetGrooveB(const cpConstraint *constraint)
  • void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value)
  • cpVect cpGrooveJointGetAnchr2(const cpConstraint *constraint)
  • void cpGrooveJointSetAnchr2(cpConstraint *constraint, cpVect value)

Damped Spring:

cpDampedSpring *cpDampedSpringAlloc(void)

cpDampedSpring *cpDampedSpringInit(
	cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2,
	cpFloat restLength, cpFloat stiffness, cpFloat damping
)

cpConstraint *cpDampedSpringNew(
	cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2,
	cpFloat restLength, cpFloat stiffness, cpFloat damping
)

Defined much like a slide joint. restLength is the distance the spring wants to be, stiffness is the spring constant (Young’s modulus), and damping is how soft to make the damping of the spring.

Properties

  • cpVect cpDampedSpringGetAnchr1(const cpConstraint *constraint)
  • void cpDampedSpringSetAnchr1(cpConstraint *constraint, cpVect value)
  • cpVect cpDampedSpringGetAnchr2(const cpConstraint *constraint)
  • void cpDampedSpringSetAnchr2(cpConstraint *constraint, cpVect value)
  • cpFloat cpDampedSpringGetRestLength(const cpConstraint *constraint)
  • void cpDampedSpringSetRestLength(cpConstraint *constraint, cpFloat value)
  • cpFloat cpDampedSpringGetStiffness(const cpConstraint *constraint)
  • void cpDampedSpringSetStiffness(cpConstraint *constraint, cpFloat value)
  • cpFloat cpDampedSpringGetDamping(const cpConstraint *constraint)
  • void cpDampedSpringSetDamping(cpConstraint *constraint, cpFloat value)

Damped Rotary Spring:

cpDampedRotarySpring *cpDampedRotarySpringAlloc(void)

cpDampedRotarySpring *cpDampedRotarySpringInit(
	cpDampedRotarySpring *joint, cpBody *a, cpBody *b,
	cpFloat restAngle, cpFloat stiffness, cpFloat damping
)

cpConstraint *cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping)

Like a damped spring, but works in an angular fashion. restAngle is the relative angle in radians that the bodies want to have, stiffness and damping work basically the same as on a damped spring.

Properties

  • cpFloat cpDampedRotarySpringGetRestAngle(const cpConstraint *constraint)
  • void cpDampedRotarySpringSetRestAngle(cpConstraint *constraint, cpFloat value)
  • cpFloat cpDampedRotarySpringGetStiffness(const cpConstraint *constraint)
  • void cpDampedRotarySpringSetStiffness(cpConstraint *constraint, cpFloat value)
  • cpFloat cpDampedRotarySpringGetDamping(const cpConstraint *constraint)
  • void cpDampedRotarySpringSetDamping(cpConstraint *constraint, cpFloat value)

Rotary Limit Joint:

cpRotaryLimitJoint *cpRotaryLimitJointAlloc(void)
cpRotaryLimitJoint *cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max)
cpConstraint *cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max)

Constrains the relative rotations of two bodies. min and max are the angular limits in radians. It is implemented so that it’s possible to for the range to be greater than a full revolution.

Properties

  • cpFloat cpRotaryLimitJointGetMin(const cpConstraint *constraint)
  • void cpRotaryLimitJointSetMin(cpConstraint *constraint, cpFloat value)
  • cpFloat cpRotaryLimitJointGetMax(const cpConstraint *constraint)
  • void cpRotaryLimitJointSetMax(cpConstraint *constraint, cpFloat value)

Ratchet Joint:

cpRatchetJoint *cpRatchetJointAlloc(void);
cpRatchetJoint *cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
cpConstraint *cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);

Works like a socket wrench. ratchet is the distance between “clicks”, phase is the initial offset to use when deciding where the ratchet angles are.

Properties

  • cpFloat cpRatchetJointGetAngle(const cpConstraint *constraint)
  • void cpRatchetJointSetAngle(cpConstraint *constraint, cpFloat value)
  • cpFloat cpRatchetJointGetPhase(const cpConstraint *constraint)
  • void cpRatchetJointSetPhase(cpConstraint *constraint, cpFloat value)
  • cpFloat cpRatchetJointGetRatchet(const cpConstraint *constraint)
  • void cpRatchetJointSetRatchet(cpConstraint *constraint, cpFloat value)

Gear Joint:

cpGearJoint *cpGearJointAlloc(void);
cpGearJoint *cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
cpConstraint *cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);

Keeps the angular velocity ratio of a pair of bodies constant. ratio is always measured in absolute terms. It is currently not possible to set the ratio in relation to a third body’s angular velocity. phase is the initial angular offset of the two bodies.

Properties

  • cpFloat cpGearJointGetPhase(const cpConstraint *constraint)
  • void cpGearJointSetPhase(cpConstraint *constraint, cpFloat value)
  • cpFloat cpGearJointGetRatio(const cpConstraint *constraint)
  • void cpGearJointSetRatio(cpConstraint *constraint, cpFloat value)

Simple Motor:

cpSimpleMotor *cpSimpleMotorAlloc(void);
cpSimpleMotor *cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate);
cpConstraint *cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate);

Keeps the relative angular velocity of a pair of bodies constant. rate is the desired relative angular velocity. You will usually want to set an force (torque) maximum for motors as otherwise they will be able to apply a nearly infinite torque to keep the bodies moving.

Properties

  • cpFloat cpSimpleMotorGetRate(const cpConstraint *constraint)
  • void cpSimpleMotorSetRate(cpConstraint *constraint, cpFloat value)

Notes:

  • You can add multiple joints between two bodies, but make sure that they don’t fight. Doing so can cause the bodies jitter or spin violently.

Overview of Collision Detection in Chipmunk:

In order to make collision detection in Chipmunk as fast as possible, the process is broken down into several stages. While I’ve tried to keep it conceptually simple, the implementation can be a bit daunting. Fortunately as a user of the library, you don’t need to understand everything about how it works. Though if you are trying to squeeze every ounce of performance out of Chipmunk, understanding this section can be helpful.

Spatial Indexing:

A for loop that checks every object against every other object in the scene would be very slow. So the first stage of the collision detection (or broadphase as it is commonly called), is to use a high level spatial algorithm to figure out which objects should be even be checked for collisions. Currently Chipmunk supports two spatial indexes, an axis-aligned bounding box tree and a spatial hash. These spatial indexes are able to quickly identify which shapes are near each other and should be checked for a collision.

Collision Filtering:

After the spatial index figures out which pairs of shapes are likely to be near each other, it passes them back to the space to perform some additional filtering on the pairs. Before doing anything else, Chipmunk performs a few quick tests to check if shapes should collide.

  • Bounding Box Test: The shapes are not colliding if their bounding boxes are not overlapping. Objects like diagonal line segments can trigger a lot of false positives here, but it’s unlikely to be something you should worry about.
  • Layer Test: The shapes are not colliding if they don’t occupy any of the same layers. (the bitwise AND of their layer masks is 0)
  • Group Test: Shapes shouldn’t collide with other shapes in the same non-zero group.

Primitive Shape to Shape Collision Detection:

The most expensive test is to actually check for overlap based on their geometry. Circle to circle and circle to line collisions are pretty quick. Poly to poly collisions get more expensive as the number of vertexes increases. Simpler shapes make for faster collisions (and more importantly fewer collision points for the solver to run). Chipmunk uses a small dispatch table to figure out which function to use to check if the shapes overlap.

Collision Handler Filtering:

After checking if two shapes overlap Chipmunk will look to see if you have defined a collision handler for the collision types of the shapes. This is vital to process collisions events for the gameplay, but also gives you a very flexible way to filter out collisions. The return value of the begin() and preSolve() callbacks determines whether or not the colliding pair of shapes is discarded or not. Returning true will keep the pair, false will discard it. Rejecting a collision from a begin() callback is permanent, rejecting it from the preSolve() only applies to the step it occured in. If you don’t define a handler for the given collision_types, Chipmunk will call the space’s default handler, which by default is defined to simply accept all collisions.

While using callbacks to filter collisions is the most flexible way, keep in mind that by the time your callback is called all of the most expensive collision detection has already been done. For simulations with a lot of colliding objects each frame, the time spent finding collisions is small compared to the time spent solving the physics for them so it may not be a big deal. Still, use layers or groups first if you can.

Collision Callbacks:

A physics library without any events or feedback would not be very useful for games. How would you know when the player bumped into an enemy so that you could take some health points away? How would you know how hard the car hit something so you don’t play a loud crash noise when a pebble hits it? What if you need to decide if a collision should be ignored based on specific conditions, like implementing one way platforms? Chipmunk has a number of powerful callback systems that you can plug into to accomplish all of that.

Collision Handlers:

A collision handler is a set of 4 function callbacks for the different collision events that Chipmunk recognizes. The event types are:

  • begin(): Two shapes just started touching for the first time this step. Return true from the callback to process the collision normally or false to cause Chipmunk to ignore the collision entirely. If you return false, the preSolve() and postSolve() callbacks will never be run, but you will still recieve a separate event when the shapes stop overlapping.
  • preSolve(): Two shapes are touching during this step. Return false from the callback to make Chipmunk ignore the collision this step or true to process it normally. Additionally, you may override collision values such as cpArbiter.e and cpArbiter.u to provide custom friction or elasticity values. See cpArbiter for more info.
  • postSolve(): Two shapes are touching and their collision response has been processed. You can retrieve the collision force at this time if you want to use it to calculate sound volumes or damage amounts. See cpArbiter for more info.
  • separate(): Two shapes have just stopped touching for the first time this step. To ensure that begin()/separate() are always called in balanced pairs, it will also be called when removing a shape while its in contact with something or when deallocating the space.

Collision callbacks are closely associated with cpArbiter structs. You should familiarize yourself with those as well.

Note: Shapes tagged as sensors (cpShape.sensor == true) never generate collisions that get processed so collisions between sensors shapes and other shapes will never call the postSolve() callback. They still generate begin(), and separate() callbacks, and the preSolve() callback is also called every frame even though there is no real collision.

Note #2: preSolve() callbacks are called before the sleeping algorithm runs. If an object falls asleep, it’s postSolve() callback won’t be called until it’s reawoken.

Collision Handler API:

typedef int (*cpCollisionBeginFunc)(cpArbiter *arb, struct cpSpace *space, void *data)
typedef int (*cpCollisionPreSolveFunc)(cpArbiter *arb, cpSpace *space, void *data)
typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, cpSpace *space, void *data)
typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, cpSpace *space, void *data)

Collision handler function types. While all of them take an arbiter, space, and a user data pointer, only the begin() and preSolve() callbacks return a value. See above for more information.

void cpSpaceAddCollisionHandler(
	cpSpace *space,
	cpCollisionType a, cpCollisionType b,
	cpCollisionBeginFunc begin,
	cpCollisionPreSolveFunc preSolve,
	cpCollisionPostSolveFunc postSolve,
	cpCollisionSeparateFunc separate,
	void *data
)

Add a collision handler for given collision type pair. Whenever a shapes with collision type (cpShape.collision_type) a and collision type b collide, these callbacks will be used to process the collision. data is a user definable context pointer that is passed to each of the callbacks. NULL can be provided for callbacks you do not wish to implement, however Chipmunk will call it’s own default versions for these and not the default ones you’ve set up for the space. If you need to fall back on the space’s default callbacks, you’ll have to provide them individually to each handler definition.

void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b)

Remove a collision handler for a given collision type pair.

void cpSpaceSetDefaultCollisionHandler(
	cpSpace *space,
	cpCollisionBeginFunc begin,
	cpCollisionPreSolveFunc preSolve,
	cpCollisionPostSolveFunc postSolve,
	cpCollisionSeparateFunc separate,
	void *data
)

Register a default collision handler to be used when no specific collision handler is found. The space is given a default handler when created that returns true for all collisions in begin() and preSolve() and does nothing in the postSolve() and separate() callbacks.

Post-Step Callbacks:

Post-step callbacks are the one place where you can break the rules about adding or removing objects from within a callback. In fact, their primary function is to help you safely remove objects from the space that you wanted to disable or destroy in a collision or query callback.

Post step callbacks are registered as a function and a pointer that is used as a key. You can only register one postStep() callback per key. This prevents you from accidentally removing an object more than once. For instance, say that you get a collision callback between a bullet and object A. You want to destroy both the bullet and object A, so you register a postStep() callback to safely remove them from your game. Then you get a second collision callback between the bullet and object B. You register a postStep() callback to remove object B, and a second postStep() callback to remove the bullet. Because you can only register one callback per key, the postStep() callback for the bullet will only be called once and you can’t accidentally try to remove it twice.

typedef void (*cpPostStepFunc)(cpSpace *space, void *obj, void *data)

Function type used for postStep() callbacks. space is the space the callback was registered on, obj is the pointer value you supplied as the key, and data is a user definable pointer you can use to pass in as a context value.

cpBool cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data);

Add func to be called before cpSpaceStep() returns. key and data will be passed to your function. Only the first callback registered for any unique value of key will be recorded. It returns true if the callback is scheduled and false when the key has already been used. You can add postStep() callbacks from outside of other callback functions, but there isn’t a good reason to and they won’t be called until the next time cpSpaceStep() is finishing.

Note: Post-step callbacks are not run in any particular order. If you need to sequence a number of events, you’ll need to put them in a single callback.

Examples:

See the callback examples for more information.

Chipmunk Collision Pairs: cpArbiter

Chipmunk’s cpArbiter struct encapsulates a pair of colliding shapes and all of the data about their collision.

Why are they called arbiters? The short answer is that I kept using the word “arbitrates” to describe the way that collisions were resolved and then I saw that Box2D actually called them arbiters way back in 2006 when I was looking at its solver. An arbiter is like a judge, a person that has authority to settle disputes between two people. It was a fun, fitting name and was shorter to type than CollisionPair which I had been using. It was originally meant to be a private internal structure only, but evolved to be useful from callbacks.

Memory Management:

You will never need to create or free an arbiter. More importantly, because they are entirely managed by the space you should never store a reference to an arbiter as you don’t know when they will be recycled. Use them within the callback where they are given to you and then forget about them or copy out the information you need.

Properties:

cpFloat cpArbiterGetElasticity(const cpArbiter *arb)
void cpArbiterSetElasticity(cpArbiter *arb, cpFloat value)

The calculated elasticity for this collision pair. Setting the value in a preSolve() callback will override the value calculated by the space.

cpFloat cpArbiterGetFriction(const cpArbiter *arb)
void cpArbiterSetFriction(cpArbiter *arb, cpFloat value)

The calculated friction for this collision pair. Setting the value in a preSolve() callback will override the value calculated by the space.

cpVect cpArbiterGetSurfaceVelocity(const cpArbiter *arb)
void cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect value)

The calculated surface velocity for this collision pair. Setting the value in a preSolve() callback will override the value calculated by the space.

cpDataPointer cpArbiterGetUserData(const cpArbiter *arb)
void cpArbiterSetUserData(cpArbiter *arb, cpDataPointer data)

A user definable pointer. The value will persist for the pair of shapes until the separate() callback is called.

NOTE: If you need to clean up this pointer, you should implement the separate() callback to do it. Also be careful when destroying the space as there may be active collisions still. In order to trigger the separate() callbacks, youll need to remove all the shapes from the space before disposing of it. This is something I’d suggest doing anyway. See ChipmunkDemo.c:ChipmunkDemoFreeSpaceChildren() for an example of how to do it easily.

int cpArbiterGetCount(const cpArbiter *arb)
cpVect cpArbiterGetNormal(const cpArbiter *arb, int i)
cpVect cpArbiterGetPoint(const cpArbiter *arb, int i)
cpFloat cpArbiterGetDepth(const cpArbiter *arb, int i)

Get the number of contacts tracked by this arbiter or the specific collision point, collision normal or penetration depth of a collision point.

cpBool cpArbiterIsFirstContact(const cpArbiter *arb)

Returns true if this is the first step the two shapes started touching. This can be useful for sound effects for instance. If it’s the first frame for a certain collision, check the energy of the collision in a postStep() callbock and use that to determine the volume of a sound effect to play.

void cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape **b)
void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody **b)

Get the shapes or bodies in the order that they were defined in the collision handler associated with this arbiter. If you defined the handler as cpSpaceAddCollisionHandler(space, 1, 2, ...), you you will find that a->collision_type == 1 and b->collision_type == 2.

Contact Point Sets:

Contact point sets make getting contact information simpler.

cpContactPointSet cpArbiterGetContactPointSet(const cpArbiter *arb)

Get a contact point set struct from an arbiter.

You might do something like the following to get and process a contact point set:

cpContactPointSet set = cpArbiterGetContactPointSet(arbiter);
for(int i=0; i<set.count; i++){
	// get and work with the collision point normal and penetration distance:
	set.points[i].point
	set.points[i].normal
	set.points[i].dist
}

Helper Functions:

void cpArbiterGetShapes(cpArbiter *arb, cpShape **a, cpShape **b)
void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody **b)

Get the shapes (or their bodies) in the order that they were defined in the collision handler associated with this arbiter. If you defined the handler as cpSpaceAddCollisionHandler(space, 1, 2, ...), you you will find that a->collision_type == 1 and b->collision_type == 2. The convenience macro defines and initializes the two shape variables for you. The default collision handler doesn’t use collision types so the order is undefined.

#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b)
#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);

Shortcut macros for defining variables for and retrieving the shapes/bodies for an arbiter.

cpVect cpArbiterTotalImpulseWithFriction(cpArbiter *arb);
cpVect cpArbiterTotalImpulse(cpArbiter *arb);

Returns the impulse that was applied this step to resolve the collision. These functions should only be called from a postStep() or cpBodyEachArbiter() callback, otherwise the result is undefined. If in doubt which function to use, use cpArbiterTotalImpulseWithFriction().

cpFloat cpArbiterTotalKE(const cpArbiter *arb);

Calculate the amount of energy lost in a collision including static, but not dynamic friction. This function should only be called from a postSolve(), postStep() or cpBodyEachArbiter() callback.

Queries:

Chipmunk spaces support four kinds of spatial queries, nearest point, segment, shape and fast bounding box queries. Any type can be performed efficiently against an entire space, and point and segment queries can be performed against individual shapes. All types of queries take a collision group and layer that are used to filter matches out using the same rules used for filtering collisions between shapes. See cpShape for more information. If you don’t want to filter out any matches, use CP_ALL_LAYERS for the layers and CP_NO_GROUP as the group.

Nearest Point Queries:

Point queries are useful for things like mouse picking and simple sensors. They allow you to check if there are shapes within a certain distance of a point, find the closest point on a shape to a given point or find the closest shape to a point.

typedef struct cpNearestPointQueryInfo {
	/// The nearest shape, NULL if no shape was within range.
	cpShape *shape;
	/// The closest point on the shape's surface. (in world space coordinates)
	cpVect p;
	/// The distance to the point. The distance is negative if the point is inside the shape.
	cpFloat d;
} cpNearestPointQueryInfo;

Nearest point queries return the point on the surface of the shape as well as the distance from the query point to the surface point.

cpFloat cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *out)

Find the distance from point to shape. If the point is inside of the shape, the distance will be negative and equal to the depth of the point.

typedef void (*cpSpaceNearestPointQueryFunc)(cpShape *shape, cpFloat distance, cpVect point, void *data);

void cpSpaceNearestPointQuery(
	cpSpace *space, cpVect point, cpFloat maxDistance,
	cpLayers layers, cpGroup group,
	cpSpaceNearestPointQueryFunc func, void *data
)

Query space at point for shapes within the given distance range filtering out matches with the given layers and group. func is called for each shape found along with the distance to the closest point on the shape’s surface, the distance to that point and the data argument passed to cpSpaceNearestPointQuery(). Sensor shapes are included. If a maxDistance of 0.0 is used, the point must lie inside a shape. Negative maxDistance is also allowed meaning that the point must be a under a certain depth within a shape to be considered a match.

cpShape *cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out)

Query space at point and return the closest shape within maxDistance units of distance. out is an optional pointer to a cpNearestPointQueryInfo if you want additional information about the match.

Segment Queries:

Segment queries are like ray casting, but because not all spatial indexes allow processing infinitely long ray queries it is limited to segments. In practice this is still very fast and you don’t need to worry too much about the performance as long as you aren’t using extremely long segments for your queries.

typedef struct cpSegmentQueryInfo {
	/// The shape that was hit, NULL if no collision occured.
	cpShape *shape;
	/// The normalized distance along the query segment in the range [0, 1].
	cpFloat t;
	/// The normal of the surface hit.
	cpVect n;
} cpSegmentQueryInfo;

Segment queries return more information than just a simple yes or no, they also return where a shape was hit and it’s surface normal at the hit point. t is the percentage between the query start and end points. If you need the hit point in world space or the absolute distance from start, see the segment query helper functions farther down.

cpBool cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)

Perform a segment query from a to b against a single shape shape. info must be a valid pointer to a cpSegmentQueryInfo structure which will be initialized with the raycast info.

typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data)

void cpSpaceSegmentQuery(
	cpSpace *space, cpVect start, cpVect end,
	cpLayers layers, cpGroup group,
	cpSpaceSegmentQueryFunc func, void *data
)

Query space along the line segment from start to end filtering out matches with the given layers and group. func is called with the normalized distance along the line and surface normal for each shape found along with the data argument passed to cpSpacePointQuery(). Sensor shapes are included.

cpShape *cpSpaceSegmentQueryFirst(
	cpSpace *space, cpVect start, cpVect end,
	cpLayers layers, cpGroup group,
	cpSegmentQueryInfo *info
)

Query space along the line segment from start to end filtering out matches with the given layers and group. Only the first shape encountered is returned and the search is short circuited. Returns NULL if no shape was found. The info struct pointed to by info will be initialized with the raycast info unless info is NULL. Sensor shapes are ignored.

Segment Query Helper Functions:

cpVect cpSegmentQueryHitPoint(cpVect start, cpVect end, cpSegmentQueryInfo info)

Return the hit point in world coordinates where the segment first intersected with the shape.

cpFloat cpSegmentQueryHitDist(cpVect start, cpVect end, cpSegmentQueryInfo info)

Return the absolute distance where the segment first hit the shape.

AABB Queries:

AABB queries give you a fast way to check roughly which shapes are in an area.

typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data)

void cpSpaceBBQuery(
	cpSpace *space, cpBB bb,
	cpLayers layers, cpGroup group,
	cpSpaceBBQueryFunc func, void *data
)

Query space to find all shapes near bb filtering out matches with the given layers and group. func is called for each shape whose bounding box overlaps bb along with the data argument passed to cpSpaceBBQuery(). Sensor shapes are included.

Shape Queries:

Shape queries allow you to check if shapes in a space are overlapping a specific area. You can use this to check if an object already exists at a location you want to add another shape, or to use as sensor queries for AI.

You can either create a body/shape pair before querying, or you can create a shape passing NULL for the body and position the shape using cpShapeUpdate() to set the position and rotation of the shape.

typedef void (*cpSpaceShapeQueryFunc)(cpShape *shape, cpContactPointSet *points, void *data);

cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data);

Query space to find all shapes overlapping shape. Matches are filtered using the layers and group of shape. func is called for each overlapping shape along with a pointer to a temporary cpContactPointSet and the data argument passed to cpSpaceBBQuery(). Sensor shapes are included.

Blocks:

If your compiler supports blocks (such as Clang), there are an alternate set of functions you can call. cpSpaceNearestPointQuery_b(), etc. See chipmunk.h for more information.

Examples:

See the query examples for more information.

Chipmunk-6.1.5/doc/stylesheet.css000644 000765 000000 00000001750 12151675775 017717 0ustar00slembckewheel000000 000000 h1, h2 { padding: 0.25em; border-radius: 0.25em; } h1 { background-color: #89b4cb; } h2 { background-color: lightGrey; } p { margin-left: 1em; } p.expl { margin-left: 2em; } code { color: #191970 } .HideShow { background-color: lightGrey; padding: 0.5em; border-radius: 1em; border: 2px grey solid; } .PopOpen { border-radius: 1em; border: 1px grey solid; } pre { border-radius: 0.75em; background-color: #F0F0F0; padding: 0.5em; margin-left: 1em; } /*ul { border-radius: 0.75em; background-color: #F0F0F0; margin-left: 1em; }*/ table { border: 2px solid black; border-collapse: collapse; margin-left: 1em; } table td, th { border: 1px black solid; padding: 0.5em; } h1 a:link, h2 a:link, h3 a:link, h1 a:visited, h2 a:visited, h3 a:visited { text-decoration:none; color:black; background-color:transparent } h1 a:hover, h2 a:hover, h3 a:hover, h1 a:active, h2 a:active, h3 a:active { text-decoration:underline; color:black; background-color:transparent } Chipmunk-6.1.5/doc/images/hash_just_right.png000644 000765 000000 00000025311 12151675775 022153 0ustar00slembckewheel000000 000000 ‰PNG  IHDRÅøÛi pHYs  šœ2iCCPPhotoshop ICC profilexÚ­’±kqÇ?wQ[¤ÄPÒNoê%´ƒ "I“Vjk iJ›€ÃõîšœÞ]~Þ]b#‚‹stEŠ(¸)E´£"H‹ÿ€nBA[Ïá¼Ë ÕÅ?ø¼Çã½ïûòƒÄ¶*„%¶ã»å³cÊBµ¦ôlÒ‡L/)Rªæ‰|©4Í®ñí#À‡cªÖÍ/wö¯ž¾ø¨~þùrþöËþIw¡Z)¤ë!ç€ôbÈ }Õ>H ­5T¤ë@Æ­” ­ÉzÈ/€äbÈo€d[«û mYG7{“ºái çS÷4ä' í±í¦‰gÀQM¸>$6€Ã ÕšJn‚3G@¾Õ­Õ\xú¶»µá"¤OÀÚýnmk ßzK£#H}.ìý[Cг;nü¸;!± ëW´–Ûþí—$½ƒåáÍaïýˆvãвð`æ©p7ÃóÐÿ J@%‡<:½ÐCLǰU¥hzÂR;ü÷°­V´«èsg.ÏÂ/U"öÚ³ã/™“ëjq*âkÂLÜãN”#¾¤ž+El8s³ñ|«4ÝÝ5÷Þølwfe>b·Už‹ørs*î×b¬Í±f♦?ë§€‰ƒŠB…J'ü›ûR°2$ÿàÕã¯xåË>@¡):®YoøJ^ËÈ(“Žv<£Œd³§øØÆ´áðŽt cHRMmus ö¯…™nšç»1}½v x(IDATxÚí] pUå¿$„ÇÃ+„æAxH[š W‘òŠ‚^©òQµ)à!¾:*AKµ& ²Ø1YÜ©]›lw»8ckÝigev»2Ý®º;íTûÚv¶Ý÷wîÿæäÜs¾ï;ß}ß›üÿóÍsÏýÎåœ_~ÿ×ïû<Ÿ³±±‰ì£>úXbøÈÃ? 66¡Yqâ#‡Í9B1rØØÂà:fo- ÎaoM9NÂaä°±©L†F[$Þ¡ˆ‘ÃÆ&EŽ¢¤ÃÈacsá?ç°±1ç°±%0Î1±ÄÈacsGçÖØØtÍl`Îac‹Ü[³Aˆ‘ÃÆæ‚!í0rØØTÞësØØbÃ9ì­±±…çıªÖ3(¶“8ŸŸ«ý¨Ï~øÃþ(Kâüø=?ꟕ'®•ݱóF¯]»vÏ=÷Üj‹-¢¿›µ¶¶ª¿_v?Œ!rÒÈ"{Þtæ'9êÞlÙí^¼xÑãñLY\1¦Ü9м…æŸ?Îv<:·×¾õÖ[š`ôÿ® 6Ó¡ëœT˜Ùó¦3?qÈQß“ó€uÎk¯½†§¿}ÍÓ=»ºƒcg—ä +ää®î¶ÛãÚï|ç;Šï—ݣŕsRÜs‹ìyÓ™Ÿ|oMç/Á‹/¾ˆ§¿sË6Tô ç™þÑZ÷®}çw>Ö3ëý0Zž·¦é›¹ÎO(rÔ)pÅÉ䨍Æ:BNvõ!ç0®½råJX?Dæ5rR™jžyæ™G}ô‘€–Ø©S§„çu¼ú¤qŽ,2Sœ'ätX‘#tØDç 9àœþ]FKÚq`“94Û©~øá‡:ÏIªpŽ衜#÷ÍDD¤ðÖ\ï‡ÑrRˆÀ3øuqíùºo½« ¯Ž!øàƒèûK⛕ևP°z×YU%Gâ¶ 9GBŒMÎ>Íxˆ'L˜€~VžQšìííM@DÈA%G—j,²qŽúùL2çhê%ì¹5Q—M(`ºdõÖçDõs „Üÿý#FŒÀ}ääÂy­w,éØãM›6% [ ˆs{4³²ÜZësÄÞš´jë!pé¾a}N¬âœîîîU«VQËx_Ŷõ·õ4ÓÀ[`)2D5ª2é­Ï õÖT8q|Ô½Ò¬ÏÑ7¼ð K—.%ÌLôϾ¥ó Åßs0ãÕ×¾ᱎ·>dž+½¸&¦õ½µ´Ñçz´õ9²îÖçÄ„sNž<9mÚ4#˜ñŸÞts}×-¡ãàèêI{â]ççÖ¥„cíÇQô¤«>íßø/uo=>§ù a´ñq=G9f([4²²¥Þ•~ÌÐL¦$[2½µF]ÎúBNeÑÌê •4ªŠf›Ç¾ÒÚ/”ÖâÕW²ÐGÆCn-K5²>'ä ˜A¬OŽhxp‚ÄI;ä¹c ¨¸& 4ã¡ç6§¶YöG6]õ9øÏÀž5kÖl‹™o'Nœ8Ébæ[:(..Þ¼ysdÿ.£Å†œ½{÷š „.BXÞÚσšpíóÏ?ŸHÎYÙèÆ6¡óldú¬6cü¡OçDìÈÅu>£Å†œñãÇçŒA çð Â;~á`¼õ9„^5MÎq}6>ûì3fîܹA‰\¼ãM}N²æ3ZlÈÙ¿?žŠÛt#–‚¥ëç!kw·ó¡Ç*+i§ÏùôÓO_zé%3¯8Ù[Ô4åÖN_sªès’5ŸÑâŒsÈU Ń “v[¯8[Pßm$lPö±=ñK–,ÉÉÉqžÌ[›½`/``‰õmÿœ7?X¾\SŸƒ9VÀŒÏ) ÀôÔ§‘*úœdÍg´8‘Cé8l~1½H)Èœ‚­ 7ãq¿n^Q06¹iês:;;Gñ: .D ¢~~°<âgL.Ê)h¸aq{í}&`ₜT‹aXŸqn MYÃ<…“&ŠyúßRUImó¡ZÊò'¿¹¤çÙšöro>ÅŸs+´ÂŠy°ÎQoŸ]í3ÄýW5Ì„ðyÀÊ8ÈHáö›nL]ü‘>'Yó-Âzy)2̨#z‹t¶ÙŒC ;À ƒqyIÏŽò&bgÏAë­ÅêyÕà–¼Y9­s6:I&Žœ>'Yó-BätttàBÇ€6`ìèBKm;8X3±ár6&xÎ-ìœSPæÏŸ/L'D³®t¸ÏRD5¾ÂÝKºÂ&ÆÈas>… ЫÄp~·Å*++QÖÔIC[Ï[ç¬(,//Çúfã†36æÁ¾)ÍD>ëÖ­kï³3gδKÌùQôRû©¦r£f9 íd‰Ie5ýG”Œ‡;æz˜®®.9‡Ý€fAµ!dÌ¿§aÞëÏ÷0&¬´aÆ:..î^4Ö‡ AùÑ£GÕ8q~W¢¢š:FNj 'ú àñãLJfæ‹Q Á nâwß}7¢s` HÌlS‹<ô ºoHRÆñ‹<·ïWOúCçËþq^»<—ôðÌÖü¡^ü_êêêt¨FÆ9úûç„D5uÇôÙ&€«cŒœ”@ŽŽQ²¸ó©gÛ­íÈ#­û6ïØÕ´qSƒÿvÿ’[ªg̬()-;Λ—'D—ÏçÓAŽÕöì1*3ÎAy»§€‚ê»î+k¨ùÞ!„œÿrúÒ2·ê‹üøÇŒsàÀMüD 3húQ sNò‘±^d’Ÿ›ÛÓqÁe¼zžºÏ~£ãÉg Œí;P3»ŠëýX ‡,??ßRµ'£䣩˜ƒLôãáEÈmbƒŒpœãDåéÂáE¸;Ž)¨Æ´põ`a%Ј^9ÉAN¬z·à‰RœØŽ;.€”̱â~¬„CøùÒ—¾DUQG?…nl[L4afñâÅx­ãë]ØI~Úe ±âjÍõ øô:tHÆoذ×¶Ì\ߌ9'…8'¬˜jxPÖ +Mh;ÐYÌ ÷#ƒ„dœàÔ¡aÇHÄù]SÏ·¤>hÚw°yõR^ŸnŸ1Ûh©FjñĉŠÜšBTîl(Y¬ÄI˜Z#' ½5êÕGß*“&9sæø×p-¾!‚zŽ&f¬o©xŠ&4´¢écæÍ€î–”UfÌ·÷ÜÛb¶T;ãíÐ dþây1m9é‡R#ƒ=´‹9ýLe\ÛÙ©çÃ`l!ç† þQ4A›õÐËné5ä²qÉÙou1s)<8?a°¥šºÚ¬=¶ÒMըҸ†‘wäÄJ?CËV b±×s4 „èÈ\ŒF_ŸCxÐl>Ò DáÈÒkæ1*§˜y禦Ÿ&—zöµ´ŽìjsrZ9ãQºaä$“s¢l)@f Ï„*m|$vÛZîÙm[OCGŸ£ƒ"×ù¨¢¢TŠòO8c²Jx s ‹ŠmP‘AÈÌ455YK7X¹²¿tÓ¨†‘“¢Þš+®Hb M )8çÕó¨É¥ÕúEœC'/]ºÔÐЀv›cÇŽ$²ù¤V0º§Ë›„úR¶=õB§0tì„2ˆˆŒxÆï§Åøƒ¥›…÷ƶâÉúœôŽsìÒáC­ÒaÕsœUQ›¡£Ç¦BÓ'"¬Ì„<…l! 5™êêê@óXZ9¿»¸û'S[Þ›ÑJš6œ_V¿R졉(È<03Ó§OW”nØ[ȉLŸl”Öé’v|Ðí¦h”VësÔANYYYõ¬Y]/ŸkâdkKsSãfÿÒ¥8S4nœ Qð¬Ù—””deeáíÛy¥êÅ€tY8¯w¤ÐC _RÁé­½µñ匡º¥›Ñ#'îȉIÓ4þŽGÄ‚p¹2¤§»Ìl›>ÒÖýÂÒç8¬¯`@¥ç¯_3ÆÅ ¶ƒ®o~Ã@TóA¢J=žkþŒ?z ÑÇžcFI88xû+m¿W„ïùíÌ«a=™s‰·vß}÷É­„|Ž c†¨M:AŒ60vCñõ:ÒŠŽO UËÆÍý˜1ÇÅ×ìg,ˆú· >ïÏGò'Íšd£ƒ÷¶4™ßóIœ 8ŒœY<–ñG~ Ï+*3´nÈ@e(رЮ·N[»v­Î÷»¢Åz’ÔpÒ육 ÂãwŸ8ù¯}Oüÿæ{Mä„€ä’{ž þxH¾äO9Wg¬Ž‡WÆÈIoΉ C7Dë€þ&j²Z§ð<5PÃ`Æ"ÇùÎç¾¾ÆãAgçoÇŒý÷eþW/¹8f6,™ç×oØŽÅHß™´è§ Ì 0r’€œxï¡å|*yLÚÏî—Ï)3!}²téÏ ^òx¾zë*êìt-àÈFfffõ¨²¸fŸ9)Ê9)…%EbÀ êOðŒÐmë4íúK^ùiˆRÄ¢H Ðo‰±¥GÛ¼í fFÎ@öÖ"3ª1Ï@þ‰\™.Õ\¼Ð8øYãf3¦½|ª2“Ö«Î ’a%œ(õ6¬ÏI!äèèsÎ;'\í6J=OdóÃÒç QŽD³,Ðÿ6ôä•ç¾þË|’Ý›‘O4¡í UÑ. KUÏ®2аm5Ûã›1ç¤çàÁEìž•åL…¡p‰D™¹Ú-h´Ú­ c±òëÂÒçäååõsÜœ4Û„UÅÅ5hy¦ žÐ}ö[].ÉèK!­7¸Êáĺ3õ9*‹ßþ<:+õqÞw¦yGÛ½w·n[Ór§¿iÕâ†%3}•åÕ*®/(ãÍ•UrÖ¬YÛûKŸ,æ(2ir.B Í8¬¾¾žþ;h¥bÆùvÌØBwÂá8'ÞȉÓþ<:ÈŸ÷<¥3íz|O{KcÍw–ΙŒ§'¶÷ÇbNhyÔÐÖ×?ÖgØÖ·´­È?›Ù6‰Ÿ¶qK“€p9 ¶ømq¥£Ï3V EÈ“"ØNÖøŽ92¶÷¯¯Ïs*B1ÇÐ~–”TUUmÞ¼ÙÄÏwÜ1|¸±î¡åz™>çÉç;ˆ ’K8ŒœÏã·KœNÔQSS—LÈ0'Äêðè$Äöþõõ9TÌA*ª‘¸mm=bs;A8X½mß¾}>ø µT#spä+mΜÉB íZb£FŽÊ[SìW¬¿‰¼9_Ç[C ¼j²Nœ¸B EJlï__Ÿ,æHh꜖/J»âQOlîÙU×ö… £ò‹B×]wƒýßq€·K–ù)s@BN—pXŸ“ähns-[…Uhš Þ‚:ÂÂŒ9@V‹-ŠíýëësÄŽbèê[ æíóšžØÔðcSÏC«;×Õ¶Ìšä3‰¾¨±An2o¼ÐùýZgäæ¡i 1biöÖÂæœp÷c‘Í×IC˜‚pÅ•^„$È!c{ÿúúA1Gpð:½ÂÐrî¿­=›ÐqrSˆ@J!t¦ýsæÐßffbãÄj§|-þôÂÈqÉJ«Ÿ9ç4õ|ºŠ±ÕLÃ|€sàÚÝ»wÇöþõõ9!ÊáHФ#¼Þœa^+TLæé‡Pà¸õÎnÑË#®7ÛÉÌNÂaä|–“£iúõ#Ô´*2o ×b=¾ØÞ¿¾>Çë'MjXy;‚DüH—éës† ¯LH8Âñ· ›ÿ4Ì ØüÞ3äÛ¹ŒœTDN K:®%|<ŽÆBé­Û4“i!µîÇq-–ä‹íýëës6nÜ8Î!™F}³¢¬ÔwãQVDhç»›±Žà³3ï:¹©G<ïÎhøµ·øØr43KWÁÆúœÄgÔû±hž×\ð•M ¨ØAõ@'4È”#c{ÿaésÌ s°.!v1ÀêjÈ,c(Z Wˆ¨Óóæ}SáZ,iÛûKŸc¾¥íi_Ù|ê¸ÐÐðaàéÿM~Ñùº61áH°´}ܬW22áªýxÞ6ŽsR·ž£_útÍ­ÉŒÖÛGÄ¢Þôö#:µ´B_ ï?,}ŽUßÖpó ÚÈM8Ÿƒe !¢~cúº &ldÃL¯õ ª¥ØS:~zÖçDÛñ©è,~$›ïª‡¡Fi¥o&%tUãÚ>ø ¶÷îþ9´r´AeÏé1vß~‹±™{m­s>!ýâ|´›«†adá+–'Ë7cÎ #+eÌàÊ9Ø~Іý’(ª@¶Fé˜ÜXúZóÖ7{ Á¦çô!¼¶4¬ mwmó 9uôóÑV ¡lª¡cc}ÎàÐçX$O†YÌy’¥ÃºŸØêshKÐêÉ7˜˜1GkãjÚçݺ—(I Œ pj[¤™4¹ç†«ŒÕB{²sœ3xô9ŠFi×1Ã7ÛÚ(`}I *Š -€ O[Ó]˜€‚¹L»©`C[€-rÍœèÃ&©FN2õ9c'"ÖGŠõ™¾T–>Çl”N¼>¹f´ÞÙ}ì~lõœ ·ØêÍŽ™˜OœƒÄ4õG»£Åqé¤KÙ9©¢ÏÙ¶m›P# ÝœE“‹A,ðÊÒ C)`l{Û—3` d…­—¢dÅô9à:‰Î#MNª §uÞ €áŽrpð…éëu¢'„ åö”[“Õ0rRKŸƒ…8hΓ'OÚV»…tÙj·F"¸¡!¬û‰^Ÿƒ¸…ö0l¿KÏp"ôÜÀKpê ¥Í#¥±«/íÒzú©Vz€õ9ƒJŸîj·´¢4ÚÕ¨×3¬û‰^ŸC»¯!†‘òŒ N}‰B»]Y°I+I‚éæœÈõ9´„\ØaŽÓ† ð4Ÿ:u 1T Œíþ9ÖãÈôBQêsP¥1âû-«Cè%x,÷ÙúæL8>è‹ó"1Ýxsk0U tÛ踺¬N•`}Nzésð$yGž]ïŸTYUX^1<ßkó¦àhÁÝšiX˜>œ±çŸ^g©4W8E¦ŠFŸCý5ÍëWXprHJ8§lÌ|­›7_2jÔ(Z¦ƒÕP°íóŸ‘éshä/Hµô#'r}’ÂSùx³Ç:vëÜòlûª#­Kv4T˜ L§Å°-UGŸCý5M+oÑpÒ¸2uè`Éhò¤.**²¼2+¡?]¡%ÏÊë0rˆ>~°Ñr¹6ÖcçÛ}»MPeÖé‹xIÎ8%…œCý5xâå yÐA5*P-™3-7{ØÃ?L]Xì©ü4lD„\ÂO&ûƒËO{<Û&/Kb[4#'–ú#_´£ÉxlçÁBH EÌ9±Õ)ô9¯¼òJvvöÜŠ"θž§ö¤ Qqq1Aè½>=¶F<4¡Š9g èsÀ¯bƒ„'Öóô®E:â=<â×kgóÖ°i;Ö4¤ +l…N9±„ž·Ì§ÆÔCm€!Ú1ÓésÞŒ(1· #+Çä¿LÊúœôÒç †ß.¼/ž±M@,ds"X7=2½PÄú4+„Æ92'MJ8ïØúÍ{7âK€C‡½ q‚­Øi]5²’Š5 {WµžÙÛý­–ž {»ÿ®fÝA,™›“£Ö0ç¤>£®w®30½2þ±‚çÎÇÛp-òlÑ{kaé…¢Ñç,\¸04Ú1ðЫÊÁsåHÓ/gOùýuÞ¿Ïȸ-'gîܹ´~4YÞpï¼ ß†%MÇÛëx¥¯½80¦!,ÔÈ­±>' ô9$Js¢ÂöVø|<™(MSÿ¿Ÿ†ÂWD`Ö'űý‡¤I‚S‡®6¬0åÓ§ƒÄ2IJ/@,xØÐÒc;‰ù999ÁÕ S)IÀȉ$f@ÝQ¾:¼‘½E^¤5Ç$ CŽÍP• äœ:¤ŒvŒ·@Îo229W¦1„XBbÛ!ÀÌpór ß™Æúœ°ãW} šP¨ 34Ë6¥5‘é’…SÇZ”å<è–a3ún@5?Èξ”?úÛ;;­°!D†"°“±zNŠI 9ês4OšS­ï§YOâBMiì~’ˆš!HœÓul¿:½æ›e,o‹ùäéYñ @‹ódà-œ: Š9©e‘Õ© êJ2fÚ:@VæJê‘Õ+‰aêVí‚À¡5èOC#"2“ï4ß™6t ”?|#'u9',eÐí»¨Ur¬(B€„0)š’R8Ç!Z,B(Ød]6O›÷k2.oâ¤-’PÙjA¯4ësR0C Ö·Ë ·:Q!LCÛàd[:ýO£Se‚ääC†îÀ’-@å'‘N°N†8´¦Âgú`!jV¢¨¹gY•áìuúšYŸ“õÅŒõñ‹DYFF/Šª(•AëA‡UÜLnœcÛýàAõAÀ[£µoœ½Eh;²Hæ•)¸c[ýCNW{{k)Í9®úRæ˜eP'½(|6´XWµlžøý4"Ð A4>4êÐ~Œín–.uΧÎÑöt IFäÐ1$•&”õ9IÏJkê[¨ jÉ"æ±ÀÇ£2h4ûó$˜stàeÀp œu<ðéC m  8ܹ¶Q·VndÎIJ¨ EÂ2¨:Oà,ƒFÓ¦™:ÞšÕ–/_Ž=ädº=J ¬éZÀq0•Ái3W3rR9:É.<Þ1c5{mlcV½_¶6§~r/1ȉ Uaõ“ªÃ(éXŽSmi\FN$úœµk×’gæAq•MàdO iGhÈT¢(ƒF©«IMÎqÍ%¶TH5²®ó]¢Ï”¾?o;sNúqŽiW¯^¥Õgà¶¡¦‰~ÚEÙjÕÈÂ"€jvT·îo!P+›l['-!t‘19´ ®Q•ùf’Â(Úv~Ðêü)§àªÍgc}NJõ­E¦oAܤÙÙ³g Tpê„ Úºuk”ûóÄ9±uÒ¬œƒåÚðßß¾¼Ù%%íàŸ+Ë[̆kÝ­™s’Uω~ÿ¨PB:Û¬äDóýéè­™;Zë¡¡8yEÜ=ÐKdzúø¯r¯#äü¢d1ësRÎ[‹íþ9ñ›Ÿ0ä¨÷ÿqåë[S!g­‡*ô9ÈD£[çæÙ~Ì7:wšê—²òþ!¬õ YŸ“”¬tügŠr~ŠpNX~ɳ©Jbi›Wvfoª=H[#ÿfóo‹Ç®ûâò»W¬löxþûºIpØÞö°>'éqNLöωßü4Í­Ñ>@ÂÞ;ZͧA,³‚IJ,}vöü™³[›öv?õBÏ™—{Ú_y{GÓµTŠv9ñÚ?'~óÓ9ê«FMœ3}b! deeA/MÇEcÆ6Ô­h;ð  :^þiÓ^S^úËXЃõ9)‰tÑç(ü4Ù|s1eË–!cÆŒÁºjXÌS=mFÓº»:Oœâ$@2Îñãâëíñü:¿ðj ô0ç¤"«¤¾>'Ü(Ⱥ–qCU43#ÃW]ôÇdh = h-õxNܰˆõ9)š!ˆÉþ9ñ›Ÿäļªc[ÆvÝê'‡o&ƒPŤ’à:8¬ÏIÍzNôûçÄo~úfL#¥FóæmR¨Ç™—áÔáÂßAöÖRŽs¢Ù&1óã÷Óˆl?ùV¡W욈ðÆÅCs¸ppíì;²>'éYéè÷ŸIÌüsNL<7çnVÔ%fL^ªš:]kù5æœdUBS¶$šîÞ¡ˆ¶†G†@ÇI³¾miÜž âjFN:å£ÓZŸc£¼E›ÿ¦›]rüÃÖPâc}NÊeb¾/Mlϧ/çØÀƒ66onžÀ7ë+R*8lŒœôèUú礤Øi?úUex#A‡má}¬Ïaà&Ä-Ö×­Ð r,pØÐ§sëØ)h&øi’Vö`ä°%96«©©AqS˜^%íXµæõ@Û_²r~HR³>‡m° üC›#› ‚¬ò²4g`ñåÞ?ðàgC†Pèï¼E¬Ïa°ÈÆHÔ=¸Å5mÛæ.0·àý¿ÌlƒvXŸÃ6x¼567H tæèWä‚9¥ÌJàùTc;DŽsØrh+87’ ~e¨!R(*8ж£³£åW‚Z·±Ó9lƒ9páhC‘f„¹¾mñ’aYY†˜Ç7³½çqoµÞý/ÕåèÝ>š9‡mqÌX8wÑÍNªiݽTKM•ucËÂÌ™ž&~Ö5+§^,ñý¤rësØ2rlÙll&È×v¯» ‘A[ôÐF#ÓªËOt>`¢Å6.ŒÈýÌ3äÏC‡\<—õ9lƒ…sh;ĺ…7QèZÿ9r„`S×°8À3bØüU矎ÌP˜ÞÊRì­±¥>rdÍ;h&(--¥MD°#/RÕæ>ØHÜß¶CF5¦Ûöqu9!烑YŸÃ6(8‡àtåÊk‘½€ÍMþTìÝmÛ¯úkà³-šÝÍœÃ6H¼5ç®ñ¡É€ÇÛõÆÑö=¸Ð7n:#‡mÀ"Gè¹aƒQY2ÀšLS ʳµÎÙÈú¶ÁÂ9ˆv J§Mt%™3Ê·ž7+'Þ>#‡-…¼µýû÷[ý´vwùlåÞñ¬Ïa8ÈqÕÆQnÀôÖÎ(2:ÚõØ| Vfëô53ç° Š uOO­*kïÕM :mø¸m²µ>XŸÃ–®È‘í·Cé5ÄújßÌ5:ÞÑ’™™L°>‡-M‘Ö”dCÄíØc”ƒŒ=[‡7Öu.âÎú¶ä­™†¾4¸fÒ„ž 7©ÂhÛÁzˆX0¤¶¶6°ÐÔbŽsØ>rH} l#PCˆJ:XÌ ‹!š îÔÕÕá¤?v[V1rØ’‰õþ<$zkj½[óäSÝ¢˜ƒK@2´<•u…7Úk±:FêQF[JpŽ, Bh®7pj0Ì4vSÜ»·Ûa„"|¤›­f}[ "G?[€Ç=˜¤VÆ6‹üó0­²²û‹Øµ-,JëYÛ³Õ¬Ïa0qŽ­Ñ‹ÐUC݉J8yFlô‹=HÂÈV3ç°%9ïÏѨ0IMÉÀ€’ÖýydFŸž?¾¼ÜˆˆZ\·e}[jrަçY5Íf>í9pá ¹h]-N±âŠ^‘HÈš];nj{Š0rØRÝ[³&©’ÔÍkHÃCRfgLÛ²e ò׆ª§pFXøaä°%9l‹@IêisËIwM¢k<„h‘e°ÎËË£œu[ÍvF[ªX¬öš2e žïG}Ô<ÃM~ q€Oˆï¯UêŠF[âýþB×®]{ÿý÷­óc»û<­Bøÿœž·‘ÖÈQo$¬³Ó½m~<ö¦T8Å?Uÿ‘ÖÓ„‡&ùX?ëè9 ÊÏäE6ü0rØ’Ã9²ðFóÈ>ÒçW:²M0ó×&~жÓÚ·E#‡-AȉӞªqÚLÛ¶·)lÏž=„ŸQÃò‘Âfä°%:C ` ê8'æûiÛò×ûöíÖÚ„ø—Ê–øÜšO$£˜?ä( DF*ÿRÙœBHíw©õ?êÔEUF[⫨çǰ’c›¯îâaä°%!·¦Ÿtv+œ¨ãgÛ(#‡-iÞšf1T=?¡1rØRÂ[Ó)àM¨ç Wÿ£@޳I”^9l‰0EêYÈ$úóãáØ*¡Â$#‡-ÑÞZlK¢‰÷Ö˜sØ’çΤsª±"G±#‡-iqNúœ¤d„+0rØ’–[‹¸W-®úç°·Æ–L䤋>G˜[{î¹ç¶nÝŠE§9lIË­¥…>ÇÆ3%%%´rˆ±Ä;ÿRÙ’Â9i¤Ï!ð>|˜Yû•Ö×7èá_*[b“îúœ²²²ñGÞîÁ8ø{kl Ϥ£>Ç$Àæp<Œ¶$äÖÒNŸ)›I8F[“^úè¨MÂaÎaKrÒTŸcÎá>Îaä°%'·–FúÚ¬jã©6+á°·Æ–Lo--ô9 œ’êê#¶¡ñÿ~· náíö:IEND®B`‚Chipmunk-6.1.5/doc/images/hash_too_big.png000644 000765 000000 00000025004 12151675775 021412 0ustar00slembckewheel000000 000000 ‰PNG  IHDR7¯ÿ pHYs  šœ2iCCPPhotoshop ICC profilexÚ­’±kqÇ?wQ[¤ÄPÒNoê%´ƒ "I“Vjk iJ›€ÃõîšœÞ]~Þ]b#‚‹stEŠ(¸)E´£"H‹ÿ€nBA[Ïá¼Ë ÕÅ?ø¼Çã½ïûòƒÄ¶*„%¶ã»å³cÊBµ¦ôlÒ‡L/)Rªæ‰|©4Í®ñí#À‡cªÖÍ/wö¯ž¾ø¨~þùrþöËþIw¡Z)¤ë!ç€ôbÈ }Õ>H ­5T¤ë@Æ­” ­ÉzÈ/€äbÈo€d[«û mYG7{“ºái çS÷4ä' í±í¦‰gÀQM¸>$6€Ã ÕšJn‚3G@¾Õ­Õ\xú¶»µá"¤OÀÚýnmk ßzK£#H}.ìý[Cг;nü¸;!± ëW´–Ûþí—$½ƒåáÍaïýˆvãвð`æ©p7ÃóÐÿ J@%‡<:½ÐCLǰU¥hzÂR;ü÷°­V´«èsg.ÏÂ/U"öÚ³ã/™“ëjq*âkÂLÜãN”#¾¤ž+El8s³ñ|«4ÝÝ5÷Þølwfe>b·Už‹ørs*î×b¬Í±f♦?ë§€‰ƒŠB…J'ü›ûR°2$ÿàÕã¯xåË>@¡):®YoøJ^ËÈ(“Žv<£Œd³§øØÆ´áðŽt cHRMmus ö¯…™nšç»1}½v x'LIDATxÚí} pTç•fKÝz«…è-BjKBÔI¸A„ŒI€m@ µM°É¸ÀFUÆ0‚dâxi;“e§ÖöìJ®¼3q«ŠÚ¤¶g\;lÅ3CÆyTf75ž8ŽãJªvgËûÝ>ÝW·ï«o‹~©ûüõW×½·¿¾õýtÎÎùÎoúr¡cddä¨dˆ§|¯ßËõk×®¹$Cvª‰€7-˜¥G Ù×Àxƾõ÷xÂßK•õ¿ Æ3> ÞÈs¬<ˆo|èm©ò‹1øU1žñR[ÊF5ĶTk™¡µö`<ãµð¼躔×`Œ_>ÑÖœFð÷ÊR¿ŽFŒg¼ì”M¨[ªúwQç%ã¯óÏðz¼ü82þÞñÆ_Õ·âo UUƒì×TdñŒ—ÚÒÄ¡ŸA|b¼ÆñŒg|@|‚;·ªøy¼ÙŒg¼>ž¢òx$ÐÏø€™é£l䱎W|hl©~i˜Îš„ñŒ?ªV!hðùV-µ‹?|ˆó¥œ¾gü=âÙÑ K¾”s Œ!ž¥a\—²N’¯‡ä:ëKY_ÊøXÇsí.ëKëxÖ—²¾”ñ±ŽçU(ëKëx^޲¾”ñ±Žç .ëKÏúRÖ—r2ñ¬/e})ãã?<<Ü×××ÖÖVYYYRR244t”õ¥¬/e|tñD˦¦¦²²²´´4“o”ææZÌæÚÚZ©-e})ëK üþýû»»»Ui騭qvwMØï>7á>wºyÅò¥K—êGX_ÊúRƇ¯EËêÒ’^ûšñ¾í®‘Ãà¤rµÝëKY_ÊøðâÁO‘–6=ZN(Ž'&wãS ¹’¥¬/e})ãˆGÔ§¹¹ùÈ‘#âE˜P0mú¸SÁFÙÁ„‚«§ñ)|vãÆGY_ÊúRÆß;\½Y0S¼N¶Ôc{зÝÐÃÏÌ̼téR ê?ív;~¼±îwû0J”De})ãÃŽ÷˜Ófƒ¡]UÓº¦ÆIáÌø3RCz·»ë¹¹ÌÍýéêZ¬Z»êËóóÐîHŽ›Íf¬srr ìžÑÑѱaÆnÏðƒžŸöÂ… ‘ÔEÇO6¹o ¥W"*~*Ö—2>rx¯9õ¯ª6C“bÉ’&ïÅñœœ/M&ÌM&»™é¥õKÛ—:š ¶<;f…Õ†‰ë˜™+¦Im¤›3ñŠÜ,|òäÉp;ºø{!,DGV“•ÎÞžåJ¢²¾”ñáÅk­N –"!†”¿DX¼­,\ZU\$òêmE1ÿÞœ¶¿tÇá†É—3W7»ÅyEr¬3_rÌbŽ·^ª«éæp’aë¤áœrö|ž¢·$½åGÔ­[·²¾”¯Gè:%<•"5ë:àã§mÅѾ«ÔôUç5Ÿ,ìüpIã/óìS;n ¯/é­.<È”ˆþð=Vÿ~`pO¥Ÿ ½¥NT­z Ö—2>ôxDPŠd¨üh›—Ÿ+ʺ¥´gàÄöW;Ç[]~|ë ’ŸÁàÇÖ¹6U ÂU¦Ÿüá³gÏ.Ø E‡ö¬šçä­J§—¸ À0¼¬/e|$ðdNI3ÈVVìɹ®¤ŽèÙöiã–ðJ–Ó?ÀÞÚq™?<::”žKM|FÒÏË•9½ïJx{ËKT,bY_ÊøHàuÌéwkœwò›ß«èíY9 ò³³bðêæ¹«Á¹²‘ÀÆU'‰\­0Œ*rŠÞR±ŸsJ£ún–¯ø º+²¾”ñaÇ“9m÷—˜Â¿½Ü<ùEŠ•â@/{ø¹¾´Wf<µ¬Ü• ן¡ÅŸXûJm¾Ð›{ùòåäk1™Àe‘û·t* Ý’ˆ¨°Þ¬/e|ØñÙÙÙJsz¾¤óK_´ö/ÓK¤ËÎÐÆ„„‡i%»*Fzd$‘PT×Ñ}W±F•V¥8ëK^<ÅN°:¥…(¤§sŠƒÞ2™>K2ÿ2£â†ÉØ¡_PøÎeC´^•%op*ø«k ñ3ð©*QY_ÊøÐã&…9?ÓÓ hý‰’ƒcugÞjžzMÃË],^@¹µš\SJÛEQ «ÎL}rªá'Ï­¥†ý¬/e|ñÒ­_áØ[3v%HããxäŠè‡pb³))ÉÓÞå—Uukµ|]<…|ûûûY_ÊøpáÑx¡¦¦†’Ÿxš[kJ&ñßÄNǨ»²f§¸¾åP3¤;»¾’9úD]PéSÖ—2>h<¬( ß…˲¡pW#ÄQ%*‡°X,ÙY)×^qX—ÞÒ¶®·¼a^EY_ÊøPâ) ³rI=ìÌ¢^|;)ª”””„ש¯µ)+LIÜË]Ö—2>\øõë× æÙ º‘W‚t;c¨’-¯™«g'ìꮯvUIQÖ—2>ÄxR®a¶W˜!Ä£À07­¿ŠÇ¥5€òWCŠÒÂ#Ö—2>ôxê$ØVÚ›P^®Nª†,ê™gí?üó®Ûoõè;ºDQÕ©t ìé©§žb})ã‚§Ž>+JX*Ã?Õ<…ßÉe“éWEŸW/ùHlÔ X¬b¢ÈÊRÃJü°¾”¯w2."EZoýIÍ©}‘ŸRÁƒB_JEy°–¿zåÊ’’cìêxÀ²'Ö—2><õ椌hÜg\‚ÅO·º>IÍ#–þCY–R_Šä*QTµï!øFò¡rx{ï_ü—Ùw¾ïþÆ5—j!1ëK¯Ž§œ,‰¤þsqáoW~œ^üžÉô0õU¹åGQ$WQG Š*ƒ@(܇Íj¡pܸ9 ~bÎz^ÁX\§ÊDÖ—2^ˆ¢±¨ þUÇ ~Kd½­nõ¡–…J ¨²{ ç´ÁdŠ„_žò’ó½9"*&HlÙëK?<yböØîɇîsØÄ¦~à0þúÂPëÿ<øÓPØÍó^f¿§&©¬¼üc¯*cujY_F<Ñc¼«Óý•'1oxÇöŠr‘®dµî¿c‡°KÒ¾©°Tœ +^qìM·¦Ó­EŠeß¾}ª?I^”ŒØ$†OÍPr4Ͻ÷4s¤ê\}O¥fõ¥a¿N~æôÁG‰¥Â<æÄëìÈãc]ŽªU¢ y'¬¢ì>’•’SÆUÌC®GïZ»¤t‰¸ jYC] 2ÁŠG úˆÉ4—œü‰Ýþ£ó“³ºÎ­ÖõSgðeaóUÖ—FÎÀѧ¨Ú<ÿà6ÐÕš–&sbßlkû¶Ùüœ­ØŸœrºŠ¤uNÙìÜ$._ÉPãgÀn¿èFÏ”pã_uÌbs’¡‚¨ú®¯ò"’1Už ¸EçÏŸg}i„ð`šPS²¡ƒì§hHý¼§ÂëÔ®½«ëˆ®¨FùmR¾ï_çe^ŸÐ2¤²S:ÀòuûØ¶ŠÆr³%™:0ÈŠY/<öãøYF ±ô7«V½+)Ô·Ÿˆî¶{âFø›=*ëK#ЧZ^W°žéy¼ØÅ—j¥üDž:5¼…x²E,*ú<`iЇ}·óòò@cÖ—†P-â@Ò3¤ja$LD}Í)fÕX®Ö©ô8ד˜Áõ\oEõim}ýíÿpíŒß¾æC¸’‚Š $XJ„D{jm#K3JWäØÄöe¬/ ¿_lÕii€®Â.}5ÅÄ=­Ô‹2bD×Go>N{²^4Zø³íBÖ,ÿ»¼Á…ŸdfâíWð·,•² £¤.ßÞ³rèpýø³ë¦^éš}}›ûµmîóí‚M¥Y_<©OY °Ueì1çäö|¼çäV%3º¾˜ÛÇ·Q= »©QÄ#´þ²/Jÿ¥'µF²6¿Y$ä%Ç4)Î׺ÝÒSÐ9pàëKÂG9àîêrµm)Üݤä$-oVÉXYà·´¶D§°ž«"†?âKzÿ>9õ?×>#e ’“òw=¯Ò²^Ö—†Š?0-µI †ç/ËS­X8Ÿ™yŠü(^F}®+é>’rÃdº²´UŸÒéÄÒTÚaõ¥!Ó» ¯ÕhöÅs¹ÿ!||ó“u¨¨4³ôz~öØóÃ핾­GYÿ]õ¥!Ç£Ì]ÅÝUa¬Ü¢¢Þè99_z3ozª¥ñ[}ï¾5¾MŒU|PÔÉg,LDÚ‹‹‹³R¬Z´ÔŸÇÖLR2†õ¥¡ÄC2&”.f\¼»¡C¤Ùõ¢\S1âîÒ|cò¡ß§§xYj¬¹›ÄpãiÏÎÎÆ#Aù• H˜çÛü’1¬/ Íõ¡¡¡”¡MQsy¸ŠB?M¢*®¸kçÇ™àØ¯RS‡sr(„r\ÈGQñ§¯ƒ¡y¹®û‚ýUV%ôL˜XÀc³IúÏ·]Ó·¢¯©R2Fʰ¾4døÝ»wciJ[<` 3ÄkšÊºffNæä\ñto@Ÿ¨jhO4 ´e@s†} ›”«)ž>f¨PãŒHŒà¡¤¯¾ëëÆ¼\™…·,&cX_z<¼_ÐU,þ‚ݼ•½j…`2``¦ì¶Ð©¢ŽŒº¢Ð@ë#4@‚ŽTJQª°§’#ÖÆž¾2ÄtbE:ËTDžPôËúÒ°ãaÑZE¤+älCö5ó…ø¾ ã]­ž bUhi¾ÆèÌ€J#tiKáã *HYÿSxdÅ, r**δ¨>êÎáƒxrX_9<(ubQ½°½®V($ô˜V[|ïO†Zô«‹mE©™©É냓ª±^4ÜxêÖKɘ€þík Ó*Mư¾4Òx™Ûº|^Ѱ7Øû‹†š¢V³‰5<¶Ÿ¤¯ØHPWÉa1ÃúÒhâɉMõ´ T¨ ⯵MÓ)ºxb©4óšáô))chƒSÖ—FO{í…½µË½³fÙü±îÅÎ*¯ -Ýïgì̳–C3Su0 3•)C]‘X_e<^ Õ¿=­nçN¿9Šùü¢Óïâô£[…T9s¼õ:ë?c ÿZÛôߥ! þ…9ýýûœF˜)»ˆd 5m`}i”ñdK–ŽîTá¤ÈL廣^–*»×³Û øw&¿0gPMØÏ½‘^C™R‘®Ë¬U¤Œa}i”ñó,%ûéÔ0¡Rë;¾©ÁR®.ˆ<êÀ~žÛŠ~–”,µ¥Z‘$,D1Úkm)v 2 CŠo¶¡¡õ¥ÑÇû±T•Ú6V´¥¼ŒÍ9ÝêzÕœõƒ$ó?–÷ÞZ7%%äSM“{ïs:Ê{—çT!ÅíLaBQx„Eé¥K—X_}¼ÄãÕ5¡ŠE)޲”õŸQÇÿmª· úiù¢…”‹OÒét¾øâ‹¼i,âÕm騂–£*ï*YÊ+Ƙ¿ê˜ù‰%›X õo¥w2P‰4t-C3A‰tpö£££PàՠØS›õ¥QÆŸyðAˆ¿¿ÛZпew1ÎïdT|j2ý.ÙüÓêö©þ&·o~Ò¹áàP36ÚâXµ¾¹¢¡4§Èš–eÒ{÷îe}ihð¨ܯ=nÁë°ÿ8tèÐ ;wþ}a!þÐ~š‘öQg³ºg«7¢c‘¥lâb‚“Aì Wls{k~>õ¦ß©äâìß™>ðªkèåÉíÏ‚ÏK³ómhçËúÒ{¿~äÈ‘¢¢"Sð㈤%ä¿Ô,3=’øÀÄRY^&LLá«s›“““a6åÌOu¯ÃÆÂf}ið´âζ&>®3Çö‰s sÏÞk7ÿ[f–ÐÒœ|·½>ˆÐ‘gÞÞØtÙdÚoÎàŒHÌâ±…,ž ø·*ÆSÍ–Ê&múÄúÒà‰¥àžûÒ×ýæÅ«ò+—äW~´ï1´„|½$_=V¤½L½ÓÓúy–4ÿy’yÖ'ˆaýg¬á‰¥ð]Õí§œ™r»JE‚¬/ ^ÉÒ9995çìäŸà³ýõ+”1ˆWæœ;a{ç›’nw´8ô™hDÒR¼5žô¨饞þ¯ÏaBŸzsÎs€5*õUY8KM<ü‡Š-Õ±«¾S?–Žjû·t*|øPûçÙ‚-ýer ŠÑâ@Ÿ‰®ü¢œ=nô¨ÄRDwå„T]Žú_¼yàUï³Å, KU|]=[ºsõ ã ‘´ßßÒÉÅHFiÄ`h[Aø‡qCBlÿ¯kƒ—Çx—°ã ³4¶4]gd¯Ü„ê9Àã5..åÇ6ôÙ¶›qòHNC„ïûÝψèª]f–FÖã5¾.5¶:õ±´:¯y±§þim47ˆ³’Ä >õ~»tåûC/L–ÊN±še–†‰¥:ÆSå­¿>ý¶¸©¬ÂŸÛŸ¦§"´0}©ÈÒÅèÒÆGþ1긩|¸]í$[úiEãû–Þ*TÍõE–•Y)–jG’>Ø'fSþÔœlMKÁÌNµÐAÀ™•*ô%[]жH³ÿO®úw¡:'Ž«°1És–4¯»«ÈÕ±¥½u[˜¥Ñ_—Þ9øøÿÉÈnÔH2›…ßÓKãš Êu„‹éo| gè±Q›´¨Åg–†¥R³i$sñêO;ØâåGK‚ù·,Ö¬Òí™%ú½bYŸ ŠŸ;5ı¾ô‚cÿÇåy†²/Š„ª½¢‘Y [ª .Åx ŽŒÒÂåC½­×^Ü⾉is>BׇUÆÎŠ¥ ø±QÆßµø/yXZ]Xت<Ø W1Kc"_j„¥VÛJ²cú*‘Sœ¸B€Nc"ÆÈ¤ýÈð÷âRôvD‡Ç–ŠFƒ RÙ„î”Yâ1¦cKµ½_TÛ_öHØ”#Ͼºnü 9ß±²<»z±˜ *lôKÇ«œíqÛq|¹?È)úh³Ó ¾Tz<ÿ(0K#˜/•Ïû"7WˆÔ›LûîSäh97Í\× çÒ8ÀÆ[Eý¦­ìµÊãO_úš§¯GåŸóŸ: â oÔÐÔ—2KÃ`K÷ì .Æ{ñêݾ~13]RØ8ùŒÒZгKÍ–¶º^¤]Y¸ƒ o b+äxÕ—Þ¨üeîäÝph±òDˆ±\ÈÄG;@à†z#‚϶wŠY‘ui })lég¥eøUþÌb¾<þ„ÌNjy¹2»Š’¸4e½¥² 0¾õ¥ðíÁÌ=ýANAeðOTš%•Yâqb÷àôés˜7'ðú<K'E˜3žWqþÕž½§L&ä¾7Í^ס¢üÊÜü)9½j·ô–Îïgÿû—RåŸ_Û8蜘Þ}ÑÝ20ž[n[ȳÅ,úHOþdzÜÝ7´ýÛ7´Ö¨÷ûœÞ˜Õ[R þ>Èñ·)iÖ2óKÁOéÜüŒkEk/³tQt[=kÎö‡D3c*$•™ú¸ïQFÿkŒ†N0s××Ü2®gZ™¥±3t#º7uB¾[ÛšQ`øÍ¢ÎLëS ‘ê¨x¢+yø}çg¤ÌÜ¥àª!ÓÊ,á‹ñ¾aluêý3×߯^‰ïãwI–Û1V*ªoäãu¤ Å›e ¥ U 3¬.Ücfi¬²ÞNÌ”_Ÿzîsk…ûï£b ·Þr}‰J`"ì_JiaŒŽNíÒf¦ê[Œ\·™¥±;PCo8Ì;ñÑé«ÿd[I,ýoe½1âJË­SöP pÊÈ-2hH•«V‡ó*³4vGËÔs]r¤ÒcàaN__Û0&¤:Æb!›¤¨IMžž Ý´Éϧ¸‘N*§|¥Ê,U§×`aÃçÞsĵ¥iû fiGzZ²ÒNz99«r}Îwüá…–Ÿd˜ñËý,%åÉ%V¢ÙãâŠ&T:kW8þg¸ô–ZÝãO/ª§È™9%uýð‹j hKQNˆ;¬í_uƽ繹= *Íãk™¥áBävVÛ¿U·¥=]'†òohÜYæâŠVT<þÊ€·ŽTì&½eÕ¨Vî'þô¢Ftj4Ò¬õ½£úU 2§T¾+’óŒgÒ1³4ŒkQ}ÏVõ léçUVêW¦l,˜žj•»¸’yNrŒ0 ÿÚ’ý7ž¼H8b*Ò2À„ ꊅôµö9­] ˆ÷€'p J_X™ã£èÃ"]™¥áAñS<Qÿ¶!oÂd²qq©ŸÞjuþ6)IHÜ¥,yG⎆êñEJË0e7À¤+é „ÂÝC×܇/¹ï»ß¯ z4Ôô’iÕ ùäÐ…Ž3rŠte–†qÈCGâFâñ?TõcOc«Ë>÷ÈÎkªKP-»úAu¯è9‡CtŠ2]ãÝãx"¬Mßuiµý°‡¢4;ö¨ìû#šVåÌÌ/I·¦HÝ]é1³4‚N¯ºzæ§MyD°Ÿ%%?Ý|0 '•o}oóä¿Ø(óvrÙ@hõ“Òn€‰ Õ¹H¿ Œ‰éa K1w>ã*Pk˜â3­3»üãFmûîSúºgØãÓ«ÊL]×÷_;¼Ý–ïfM L«33]¿µÓ5½vµf0z!tó(˜Ù_=š°«PY‚£ëऔŸÃçeÞ¯t@ž†´Í·w8§s‹ŸH2=§æëòº4RN¯4º;«ËXoà·ëΙÆ_×.O¶&§]‡Ý «ºeaØ{ÉæÓs `¼W/HÚ¦¢úƒ‡ý­¨c/¹Áa­ÇM^›œ .ý"%™Ò¤ÒÐî]™¥‘rzgõ\\U{k«ò¥ëWéP…« Ò¦¦dš´wO fo"!ßPלàkQÚäûïÒ‹ÞFÏ”Ü"‘²é8=­êýJ›ßÿåøZ™9e[m§W™DUdP{¿×'vºTxÈ(u··Ÿü«œÕ÷¢ŸT-Œ{½¨*þ­æ©ß¤-õÜ6uêÒ‹~ÇËž‡}ÍïÿÙ^øŠk‹ÔË¥c^—FÒéU¯­×©FÂëôºÃÊR{~Òµ¨‡ÜEy•&µjxã+4*[w-‘ó¢4ß\3õY’™XúAƒÃÏ^T±¨Òcx¿©~%eh~ÿjÿªo^Û"qqÙ–F7ÒÐãõ·¼,ÓBÜ~¢¢u…ª·RU™Ð*L´Œ æô:×K÷¤_ÝÚí#†œÛ‹zïRµh¾pW^ÏÀU Q³±IfH2HNq@’fŒä¡+Z7tqµ†Ø$il_7ÀD–w‹{bÌ´ô|ØÒ}{ÓÞe™9&NíQOfØpö啃“¿³¤Kß6â4Á´:›NÎ<Ä,]¬C #ÁÅ]SÝ»°›8ÛÖ 5ÕH‰Je€ˆëbwà/]Rt²q“{Ëcî-hö”Vá"Jˆ<:¥ÅLåÅ^ç×AÎß%›?JÏ>Ì×tŸ£œYºXÂHb÷ÝŒæ²"÷È ûèÐT_gq¶·ÂiyN­I{SàDЋJk­hô–U‹üôL®gif¡æÅ ú†T¼ˆBˆÌtëÛ{_|{Ä5ØäÇ,]¤Ãœœr/ŸÞ¿õΑÁΪet½µ¤'Á;_‹ÂnÁó·æ‹ÌTÌÇDïa[ýLi^‰PG}êÀÔõsnšgG\KsK™¥<´ÓB[ç)ê›'kÍÉÉ´(•šÓ„ª^ QÁüß²öÝJrJOû+jÈû• Á¥¶”Š»Û†ˆŸ.Q1íµf)•ᨬ ûé3¤óDÞm[šgò´/„~òn¡ã-Eëí8î`´rI½ßß²ºvmC:?¿ÞÒ#õ~e~oÿ‰?â+í×%ä”rõ@ß³”‡ß°¦¥‚ŠJC*º¾x=ßÒðc_zðƒœº¸×‹ÊbEËQÏìzL˨ÖäàSzK½_¸¾©ÙX޾t|ÚåÏRé„÷»¼ÔÆ,åá WvwøÙÏy‹:(rõý‡»Ÿ)n+„ušò¿)2¢´s„tT{—£R*jòSœûVÔSN|ÃÀø O_C‚´dUNG'µøé’<`ïe–ò0õÖVJÙ¨3ÿWmå­YŸ¤¥žò}¶? íB£.¥ÆEÊẇ¾—«ÅXx¿VKêY“é ³åß“’þû¯­Û­JKÕy°O½.åÿ†·t=@þIEND®B`‚Chipmunk-6.1.5/doc/images/hash_too_small.png000644 000765 000000 00000021103 12151675775 021755 0ustar00slembckewheel000000 000000 ‰PNG  IHDR¡Håð pHYs  šœ2iCCPPhotoshop ICC profilexÚ­’±kqÇ?wQ[¤ÄPÒNoê%´ƒ "I“Vjk iJ›€ÃõîšœÞ]~Þ]b#‚‹stEŠ(¸)E´£"H‹ÿ€nBA[Ïá¼Ë ÕÅ?ø¼Çã½ïûòƒÄ¶*„%¶ã»å³cÊBµ¦ôlÒ‡L/)Rªæ‰|©4Í®ñí#À‡cªÖÍ/wö¯ž¾ø¨~þùrþöËþIw¡Z)¤ë!ç€ôbÈ }Õ>H ­5T¤ë@Æ­” ­ÉzÈ/€äbÈo€d[«û mYG7{“ºái çS÷4ä' í±í¦‰gÀQM¸>$6€Ã ÕšJn‚3G@¾Õ­Õ\xú¶»µá"¤OÀÚýnmk ßzK£#H}.ìý[Cг;nü¸;!± ëW´–Ûþí—$½ƒåáÍaïýˆvãвð`æ©p7ÃóÐÿ J@%‡<:½ÐCLǰU¥hzÂR;ü÷°­V´«èsg.ÏÂ/U"öÚ³ã/™“ëjq*âkÂLÜãN”#¾¤ž+El8s³ñ|«4ÝÝ5÷Þølwfe>b·Už‹ørs*î×b¬Í±f♦?ë§€‰ƒŠB…J'ü›ûR°2$ÿàÕã¯xåË>@¡):®YoøJ^ËÈ(“Žv<£Œd³§øØÆ´áðŽt cHRMmus ö¯…™nšç»1}½v x‹IDATxÚí]mpTUšîùH !ˆEù?BB aãàG‰”‰Éð%* ‰A„GLÍ8Žgu„;ºJ(pHÕ’ÚŠúƒÄ_Z»NéTm•þ؂ڭҪý³Z5ö'ûÜ~»OŸ>÷Üs¿»ï½}NÝJunŸ¾Ý}û}Îûùœ7uCxŽïÓã»ï¾£^ˆ·×Ò[ø}½}_õHiaŠ5<Ë"¦ØáÇÃk5Ž¢ÈbõÖzÄXýfm 鑼1S`Yd/ÄÏŸÙùkøá‡ëׯòÉ'}ôÑÙô8•/¾øâž={ÚÛÛzè¡•+WÖ×××ÕÕUWW§R©ªª*<ÀyL»zõê?þ0ÂÓJ±0$"²z¹úF~ž-ÀûšM2Èý¹sçxà›o¾9e=¦Î¬˜1¯¶jñ’šå+n]ׂ£~CÛÒŽ®¥íx€§ØL h$¾úê+"`ÀÛª ›ë\Rý,íþ±‡¢õ›·¼æü]غaí+¼>øÈÛC86¾7¼åòèwŒã¯xŒ‰ñÂå{{ò[æñ€Á{)Ÿ·;Ôßµ†DàA†-–Žúûúù|ß/¾øâرc°gH@±®7ì醬C‚±ÒcEωû˜\âl}&ÁVœW-öùçí•wà½Ö¼rBc p&JßHý}ý»×j Z.ìr¶êÏZ´8#ú²Ek6æ¨×øŽ1•ÄÛÎOÅWŽõˆ×€­Ï‹~}éšSx˜œEÈ„å?&=ïh~*¾6½1ð>!Ê“&OæmýŒ,ŽÉÖì쿘‰ çKÜb»ùZèî€åCqžšÆmï_[)J¯…Eä|¾ëëk èÞ€ñC–Ï}‡;2ÙeÏRøß…p»¼¾Æ€¡Œk×®ÑòÀ<³|T²( ÝÐ|ÄFÇt>ßíõu­„ßQ° €ÃøŒ4ï'‚éyù‡à®<ØßáJXeÁMèŒ[ìl¾Ûëk „+|…ÿn«nZд+E~°üS67O.mMvÙ|ä†qAä¶Îw{}p…/"êH]¬ÔWèïï§åaœŽ1;{=?l¯žË"ê|¾«ëk ƒTÅùù¶ZÂs­„°üÃvÏ[þÇì2»[-üyT¿A±8Ÿïêú Ñþm!Ï_5Ì~ˆinùWJdǘ2¢/›àúÎ绺~*Œ#¨ê€b‰WÁ*ê4~„ÛþEz&{ü—üáùû¢¦˜´ü+”c2‰t3†ÞEp0‚º~*Êëb±ÜÍXDI¥Ÿ¤lV'|ûí·£.­­­mÛ¶m¨QCÐæwÞž˜˜ xû¾à¦L™2eúͳÉ[µôD]®ÜÒùx æ~ýx` À²X°Šºo0­ 1­ô´¶ô¬iêºkqKý‚¦ªÊÚéÓ*Ì4”ÊÊJ€dݺuIww7@bf™HªôTÄàÖ÷;™ €·kØÛÆõÃÂ@ >¢_-^ïëç>óÿRxþHÏ豃㙣/÷ç÷mz²}pÓ#‡[[º›îiHæÍ] *æÍ›‡ —â­Qþ=ƒø$ù対_1og¸Å!\_ëäè6°œC”Eéwvløéóx­š€K! „íÝÖëû™_ÓØDnqà×OEj1|5³«']ü®a¬Én®Æèèè•+WFÓ£µµfD ˜t‚yÂÚ•]jfU@äù.ëõ½ÍgD‚àùYÌH^¥P ºâL܉>n1ÀÆòåËa؈k|ßøñƒ– ˜FØ‘Áê]@KÏT2û¨×÷6MšH`(ŸÀù‘ ð}ùå— =`eþJOF$uU` *X´hœàœd[éÙSx!†ô-( œË×z­×÷6ŸˆFýiàüHµVqk üº¯¿þú÷Ê¡P%e Íœ9˹Äè³ÿ·¶f ¬óõÉϦ:~Ÿõúžçgó¢ï`\ºt‰Bá91„Ìÿ–”-d˜++»ÜJ?p$°éˆpq ¶æäÏ_½¾çùÅ¿>`þ@¤ô€t!§`aýâž¾_0Øæ>o”Ø`·âÛo¿Å]BÜÓ”=‰×Âæá¯<22bÔ6·U¯ïy>@˜ã×'†?`%÷Bº§îŽ%ï~0z~d|ïs†IŠlŽy~‰c€Oãu>6 ZøùóÜSHàµàþJraÁÕë{žŸ#$‰? VdƒÞÝÐégÇÞ^ãF í/Ì× M9qäÛ>]Ð7~àÃïÄÂÏraˆ!*/êø«×÷<Ÿˆ9~}2ø ïI{|áÕkZ>¼lˆ>ý¥cûS=­̶iξg†m¬ <Æk©Vi2ÔÃ¥“Á热×÷3o‰™_kþ€UÚ‹€×<Ú6$Dµ¢ t뜦‡óÓd° ðZ,ÿ¸`cc£˜ Žày>”ƉâüE6vìØ»¿þá¶œÐ_ÀÀ`€ŸœÏ¯± ƒuG °»·sçÎ\¡„%€5v”$¦í€V½x$$>€çùó›[ ~}Äù~9>5¶eËÃëÝÜõ¡IîÙö8!øÔ H¨±/Žèþ¬Šy‰ï³Q8Ö4u`a¸ðøžçç "Ë𣬤?wdÏÀ^ÂKà=ûÁ@Dö†äN®^½y.[È( ?>)Þ œày¾@$ˆ(À3¨kûSÝfA·DBú$Áà7Þ(q=@êB QvX! …wÞy'”@Ææày> ¨^#ºüoXµj¾âžVf€ áü]÷®`à͈2yÒá'FR(Ñ稆•vË–-Ë[hCãxžŸÇ¯?P°žm4©_éb¯8Ø|äÑpDÇKsç€çùŒ_. ¨žm¶¯EbŸZ0|iÀÖR+$’  z—&è¶³ÍÍ3[œWÖÂ=€u倰j(v>~ 4!œ8½}è›Å-WQ(aЇ†Äð<ÛVg*&Bå¬ÿfg§ˆxùÄ EhÂvùçÏskjgÍšõé§Ÿ–¬À²Bý.Cþu%P³` 㶘ÉÄXø¸®œw¡Tê¿§N=A™ày>¹Å9"AHü@ú‰;)Ø5êK`ëÖ­ >TFE¥†ÐïOÃ"·¸;ëøé8FØ+ëгÏ’ày¾Ø¨/ü˜­ß=Ïõ[-üVÉzðëSC3fV'Pšq!Ÿ}‚që*0Àó|s£¾„𠲌^–<•ÀL¥õЀÊì,áñ<Ï_Ã5êK ¹¹Yˆ“*ÒÆS—ÇS¢íÁ))½Û•^œ(,Àó|±Q_Âø”.øÅ‰AEð‡@‹±_C Èõ†g )úQIܳ¤P|Ïóóþç¨×'3€eÍ`á(<À*rC‹¦˜‘.Àó|£Qÿ±£ÌP§¥‚ûÍ7ßÀ¶ XñˆQiÞfÂj{-ëÒqñâŲٳן|³X|Ïósú¢ÏpÕ ‹=€q#0@ÄÓ¬¶íê&f½ZúKj¯EoÛ¨àN‘ày>ñë‰Huþ€C_Í<ä òG„™LlÞZBMÏ×â.(.ÊÚ‹Äð€çù"ADø~*Û~€,׃:Ù™=pÝk HïÍÙ½{7…VŠËð<Ÿ "Çj¹2ŸQw'ÇTƒú~Òœ o¸Ø|Ïóóˆ‘âø7[­lYaõü‚¹õQÖV÷‡9ÄKÚ;‹Îð<ŸøõD$ˆqÿðlu%½Ž‘C¬h©eþ›!Äš?`ºM.0*6«*Àó|ØrbØØñÂÓê-Ý5ÐY̼;C\øæF}1æ„ç›: –ò€CLí~£Àð<ߪQ_œø…ôtÚ˜ ì«nN²Æˆ?ÀŽ\£>?ü-QÛ›‹ÿls&ê7Rï¾zõêUÕfrqà°ù’r·ü¢„íÕ"®¨q¨ÊÔ ‡8R|ÏóE"þ€.-.ºpÂp›á€¤Šð,ö²Ü®0&ü¾QŸ@$pÍÐz À¸pᆠPûêWl*ƒ¿Ýéq,;NeÇÙì@á 6ŒA19m#é_€;ÆïÏGþ;“kÔç™? 1P` à+Ÿ1cî¼Z0„èH9“&M$üc ªªj)ËGƒày> ÖX4ê‹AÿÒÄÀc]>§cxlœ=¾~|îò(oþéüÞÆñÚÛC8~™.Ù·oŸÃyà‹üȨñ<Ï·ä×Ç¢ÿ@ úÄ„<Ñç >ÏÚš]8WÉ“Œ-1>€çùðm°ó\Àü=BÕ;öö°…_z^!˜Ö|ÍíNròYÄøžçã»dÜâùz„Ší{ºoÖ ìÎÉn,I)>€çùD$È5„? GØzÀ¼ü§ÏLXéf ¢@HÊ5›‰-€‡[|ûƒäâ\ñϸJg–ÚÀÖI†_{è0¿À n1ÿ/ÿø\º\1Sÿ äh;‰HñŠ5?¥Ù·…Ø/‡¹*°´‘Î]¾Bðc3E£Ñãe~*Ô]4„½Ã LJ^PK¿ô_¦ü+XÆ$Ž (óÃÕÚ’bà…, ¿ÙaøCºFÒaŽL=úûûÜ¿?îóƒÇ@z¾ öVçðð¹¸ð5s±æ®ÿ@€$¬X Dý}ý8<¨ùð!ãKr?lëpÇoÞ:£hÀìêSÑÎB¹`blù…ë? ›+ÔÇGêýâ½­„—ÓE??`®¡x-]CpÛqL###y»kÅ™?P þº¹±ˆ9ß/Þ­MB;¨B(Ö{«|Û¼`À  ÆŸ?P þ nŒl!oýíÔ áƒ4[Ù?™Ç2„¼œ®™ƒ&QìbïðSÌLÃ# @ý¤;¶&8j¤þ¾~6óÊ`à­3f‰Wøôà—Y ø¯•6Š5 ýtöM®Æ™@90fƒWãÚµk¹žv1çÄ ÿ€ŽºòƒöÐF”S%î1¢^5ö¡ö›>¿>í+±ò`2ø¡ôˆ¾«ÓìÀþÀ ¯ä0àÿë×aülc2ø¡ôжPHƒ’S+ï_»z]Ëú m8ÚÚ;A©ÁbR:PM´ï`?þBèqÀ¢£}û.¼öóÏ?äëËiõñä„Ò Ž®j,jæÖ®]»`Á4Þœ•)7k÷õë×Á߀#îüPú¸júvHzÀÖ°o¥°OÝonàDv|‘H)ÐŽð§™3àÿ3ç¶š‹? ”þž1`Þʦ`©+Ïõ…t-ÔýÌMFóý˜C³-Öü¸ê·ûúɪ†÷„ÁwQ4› ê3‹ýÈJ–?G xè?‘0«ºñ”U³)é|ÿF4‡J–?T=àª/r±ô€ð!Õ ×Âðar=ºK™?pC@›Öøi’’·­ØÆ }±=«æh ølZ Óâó+¨Áðõ×_#PKœjD ù¥Žņϱжý øÇ”ª›6mâ­ ¼9¤ù¥®¤ûýÇHØö7ÀÚ-¯€;›îª­»ÙºŒ9ô§óš? 1ð}Pz ¨$FP_]ÕJ•••øöž®?ŽÿSß ±kù¦M›„¾Lš?PÌðy€Ëd ìü|_á²ÎȈÑòÿ«áßt<ܵ'¡ ò¶ÜÒü‘©Röc.—ÚV_ = ,ÿ8Þ?Ç`°`ÉÂéÓ§K£C%ÍH˜( H}ô¹1Vú% ÿ~è8“{ 8OysHóWø»†ŸIŒà­ ,ÿT—ŠåŸ[øÏ HÀ ˜&O–•, "†„ÿeÉÚBlù?zæ¸YèÍGÕœêI“'·½Aó k/XEéØBùÃÇàïJÅݬpæÐïâ%™ Ù5 X¥¬6«4‚½ílù?0Øo’þsœP©‚•ëW³žïš?˜R6·\& ÕÂZ”=,ÿঠËÿÛ2ëßB'GÙÌr1_¦ù'k´i ´lFÒ^Î%Þ|¼ð¦a±Veš?¤?`ŸÑj”Å€»åŸŸß°¶Ñ¼íŠæ$? ™(âþÚ];ÇñÂÎ å3Ð¡ÃØ•ZóJ' Y0Jt¨>1mb·¶­Å•d~ ÑŠTêWuõïäùÇš?P2ˆ© ›ÞÌ"zÛz¥WƒáÃáßý{u%šÙÿmzÙ•öNÍp¤…` ñª˜ÚBtÿÁ,"©å£Ã¿ þ¿Šr`Çç÷¯Õü×ÁP­Ѝpÿ‘“|޳gOü[UðZ?ÕÕkþ@’3J±Þ²N±‘EôìÀ~ó’oÅ«Êf–5¥RŸ´¶~ðÓŸf¶§Öý‰„U• s°ˆÊ+Êó%ÞÞ€ö€Ð㵬Óç¶%Õý©’„~PÓ§f ‹È¬ žèfðP+ÍשÛЦûh ÄL³±}SöôÚ.ÿͦåŸÔÌMktÿDlamåóÈ":5ú–¥u"AÄ÷íÛ'ÍëS£¾¾~úͳuÿˆsXL3 '@¾oɬhY)Õ´ü/[¶Œõw²Úb ×™2e H6"ßRót@Ó­«êj-÷óF‚EÄbDd!‰FËÿÎ;qëÔ{Ñõ©•%j(ÐÍRó4b x±^·na]y‹ø´—ÄüùóOŸ>mµÉ»Šèf £(ÓÐRó"‚è'w ¶ÝÔ’¡iCEXDlùß²e oI*øÂÇ@CKi³ž–š? õ@ÀzÀÏ–6êmÂÈ"Â@m)ɶ\«´U¿-WÉñ’WôŸ°ý”¤†ÍñãÇŸ~úi…ºpµÉ{{{;`°´£«DùÉÃ@DÒÆ~*¯\m¹îj‹v«w¤¼A½9}V üTY(|ÉÜyë?àd¾âMiÿjp/KŽ?H=[(¨ý®ƒú}©©Rï¬tøÚ Š,8ãß²ê? ƒÛ»122 ´.“AÓýCù#k¹CIU‹ ºBHm*ý ¤ª««‘A3Rš?,Μ9ã §³ñRûQz )†y‘vŒH}ßëׯSmÕ‹G4 8z "ñM‡@EÀþ¦I“(fq‘Êݺu+\LiéŽTDðû¢Ùkcc#¹|.YóÀiƒXÄv~H4Dš9mÚà–öÃ>Òv÷=KæÖ¤¸A¨ {G£^͉fˆÎw„—\WWG»—æ ùÚ>$ªš›n[0¾ÿàxoŸñ7} ?ù Pѳ®¥åŽÅ*ßl¨}ˆš?`„Rî? öín$}Xed!]+V2éÏ!ƒŽóO>3°ñ1õ‹jÓ½dh=z4_H 'aîò<J«ÿ€“ºÜé·¦"6·Yèm3ÛªËÊ}ôÑÝ Q£ŒNøí©xðBí—¨[å½û¡®íYÉ·Y'äã„X¿±»ðø3H°Ó ‘à„Ñ?ÝU-J²õUqŠk|oß„Bdaäàµð bzCx$€Ž]þ@°þ€¢J±¤ô{ ïÆ}N²{-ô€ì)Ä‘ @°¦b}[rHhlZòÍÒâLo4::zåÊ•Ñìp•¬U¯®B–tAD~DH †¬ÉO¢Ó&qÂ8yò$P6{6¥P‰ jN޲>ïDq0P€ì¦ ‹£ùC]@爵ÞU¿yPÈVú¹QE\µ¸Å­Ájò‹/îÞ½›èi4PsýHÀm R<üÞ÷†{³pæ£ÑD¨Ë¼_±V‘°75ä’DŸ©‚ëéÕóÍ“‘ ¶ )¬ ìÉŠiÓ`JÅ”ä`;Pw„ Òž={(¢JÕx(φÔZæLØíèúŸš[þsaÝàŽ]ð:ðÂ5¯  ÕZÝÏ6âjtÙšš˜d¨UI¾-Dr)ÕŸ}öˆ |y‚‡zzõ|ó§¢ ÒaJ³‡;Ï=5 Å Q2ÃH@LÁY£tƒˆ;KÛ;¡(ð`~s ½uOA‡=×Ò›f㸚Ê“§Lž1«¬®aÞÂ{ç‘Ii¨å¤ÞA©? èô0ýÉOŒ¢ÜhÏõôn•mˆk–o0¤Ÿ¢ *íbJøTÔ`×ÖÖvttHŸE1öwÁ/63¼ˆŠŠŠ|ñNÝ4uòô™S+g—¯^PõeS?ëç/?üüÐ/ ï86úÌkã=t´^—@ Å›Y”aQà.üݾ_ß¶ÜØj %kAÕÓ«…@™ Ú ’‚BTj©à¯~#̵qãF|µÚ[*Í{žZ]ŸXl}gŸ`’ÍŽí_ÿ_M·âØðÚx7Îü&ý—;6Px-ÉP×hP„¾ññž®·ÆqÜùPm¸ÉJqœ·w‹ÌLPÈaz8?M†ê:”ÓE*¬ìŸÿÀö¼èyjÝøåÞ–5w°Z=$ÁL,ði±î6#Avd¦íz‚iÔ„c@:.]º„ï[c ¤¿óÇ Í{è—ÀU/B>?•ñc¯k±s…åA!…"…Ïüˆà½÷Þ‹ÒrÿçŸÙp†ü~uÅ8Eö n=É—cÈa¿u’1 ­¿Çƒ¥´zÁ}þxìÄyœç7  œ­B?Û©ÍK$^ád („¬ÑÔбù~Ÿ†ñSS9ðÒF’~(zн«™i5º¨ìjGÖÚ1I|·•ÀøÌè*9=s_¾õè/ýLà¨_ÓFë•:ö™Í…Ô¶ bî{”ï³Zà+`2’$›WÒÏ`F£­&1~©ž5ÎM þÀkŸÑìk$ý%(&³Ç¬x$¬Þ~˜Jö¥ûñûùTÔIÛyeÿ/¨x- ¹¸EÍ·÷³¹ÙXã›n:Õ%Š>÷ïà‰-$£ê0Œ¨FW£µ¸w[ÛH=ÕµX錋DÐÇà@ óR%¢üy¼Š9‹‘-¹µÊ¸ã-@3§î}0'îV0¸ÜÛöðÝ,tcå[cº§¥^¶Òw[h€ÜùùKæÀ(XDYG“!^³´ÉVúÙñø£ð›ñ*f‚ûÿ‚ï¿ÿ>Bà|T{ñœ¹ˆö*`í( $ ÅhÓ>€a5ì–‡ï6›=VÇè{ ¥Ýܬ0«!XÔt«b±Wx!>U0z š=]Ì=ꦖW@¬&ô â§BØ4íLBÃ`iÄRDÆ1 x½„ ¤ÎtmË "­ ¢u+âào;nåa–Ü1×0~2kü~«µ_xaŽÔñ×ÇÅaÒØF»¥Vµ-£@sIèúÖÌtãï„…ÿøa?FQX8àÎÐ9À›€ ÔÉu561..zYy>ð/®ô—{'z ;à!I•:¸]eÓ,£@*`À‘ r‰T׉ÔJÐ.&,fk Ø¿¦°é‘#G7—¥' ñá xë9sæC¬(á¶²”øZ)ˆfxQ þ3Ц¼g.J¶µ+l~ ÚC¿¹ËŽiÉ·òò,%V.‘ðš9jÚNé0'Vú¸ijÌÓdU¥CˆÕºº±BÙlx?Šð)d»Ø[EHé çX££X3_äÜ7`åIæP: á[ávòª¿¾Cƒt¾«èÏ2c ÀBFᓌÞèNúM`@4‰÷…Øõ)Ö·ÿÌv É¿ÏgË%’Ì0§ÃÜ.ül>yÆ”V P¸%ºZŽê ¶Òá?* 9H°½¬K•@¾sÌ—÷ÒõMåÝÎÓd¬\"±¶9dwmÜ%•{ÌOÁ™æ+XÏܲ%ºZŽÕz $[ˆï›K +Íã¼`S™ké¨\–½“Äpö|7Ÿ*6<ŠH­ô®„C})Ü´^Ä—DÒW!÷¶`@8A!,f¶‡ £YFDV"«è ~ˆ3';¥Ñ!•·À=Kµtæ÷t¹ÄÚ¬õßí Æ|êNûÿ_?õ“»‹„IEND®B`‚Chipmunk-6.1.5/doc/images/hms_logo.png000644 000765 000000 00000027030 12151675775 020575 0ustar00slembckewheel000000 000000 ‰PNG  IHDRƒƒ®¨f pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF#CIDATxÚí] tTU¶¥WÛý[ûc+(6Ò_¿­- ýÕníÆ±eP•APdQ „@2V*#„@&f„„† 32‡•™€8¡¨ ž¿÷­÷ÂK‘Jª’z•ªÀ]ë¬J*•Wïݳï¹g¾5D¤F5§[A÷€Zƒºü@Á (P(Q{ÒÞ÷Ó>×Zû¿{´ëT빪nTô¨h~N>;pRíøRæl: ÓÖ핌U»dü§;$ié6I\R(£ªWþÎ÷ùw~ŽŸçÿñÿy^×åõŒ3Ú}õÕîóLÿAù óö¸x銜þöGÙúe‘äoÿB&®Þ-cÀ\Kî& Ÿ¿AB³×Kˆ¯aøïEälTIʵ½êïñïavÿÇ÷x=^wâªÝê{ø}ü^~)ã¼v¿}e;ñö¤ò6tâšMüÂ/jµ.(<,–ïkÞ&0ÍÆÀQó>“𜠵`“[É"pt€‘ø½ü~Þï‡÷UÊ8¡=G£`pšæƒ.gôGˆèǾRâ{ôâ­Å«—«™Ì Ç+0vi¡bÁAf¹%iÁï×¥ï‹÷ÇûäýÚËÚs5»†ò©©&ZKŒc_ŸÇÞý˜¼­\¡:ClRa½D/ܬV'•À3ß]q˶+p˜ #ñ¾t`ð~yß¼ÿRF¾ö¼7À`GO²3uéÊÙsâœÌølŸšäƒ°'NÄùÏB'Þ/ï›?ó9ø<|.»‘­=ÿu†º TòÞ‚GÏJ&”4îûašâæXLcÂç­—#gKw%?w^1Ä(I;P\Òæ¡îõ†ß€zŽê³ñ+Ì5®NV˜¦Í[Ê™d®öYkaú•í^Øpð”úœµŠÀ`T@õgãsòy-i¦Õæå7× ‚rJ¬^ì©3×ïSb•åÌÄRš³N¦­ýÜ)ïдuŸKÐ\ÏêeQ˜fÞò¹_«SähóT­Á@›»¨Ø:øå’ì>"Ñšhqr"ÉPn 1ÐÎÿtÑ92L>Û>¾Á+À K ¥øây8œÃ(Òæ«Ú¡&(Éø¤N£ìóŠìçÜ{ãò·(‡+cÛ‘322k]•o¥Y œÎçÅn$ióW-ÀP´I2Æ–î:R¼º:qddÐÜu²÷ä׊8ÍøLÛ.¼ úÖÁyáüpž c“6> †fF%‘+y\ÅjK¨ v¯ÛïeÄÊ_ÿøs±:Ê aÑüœ';ÉwÔlg•™@èoô î>þ•Ä/Úª¼‚•™¬@(\9•Ÿ< ëb×(“¥ç‰óE'š³¿¯Áßh2®ÚwÜæÓwÃj †Gñð™o+ÞSêŠJ õf@„kA4Ο êï+`Öï˜ùyÛ_ã>®°G׈…ñÓÅËRÙAsŽ®ê¨½ F÷6çñ—’zD°·ƒ!T¿Ó 0“foÜï’ÉXq%Ó_à®±pÛ2rÎ:¯T&íMPZœÏ %ÍÏPoC±D`“CB5¿¼;ˆâœú²ÝGÝNl,LÔp/ò=”­G¬WóúCÉhh°·Áß„)k÷¸ºI “Ѝ;Ƕ#gm¾‡¼M>ί ü½ ýEwK{o«Ž¦r•Iã*Ô½`“OI»-£Uƒ¡‰6Ÿr9ºŽ`–ým²÷í…ŸÅÝãÄ×? ëËŒŽz# 8ßœw®›Tè;¦ß…n5˜™@´ÿÞmƒ÷èʤ= xߣóXe<•ÂÍ BýhWÆ«è .¸Á¬,m0E 29} º·’óo…<†â Óî_Ù²‹s=‘ ²"ý¼˜56:mË{ÈóéÀyçüï>qÎ>¸å0t(Ž5|÷£r™zb5©ÕœÏä`Ñ·¦á2²X7bâvg–Ô$ÈÃè`6êëùô†éA'OídÔå+¿Š™ƒ®nF5} úü/e‘«úƒ+@¸‰N;ý›,òä ¢rÇ¢OŒO}äK¾£‡¶ do¡Æ7·ƒ¡§þ ‹¾Qû”ÅCI¦ÌN¢´‹ñ›6¾þá'å™$} –\[`Ën+íén0°<ì¸îÂeFNES*JÌu\ŒšG}¬;pB&¯ÙSáœg=|ó·R‰4ž(Æqg‚ ùcpHw¶¼ÏY0¤ëW.@lÀÓ ÃÖ,D9ƒºz ¹býg­±7©Lû‘†6É4#ç¬U/ø!ÈŸ‚’1œtwõmžºóHÞÜìñ2aö†ýêgÝmÌ{Ê-úî‚造—oñÎ/•—2${½×K Î ùd0Ã/:Sçé rõ2w¦u‡U‘Ù¥'ÎZíWÔ =5(R—ïTYRÆ{ñÊíóE~’br+ †õ+1•¡^‹=0™A­ó§=š¶köP•ØÁ^T‡QZ`ü²K~±¢``UÏb[ÉÛ¯ª'YJceDt¸¬«ôä(‚ƒgòš½J—P÷±ìÊ$ùvéªofqYÕZeá="ÉÚ@³€`ËÜ ”ÄŠH=é%kã~©Š±ùði›Å㥎*òü3D6_¨rôBØL“¤WÛçp•-ÙyD¹›ù=½Ü.*ZKQÙÁj­Yö)PVôþÍC¦’WŒ¥{.៺ÁâÐpbVͰhûUÿÁþSß áu‹…«ʇN cêâe©ªÁ´öx/tV‘{®².jüu ɶ”r[RXösÀ‡Ná‘¢kVÙìÅÔØ-®*“`BÚéTå`¾ENá!µm„z‰Jþ‘]²³`¨ :©§“[Lt;Ó\.2¸ôK q—fN.Ò3XÓhV®‚-еI¾ýñçrk#3VîRI'®X³M´.‚ƒƒ1s5uèÐAŠŠŠÊɱ´9«FâªÊYE>’Ÿ†¦c‹ìÍL{0ÜGð“»Ð­Ì ]Áå¸P¾€Žž<­à…L«“ÖCf€€€b@,]º´ÜÏÓƒ»v?U•³ªªtòUWo4~;Cý“l_gf⊠›]r±¿=ÎÄ(u8é+ö3f»udeeÉòåË]úv¡c݃ Ø=ºuŸä«aô) Yüĺ&¤ôØ»«©ï¬›H*ØæTYœE³0ñ,eé&U16ÁYeÑštx ä'ùjX€YŽÀp;è¬n/;Ó`«ÒÍ® ¶ìÛõ93èK N0Ò‰€‘®C°´™ù(u Oå†è R eþg5¾_†WôO,0¹Âu¤¯è`ƒo¦z•—|bÕÒæùÖ«À@hæl=¤, Onä¯a¼R"ôØ=3e<‘ñÌ )NÄ–Jä6ùê{åy *Ã맃!¿¤iUå@(εô°UAþô¨ˆÒÀ°Nß“¹Ê<•ßH1_Ùn,ôúqbG”aº1)†ñ¯¶¬”e;LµØéj䯡fu=îí솭_žñXú»‘ÈHæ5~ýCÅk)×aÛ`¡­ ǵ5sKjÒU>œ œãù‚_ò—|Ö ÿÅ`xNW/Ä9 U¢U%‹ÀÜÜyìl…'øŸ±Ò–'iÔÔf¯µïTåãØ¹ó××S` Ÿ ;ÖsF0ôÓ#L†Ÿ_5Í+¬Zv™½å ÄÿÅ O4û)2tK‰ÃäÙÅ^¤/· …zx¾Ãµ¤ƒuÕφñº š'­xCñ)AÅðóJæ(ÐQµýèñÖ±}­=ÝJˆü%Ÿ ®éñF0¬Q>ôo´(¥7ä7æÙlbZ ¹…×4·ª6ƒõ Ìdöä´hŠ$ù­5:ØŠö€îlªª-¢Ì8½ˆ@2+¹ªãPФ‡MÌð’Î'ò¿&Áð?¢ûÈf™¡^XÌdS¦~SÁäÉ.¥àáÓƒ‘Y[ÏGÏ*‘ä·žSDè§À¨A§Œ·–£[µà4)PºØz§: z"UçÅ)Èçü_oá)‚¡µ§"•î’tASŸØpèTµc4t«[<Ô¤´”fk‚¡«þn†Í÷þžˆzyó$YkVˆÚÓcþV[¡¯'tòÙ®ÁjW‚ÁOO adÏWd“XÒVì’ó?_ôy0|óƒÖñÞ¡ò™ü64?ñ#‚ô|=:@|©Á•¾mp¯M.Ønß(ÓG-‹/=âw ŸÉïKW¥jÁÅŸhÇ3iÄ×À û$(!¦®Ýkß}ÝçÆ÷8fIðLæùL~ü7QC‚JÁ›´å#} Å}`zº»ƒlU öV0»P¤VÍf膓@0$êÙCL‰ªÊó+«Tr»X¾ç˜ÏƒÛ®$›™:@~*ÐË• ü§«gMo0¥ÔÎh§k·:èËPDdfÇZG’Á¡Î@'ƒE“Öï—¼f ß`ú¦ƒŸÝ•üBpÙ—ä«÷ЭÕÕ2w½_ƒ;!¨ªq^“f%%;ÒZ Opˆhû·"$0c‰$O^&O?ÑOºM•$rV ˜L­›„"‹!g@7uÅŽfïËÞìÒކ¸³âtú(½ZTþ­:Hf™³pdM8ô3D‚¦¢öÁ»ß‘.gȈè¹ò‡/É;¥Ê˜Õ{ÊCyV ‹aÒQ `µl!q0 ÉܱHL‰·@îªÙ\ºúO”øOwJÀ2=Òp/ãa1Ä¢2HmgÙÛ¾”dä,ÄN[!Ó–³VɈ×UŸ÷y0°Y•˜°5;ò38ô@R\OÓ_3\M|TJ¾Ôú¯×¤GÐ4 GOTîU½¢ÄŠ¥âTø8ìIö€áƒ)fâz`pçnñrÛ^“OVK,Vx4VøˆÌiðèòAØLIÂ=Ÿ¹Rš¿ì/?Δ>'ˆeê§…kÏCh»{«¼ö^¬Œ_$Ï=í'O6ö“Ø‚’€ëT‡°7ë#͈Y8ò@:ŒM ™Ù{ŒÁo븅RŒëk™- 1d¬Låj “‘a@ÜThTÄ 6!_1^æéø[.ŸÀ 5]î¬ù¦N].1øÖNƒ‹9g×Q‰Ø§ÄˆÆuÛͯI,$@ó—¤îáãä<ÉĽÞ~sk ž¹J&î8"~#&Kã—†Ëdñ°®ÑбÄw½’ú9œ¹ž‰M8ŒZ “Áäþ“dDuò”O#¸b +˜•‹ FÄΓAÃ'IÔì5‹÷“ÁÐûîî(ÿxbÀ°]b°Š£ñYg>€ÓàÞÎRÿ÷%iù. ²Î‘:zK‚¦¯Ä–°Câ‘¢Ö­[‚üç™AÒ¾ß8KÉðÜ]»½ŒÇu;½#úÝ«ò?"r¶üùövÃj‹ëú‡Ï&o…ÊX‚¹…SäjÑ„ r³ea‹Z~yMÔÒa>ƒ†·;EËИ¹24pªÔùï7ä]¿40}§ä`5vz;BjÞÔJ<ô@w‰ÀЇ´õžÐ+¿ )Øç§bÅG‚9±âƒ#fÉŸ~ßZ5$[‹È ©[«½„Ü&¬L»KY(úm+iÙ!J’ =Òñ|çßðIˤ+¤ÁÐÅoÄ$õs$N:À @^j©ô›I¼Aå T‹ˆ&+ÜÜhY8Êgp˜éD%c”¼>ƒÒU®TüíÏ5ßÖïÆÊ„Í%Œ¯ñýB‹@ K_"w(ÿi$‰X‘ѳVKïЙ²êði ä‘ÇûI>B-^!µo~]ºŸ,“¡- ž&õî|[€|š¯ÜVÒp£õnk'-ÚEÊX|&á.l%Aãóåƒþ)rÛï_•nVC’È ­¥@ê—-mñùV.Á çQnþ¢È'^^‰ÓüÝÙDÌQ¦“ÃHþìÌPÜ(V¦€Q÷`sÂgì=.½Œ—[ûŠt9Ufï>&þÑ_þvÿûjUŽÁ‰²ÆeJm€¤Aý÷åw¬Òà»H(L¦Ôd8s÷ðûZ忈‡Že².¶Žf¯‡ÊH¦ l/wÝú–NX$†dÈm HÎúü„d¢T?ÊULà@k$C„ ZöÜÍ| i+wªs6“ßÚÎÑŠÊ57Òav4Á0 ׉2 ;`¨w[[iŽ8«ºGßd¹Œöƒb9bºy³ù¶ ꣡c„&-;j¶‘{ÿÜI"°J;§Äÿkãd4”¼q ##g)F‚É€*£ÄÉŸJ?¶‘!q±Íd$õ Œc+ ûŽš)á£çI§~cÅ‚¿†IÊk5k^löòþ“áX1ûŒ w  ™± G8v˜M‡”tG]fyÙÑ¥ÖMp›˜‚jç-åp"¼‚uo}SþõüPIÇþÿáÐLì÷í vIÁ¡"iüøyž Ä5¬øl,VlÃû»J“Ö!JGÕcô–Ac¨í Ÿ …x¿í¦W¥túò q¢bæHM€æÙ&Ãe,¼Ÿ¸ñ»ny]'æÈ è ¿«ñ¢Ú‚>ÄöðHÃð…ì‘l[½?H”ÖïÇ+k"*÷jCó?y¿j·â(öaeXiÃv0Ê:·leÕM”ZQÅÕ• Ÿš{ P›¼d›<úpoyâ©”ÆîŸ’'Öï& Ï”‡f(Ñþ1”?å@âQ9XåÃSËÈ©+”>€„R+Æ+¯=àƒëÖn+¥ÉDì‹¥ÊSÏúÉC {ICXqp&µï›„kçK$¤ã ñ4c¥„câ^j"mÖvïÅÉ›=aînP××ïŸîÜs^Ö›¡ÔH%½Zñ0_U¥cáU65±¼Š*‡µ–œÐ€€qî5ø[4þM9Àœ®SäéfÃäý‘Sƒu­—¯ü @4²AæB­óX`Z:^‡ÁaÄ­…~‹ \;zQ¡úJ Ùð?J"=“‹¶(Fsåóï4mé·âï1øžÑ0U­è#©ï«¶&b}"¬}Õ䣿®/öÎ2òx)‡³íDžÊº¨Ë«µtº ›L‹Ñüÿœtîód%…-^áÀã¦dA”?ñpiÞ6BíñéìRo™)ü&¨­E›´_ã—m/á´*¦Ü’Íq+múÇhH1õy¹?ú‚d¸b(µ³j ãÑömŽx¨sÍUu¦ »òýrËN΄eòÌÓI˜‰C þ—<-/þÛOÞì5F­üŠÄä“ÀäI21ŽðÑ9 W5d”lˆ ýéâ%ñ…A»_ï× "§Á*»d—ðËFaMs¶?ƒ©[ôJ…"8pØDåœjÚz”da5×»úÂÀTId¬CSn,`$·&n#FQ|2¦A&·þž€uy?Aê!˜6jl®<ø—w¥IË‘Zøw“Òš}¥è†R ÊÔ¢ÒùÀô¹¨e}ÎŒÎ-¦öt"ƃ‘ÇÍ“¾“á+xE *Ùä…¡ c•dP~C«ž ›;Êá®´`ï'fæ<ø&`‚ÆàzÔÆa{†ÀYÃGúHöö#ò(¸wÂ16± *²×™ï/ˆ¯Œù¨>7:—V’ÛGa+’VïJO'S»½Eâ¡R°R{㬷Äg­‘¦/ “—/‘ÉNó3c1üí¥6¢£O"¶Mëz õYù›åáÞ“;àÁ¬_W Bt3&nÌ̺wu”IØ2ý³¿Ôƒ‹`H€5CÍ|û1ß XQ‘´ïI=ŒÏaèáˆ6Ë®÷vp¥Û›©} #´m¢çt‰cÄ¿OFÖT‹f#䉒8€a>Äáãÿ×GîýKgé©Q>Œ^!1Xáó·ðÚ+R«¾üý­»<üP/™€m"(*Kî„3, Šmcè$ôhÒ ¥ªšƒî?á3` éŸVŠùȽžï±‡•®pNp±Sœ«} MëTN„2Ô .ì(¬tîw™H—® òÈ?¨XG\Ú¹A¬fo„K”Ë—”ºÐ)°R&Ñ÷Öy‘ÐeSÝ>H’[ozÒa™D½`Èh^|vˆŠp…‚J×¶/&ÉÒì³W­šˆçÏú¶Ç¸®D3]íkZïhZ<: ˜ÏÔ4júLnùп?ÖOÒÁþ‰ÔÞEüaú0ºs·HD¼âNl­:Z%½­ƒú®ù›V2> ÜáÁÖ ^Ë»kw+NCeÚ VÅ`ôX¥ o¼¦>$D™œ[•¹ÌàV¨“îéŠôŽ6­«<Á0ÌoûV¸|Œè#¥Á0"ÿþûº©Ì©H¼O†ƪÎÚRº#&rß=ïIÄý8€§<œ]áØšŠU(Rðj!lPVx=kÁ]Mï\Ó‡©œ‹aC|­Å¿#÷®7Åz†S)Cä ;çó3Ô'œ9ã«"]å+tÞ„3qv*/S¥ü÷“äÕ®±Šù©p:õEô±îí%¦d$òëÜú†ø#ie>Vùcv—W;Ǩ¸F®ñW˜ïAZ,X·WZ6.O>3DR°Õg,•Ç „ºQz,Ïào¡³×¨((•±}§¾ö90ð¼N2Ðâ œ+ÝÙ†ä•9oÂé“hò¶ÈØû0ñÛ3ì“^­x?f±–À 7ó°ô¥*M->z/G a¥Ÿu¶r5ÓíLñÞ¦Kœ<úøÈg¬<‘ê³d,²¡ÚõN‚Â9@>ÔSF!^ÂT9«–Çûák"¬•è…6?„/gJót¤¿mR%‚‡ˆWù””ƒ‰¥ø»ŠÝÑt<ÑWÀï²0‰k`~~vqˆÝ ÅR)ïÚÕð;úôÕ¡ân8者gT•{zE%°ì“ÐÄTyèŸOAé EB,˜ IA)–³Iæ¢#ëÓŸ“Bã$væiÞ¢…´îéGÑAIY½"p³Aô­ˆ-ã·JÚºC(î@NÃò½ZÔt·d®Û/‰yÒÊ}2cùjI” ©ù6iTNÇ8³Ž(òÄ`v7uƒÊ´IpÇéuåžk©ƒ! jŒ<ú|sIÛvV’–í”ÙqÙkûx@2²r¤€šž…Ê1ÒæíNòôk¯xBÚ¼Ó]­øøåû”té=l]d+¥t×¹–åžx»¾ô¹ˆ¼*!“³k؆ä•GäÞû”€Œl%¾÷~‰ÉÛ( é“ä_Ÿ‘çZ·“¤{¤e§î2)o¥X§/krªÔ¬u‡ M™.íÞí"Ö¤4y䉧%`R®a•&zÙJúf.–VmÚµHû.=$\u€Ý\j·©¯Î_ðy0ðÌÏÐ ú{Üyâm¹ga[r¨’ÌÅk¥AÇ¥ß0y¼é«òap¸<Ùü ™·n‹4xì Ô\ %-3`xVš¶ï‚|Ń’œ³ZZµl%?úiР4éØSR ÏÊôE+äžûëKLêdiÓ£ŸN’—Þé-c×–‰[OI«7;Èó­^—¾áqJ)µƒEµ÷AÍÄ1߯™Ðż«&¾»ÏÂÖ)WwR 3dA%,Û-ñS³% 2ÙϤS¯åýÁbI#-º~( ÓçK½ûP{ûô]ç‘ÔE^nÑR'O—”{¥î½…5‘#/¶é CÓs°ÂÒgËÍ7ߌt„<þ|S1Zš¿×W’ g$`[è‘$-Þl'Ç&AÝr-àò%÷³3c ~wu« ŸÈ/Cj[ny¼v tË‚§°±ä]Æ.Þ.þó¥]ùÀ’"£f­ijÍZJ0~™½Jü’g©Ü‚~63Wšvè.½­é°`²Î/ ¿P)¶Žk£F¢Gx²ŒÂãþ¹2rzŒúd¹²TT润AãfËGI³JX/úQŸ<%Õm¨~ yÎWds.ȧWý 5>V ¤ôâ\=”»‡¤W}§{•”ˆÁϱK‘ Ç·@Ä/Û}5€‹·ÔfJÆhÖ€JUÓ1–ý±K¶k)p%k6ã v¡ŽsG ‰@…±ðÈ©®ƒ&gLäOAɶéÎðÙY0Ô¡C’We¯cfÊ”T&7^ÓtËqF”û+ŠYW¹éÐi©Îƒ^Tg2£Éò‡|ÒÆqn©§~uöpŽ4ñXdW›sì>"Õ}0M-º²:çè'ÚõØîé,]ÃM …ú7èÇúV%¸5LGœâzyÛÊ.À%?ìŽwZ¨ñÍí` Õ§é«{Ç&­Þ]eí…)™=\:´8;xغ#½| ? =)Š4~Õ0 %Bܧá¡»´*zGr…<ý\Oƒ[E¢Ú*6\“«@>e…¨Í)IÿÆÝ'¾Ò:·xVO0T]W#I@FE2R+#$ #©"|­(nêß¼jßq[ìÝ %·Õ¿°šžLSÞàÙ[:8ßœwοajüñtýá˜ýÈóÀ)¹* ©°÷ä×r½¦ÄÅ-Ú¢•à­Wón¨1?檞à.0šè‘Mîg<ŸÚ,@èÇ%3Iãz¬Ø·;çÛPõ«ÆURýnxòì4˜zf‚‡r0zçK1f8t…iòÇ’h|¨QÕ` ùýèÌ#p' ô¾Ðeu6¹žÆ÷èÉ‘†áï>º ¤`# Ü)!"µ–ÂvpcØF°»xèN0Bõ;¤ãžâ Ã×U©°xç—7Ø~íu'ÿÜ †‚Þ0Ýʨh»üH­]î·~¾Áz“$‚™`(¡CðdÚÁdª«ÇèñówcˆÛuOA·2Š=C,§ËÔÕ|>[xê›n°ß6.»Ãj¨ 0šŠ³,Ø:Fn9ã­¤¾Áü¿C£Ú|ÖðU0èžÊMúÑÌ0«ÅPUì0Á¯‡‹nÀÀ6õÍæ•'À ·$N²÷±3#'Är©'ÏÜ0'Õ¼ÕôŸ<:Š–¡{,™¥¤W[ì¶n)×ñ(ÒæËcüñ4H E+ÝÓ«ƒ™Ö͸¼¾u0_ae58M¦‚#G›§Õ zµV/£rI”Å¡™Z»âá(©7‹^OJb/)£ê©:‚A§º TPqÄ…¢ÛQH}âø¹ó× .ióP·*ùQÕ`Љ§ádg‡¡Ù‹—¯\@ÈÖž¿Êùà-`Щ)(ÿ:‘ùÚózÍü{ŒÎªùFf5ò Î7ÛyTÝÀ`¬óòõJÚÚs4òæùöv0Ëû:j¢ÕW´ÊóÚýv'ËÛn€Áuú+¨/h–hgdxÑ8£ÝW_í>}jn} Fª%¶CZÃ@kAž®Ç?¥}o˜vµ|y>} ¥m'8L©+̽´v˜§G‡þ³¾·N®`Rj¹ºðÛ;@Ô¡=]{½ùwrê{Hi=¢ùŠÙ«;Vì<óÀ×N¬öwëvÎ:ÂèCpƒ!÷ô¾'’Òádzôùî1ûë²åíþºá쫺Õùýs¬³LJêˆkOI4`½6 È»o£ ¸Ô´;m5讬5ú&÷¦ÞRëL‘|osŸÐ “@B†Å0¯·cáÝÝp.ÊfÜ´Î5 åÔùИkÓ x®—}Ù?â;Ž~‹¾mïëlP¹4×4 Á,·Kžðš6ÓãV3n±Î6‰j£¸ÿ(MòþŠ>§Â¹&ðúÐs­ß)…uºyèr{­‹4,LrM1›°æðým"_YqÖYÇ‘òhëNS3ñ€€h€¶¼3¼\í‘ÍßëëÄ£)÷çÏýoÉvø¥N‘y¡÷Ýë¿ðr¯·)Ç6Þ:õ(úcTí‰pj6çã%äº @ôr+ö!syã#1Õsªuò¨àWî{4ŽÕÛP< o²øÑ+žVãƒRLvžmI64øAO‘¯Wcás|@äºo•fÁK°ÆÝí~9Èsc¾J™SkºÁ¸ÐЊB!íl¶ÛXcD'3Q¶PlHó†pª÷°ßjU€ÛXçÛÝ퀌½Óÿª øyúûÍ… +XgÜ©£Ðüà‚bª,»Áð²U³\¬„¥VÑüׇ‹ H7gæóÙEë ¤ÿbøëp¡:! lÒ}ŸÕ\ ¥ÍÐü¸³ ÉÎ!DÔ *ÄCFò[—ž2ì—Flx\âª7† hÂxé·3Ññú™åsèj¯tab6¡£¸0­ô§ûôeÑlz>¹|ŒÎ¢=ßê¶EDW8¸N¨HÚÌ” ôãÒq†iÄöË£Ù Œ¸Ëin¦/ùön_¿|‡õéÚáŒGWÛ ³°¾˜†˜#KŒ¸K༱g2ìCFì^l7‘Ë^=»—îˆk! ^âÅúXÜMš#©N)ª„¼k3ê™ØÓ¾ÏÍ9Ãh¾x ÆÿZ‡1"Sßò-ü ·L53i:oùSmö-Ê¬ÃØ‡áÿ„ Ž' HB©i@Ú0oZªåÜp’7¸X*€ÜzŠæ; ùŠ˜ôbì ¥)@Z~ŸÇr}¬y¼¥ WÍâDd2Úxƒ'Ì á¦Êš!Ëu.ß%0"·%æD(&©úÙ4_‰kiÛ~@¨ðcÁî>ïâOzQ* *ù<¦`…æ_À65ç/ nÐsË|fÁ€<#ð³¢Ì=œÎrï…æã÷T#¢ùiÀ-KÓSM‘|³KøÉlù'ºß3> Ÿ[r†‚“ž¥|"3÷ dW0Ý·•>Wd©æ†¦Oæ`ÌVòÞ”ÀDÑwÍ?8ì˃„·‚„ þ-ã´Õ uëBϽIy¹4L½í„Ô)Â7*ÔãÏ™G£Ÿ¼ê^n¥ãµgüŽ)¨í/¼±‚xI· ÷Õj½v³ž¾)…áü,¬çËGŸ×@*1O-È„ V4Q¥1°³¸w=¼1ÎxŸ4 0;ö²Ø£MºNÓÇ9fJom— ŠXÁð3ÇTÇ7÷—_x¢«ø3¹ë[š6~™ŠR_.•~°:«›Îˆà9*ra,èf&€O™.>H/•~âî ‘Øô¶øöö.AoxýI’´£”:Ú‹+ð¯…)X×e7Å_²ü#ù“„”R?Ø7ýl¦b "]ÉcýÆ)Ѐ¤XÐì*ɪé/¼ ¿¤ ®yŒ3fÊ×Yð ÊÂ<@¾%ý aHÑÃoüQ]n¦àP2Øü=Ï»—ra™N­i‹$_3?Ú—¼Â #ÏŠhÁéòq–Ñ$Ì¡<ˆ´ã¹qQ(æœN&2ºG“9ßÂ=1oîèî„¡¢Z@ª}@ÜNaÚ9 ìé/xìȘ(C@˜¼u–…h«ßW¬ÜØŠ-‹¬ÜE·xT–Ä.y @ó³i°r$OŠ^î÷ÒHB,ü7e\‘\t¾¢³9Vÿ$’Z¸Œ< ¦<Ö9ñ>Rß|P"¯©uZHSO3©$·‘ŠÛÒ*CP©eC4?™q–[ÎÄ9Ìÿ;ßÍPeå– —ÐÔË<€`Ž8¡æÞ¥¦9àÔ‘¤n£ ži˜ÖUäôp×ËÊ–þ"'Õë¬Îæ C†‘Tšˆ¶u`?“%vøÝX€¼ÂÿZð…Q’a‹©hæ§v˜Uߥ”l:M~Ž•\†£ùyðxr•³U ¸â·.ùPˆÔIšQÊú\*‹±ôó1ü6åJ rýHjM£ùÛàyÞzáz¨:Lx~ô+ƒJ:@Þ9úñ0³õ—ÜBð˜ÐSPÆX³×©g¦Aü@R©áwh~›kó<ª}÷ßeqÒVîHu€0i,C'¢  ’z™eÀQfþflY—ÒÚ^Å›¸#ZÙhº×“¦Ì¥Á/‰‹*ÕÑòÐì‰ÒCÀ9­[u'?\*2 r݉“Ôj‹q?Ži8¢hsìÙx”õiAa^²â*ã·[WÅâ:5ç˹÷ÒŽ='¢Sã7}ÎS½YU®?FÂèøU ë,¾·@!Õ<{åfô iS¯èC¤Lš½éPHcGø~ãbÂæÎ¿{Uâ®’éœ^¸ñá'¬×ìÑŒ¤ÕÞ˜\ó]í[,îp·2€Àçͽ£9yBH.¡t!ÕXˆH{xc÷¾j’ŠBB ÷º×Z“·2€À óraU“PÛ‚ñ&á «Ÿ>F0ÇÇCÅD$Æø_H$¤üëp Ÿ„/-Ú Í6ÃáJÚ"~iVïDr¿òý¨²Oj“Ò‚þøîwPäøµ%eU EÂÓ !6ذ¸f}¼qZ·ò‚„í¦ÀRÝ ¢/ž<žêoo¹€àÞ6¤ ¶Æù’¤O@Å1\Ï}sb‰€Bßk!üŒÅæSÖq–%á:‹ÈùŠð¾´.YúL1ð Zþ;H6P/>Æýº‚|[ • T3~/DìCÖ^ײ|…DMÔÒ×éóbýÅ„Â.­õÌIÇ8òç•WË¢Vz×ç9¶9†è¢Æñútds«Û)Óÿ¦€ü;À—hsþ8¸š¼Ë, .„y“¶+HZ›ïÍWJægl¤Ö"4ûX ðeÜœês  IB¤Ê’{M›7™µ×ÙT[λ‚J"}Rv"³Q~îþ°²‚žD+ÂåW¼Ž«ìM™† ­'œúg¡£¥á1"kø«-Ýñ Ê­Ïö„1&:#ó³ÀœßÑl”ššy3ÇÓâbo¡éö½Ço¤YníkWxË £Z£ö@ã»™e²ó6—61öȸrožŸäÔÕl[ý¡cÜgUÅn£Úà¤Âijé’Pû ^’r:@ÅpÊOjý¬ÛÜ;7 5ÉëƒEˆž9F.ßÞÙÕ MU«8IºÄàíãZpñ8ó™lsU.1êCl\™/ÆqáÔÕXð :†F%9rÕ=©ZšñAŒzL×Jv2s )å9åºô]îh5˜ŸŠˆ"+™>¸˜ù!W†£\©$;=åÕ«´Â]ö<#‚eJc>Öq™µqe¾iÎçÔeˆZ¢cä²Ó`4ÍD«ÒâߤçHey’IsÒ’ãÓ´Ý+8ÅÚ3 ùÒ<ä 8$Ízý´È€d$¦É€B-2IʬÄ,ÝÝFÄjb4_DÊæ0‡ØD¹L¯Ë<ôØÛ ’²Ô/©³’4V˜&€D„‡²E¢ü·¯%ê"ò6P6v@N‘:]ûÚ#¢ÃÇs±`Ì.²nžC†®ÈJRŠÒôó)ST­1¦Ã“cõñÚÛÛ‹q᪠ZapH†Q2eÅ$€07‡¾!õÙV>Û]›t ñHˆæëg{¾ÁÚŠCH…CÖfùÊ•„ør"@ò0³V–ÌË¢MÎÑ–öÀVùŸÛþ3pÈÜhöÛ¦¹ÔýñÞF]¥¥iuŸNÃOjGœ³ùûöý6dq¦X÷46ëE¡ÙõzìZ çþŒúó·o2–÷j×÷[Que}à@ÿé‘ìvŽÍy>º¹{ú‡½s×tpï¶‹ôíc²§­ï×¾÷¢—l‡Ò5Ý:ø9… ¡0Šèƒ6b²•u‘‚&~Û‘r=±çDÀdˆï²˜¬„ýþSàÈ"œùî~yå¹!! ]·«DQ#§³C~ÔqU¾»l­×´„PT›~ïhXóϹ‰ì÷íjÒŸ±îtÙ+R… €5§Zw!=ùȨAPûœßu¢å»ÜóƒÇ=õœ›isil¸æÏ]žo·î} ÉN¯mp=´™Qéå²6¿éÏOf:-­-÷#ÔYŒv$’‹®E9h+J2óy¡kFƒ¾€ ÈØµSþýçWG°V|Öö[§¯²ú¡vìÙËg«l¸ÉÜùdpÞ‰s».úðƒÔІÉ\¡±˜¡Ø ¿emáëÍúþqäí[ÕvF2ÜÁ¿Ä=¿|#®çÕõl#ÓæÅEÜ:ï²ÃWy=êÂ'Ct^¯-ëóJ ¥Œþu™ $ MÁm8çÞ4y‘<ôZ6ž _ñ+€@¤mD¬§|¥ f8KIù Œ„\›Ñ߯¾¸HQÀH½f˜ªLÅ”N»ªÏ;vl…§ŒíKÓ‡^§Œ³ž¶TÔÊ*±[ZD¸o\1C’ (U$€à|^v#T&7\:IÂËêAíÏ+ük±dëµ€î½F¯þèæ„*thÙ‰w}3´d«ÿ$…O#ß%Ú”b²ív*ÿxÛ&ÜVè˺7Û÷öÔ Ù{eßI¥Ü@¢ÁcÚŠ|ºÉeY0'¡ÌaC HðP`P+ôÈÜ¥T"Ws%¤AÏ—_¿3œ†»õ'°h¥ý¹Ñ›$ú¯vàŠaèªRФÒó²ÔÓ‡ö€µ«¼ü,<{”A3šÇ¾cëÇrßãú*Ìgxã†s¡¤\F\®tÔpjP|•eÌÃîìLñ ˆ%>*™$Wiµºòýž¯5»oìÿÈàøžÝ…Šáù?w¨~-²ÙÄ—r+‰¹4É ×x²ÿÁf«4#žvüZ©…Ç6°‹?Ï„2„jÑ)f'd>]Åpoæ0»‚“ G¹ 'M`ò†ËÍS¢Äd0ÅŒ€(e˜8F!ÍUì©×o|Ï}æw©·V}êÁxNƒ³›WÜÃ\p“D³.tÞ5â/•ì¼÷¬3†=<Ø¿ÿž5ý=Îw=S^S»©÷¡kÃìõ›Ñ>öõÈèJqÒ§Feé¯ñÕgÆI“6tÞ‘DQß5Ùò d.NèÃõ³JÞ† ®¤«0xÀ³;Z ¡Ú>uÙèÓ¸Q5vk.0NΜA)*Öª¸hG#ÀÑTúC¶?2üÔ·•Üú'…ô7aD``à”å—Ú sÖ yržz…’Sc}jºWŸ¸À[ö³«,MíjQí÷·ÿ¬Ù’Ïÿ¨KÛô}•ç{8×Ùè7ƒóxÅ2h6àÙ0- e˜€‘§ ûëO:@è×°^\_9yꚨ¸€2ÑÔcÓFŠïtXLÓú#bHuÂàÕ!b9¼³ìÏ÷×MšúÄß õ¯áÿ·xêjò™>zÓÑTìÕ@›«Ç²Ã~f³ôÁÎéC¶>ýq„on„«-#Iva ØÚ{™JÔœˆ °ËêW—N^y †#>7nnš½úú>;NîS-À† ŽI@°s^nXò4¡‰õ¡Mô„¥KÆyê\Í*ý/ö+ëØ±o9š¼ág¹rU¿÷„WÇžžš;ë_±À×ѰõªÝònUÎà*§h¿7îîÄr»~ ¿×:gáàŠ”{wfb[ö´"ZDÄÝ[±µ;1¡9õeOwM—­¦­˜Ù§ 4ûiÞDcC)h_˜0³lZ@p§D4 ù|Û1vb·W»] ð,¡ýfúì÷íJnREdË·èÔæØì7nO’¶è|xØÚ ’šñ·UŸZ{±ÊÖ|&›Ø†µ%îp‰˜NƒñÜ'¶áÄ!æ—ÐóÖÄ8ßÒòu"6µˆ‹êô@œÐù|¾3ob[P2€ ·Ÿ–M®iæõoSJ‚†íG­ÂÞQÀs0Kbª,aJ¶˜¹VÊTŸÌj¾D¼,VBT˜{Db•1N.jÂàâ«,± Mâ’˜yá–V DE[@˜Ê¡ËFIŠGe ÕX¨µ@“¨$4x\“€”Œü‹pã„Ró9X6òý5âõO‹˜Pºh^–Ðs/¸œ¡T|†x 1\bEv#‹ë7"yY"æCIZ1€ÓXS¤Æ ŽWÏRÈS'È!|jbÞ@ªèÂ{ê‡âÇPT\- „‹š­‚ ->¿^rû!øn;:ùaöÔ‘§Y?ÚZW)•JUQ¤4$DT‚‚xFŠˆ˜ÝoR—+áH]P8ÃO¨7“8F]ß*~‚&|DQ—Œ5½½’pJPBL©ñ]¼)nAxN.ꌈèSõ²( í†X"âˆõ©O9õ© šD€X©ˆ¤.!¤ U–q¬þ¯ÔI¥4J°ÓPD«eO…x‹&R~&S‚‚ÆËï³òr{Ž–O7uòÿƒD–nÿÅ€àÌ’IÖ©+åÀÓJˆUg}t@Ð~ ¿Ûb:óÐÿø]ú –EÂðIEND®B`‚Chipmunk-6.1.5/doc/examples/BreakableJoint.html000644 000765 000000 00000003461 12151675775 022375 0ustar00slembckewheel000000 000000
// Create the joint and set it's max force property.
breakableJoint = cpSpaceAddConstraint(space, cpPinJointNew(body1, body2, cpv(15,0), cpv(-15,0)));
cpConstraintSetMaxForce(breakableJoint, 4000);


// In your update function:
// Step your space normally...
cpFloat dt = 1.0/60.0;
cpSpaceStep(space, dt);

if(breakableJoint){
  // Convert the impulse to a force by dividing it by the timestep.
  cpFloat force = cpConstraintGetImpulse(breakableJoint)/dt;
  cpFloat maxForce = cpConstraintGetMaxForce(breakableJoint);

  // If the force is almost as big as the joint's max force, break it.
  if(force > 0.9*maxForce){
    cpSpaceRemoveConstraint(space, breakableJoint);
    breakableJoint = NULL;
  }
}
Chipmunk-6.1.5/doc/examples/CollisionCallback.html000644 000765 000000 00000005764 12151675775 023101 0ustar00slembckewheel000000 000000
static void
postStepRemove(cpSpace *space, cpShape *shape, void *unused)
{
  cpSpaceRemoveShape(space, shape);
  cpSpaceRemoveBody(space, shape->body);
  
  cpShapeFree(shape);
  cpBodyFree(shape->body);
}

static int
begin(cpArbiter *arb, cpSpace *space, void *unused)
{
  // Get the cpShapes involved in the collision
  // The order will be the same as you defined in the handler definition
  // a->collision_type will be BULLET_TYPE and b->collision_type will be MONSTER_TYPE
  CP_ARBITER_GET_SHAPES(arb, a, b);
  
  // The macro expands exactly as if you had typed this:
  // cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
  
  // Add a post step callback to safely remove the body and shape from the space.
  // Calling cpSpaceRemove*() directly from a collision handler callback can cause crashes.
  cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL);
  
  // The object is dead, don’t process the collision further
  return 0;
}

#define BULLET_TYPE 1
#define MONSTER_TYPE 2

// Define a collision handler for bullets and monsters
// Kill the monster by removing it’s shape and body from the space as soon as it’s hit by a bullet 
cpSpaceAddCollisionHandler(space, BULLET_TYPE, MONSTER_TYPE, begin, NULL, NULL, NULL, NULL);
Chipmunk-6.1.5/doc/examples/cpConvexHull.html000644 000765 000000 00000003700 12151675775 022127 0ustar00slembckewheel000000 000000
int first = 0;

// Create space to store the convex hull.
// An alloca(), or a variable length array would be a better, but not always portable choice.
cpVect *hullVerts = (cpVect *)calloc(vertCount, sizeof(cpVect));
int hullCount = cpConvexHull(vertCount, verts, hullVerts, &first, 0.0);

// hullVerts[0] will be equal to verts[first] here.
// If you don't care, pass NULL instead of the 'first' pointer.

cpBody *body = cpBodyNew(mass, cpMomentForPoly(mass, hullCount, hullVerts, cpvzero));
cpShape *shape = cpPolyShapeNew(body, hullCount, hullVerts, cpvzero);

free(hullVerts);

// *********
// Altenatively you can use the CP_CONVEX_HULL() macro to save yourself a little work

// The macro will declare the hullCount and hullVerts variables.
// hullVerts is allocated on the stack and does not need to be freed.
CP_CONVEX_HULL(count, verts, hullCount, hullVerts)

cpBody *body = cpBodyNew(mass, cpMomentForPoly(mass, hullCount, hullVerts, cpvzero));
cpShape *shape = cpPolyShapeNew(body, hullCount, hullVerts, cpvzero);
Chipmunk-6.1.5/doc/examples/cpSpaceEachBody.html000644 000765 000000 00000002270 12151675775 022473 0ustar00slembckewheel000000 000000
// Code snippet to check if all bodies in the space are sleeping

// This function is called once for each body in the space.
static void EachBody(cpBody *body, cpBool *allSleeping){
  if(!cpBodyIsSleeping(body)) *allSleeping = cpFalse;
}

// Then in your tick method, do this:
cpBool allSleeping = true;
cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)EachBody, &allSleeping);
printf("All are sleeping: %s\n", allSleeping ? "true" : "false");
Chipmunk-6.1.5/doc/examples/Hello Chipmunk.html000644 000765 000000 00000012473 12151675775 022326 0ustar00slembckewheel000000 000000
#include <stdio.h>
#include <chipmunk.h>

int main(void){
  // cpVect is a 2D vector and cpv() is a shortcut for initializing them.
  cpVect gravity = cpv(0, -100);
  
  // Create an empty space.
  cpSpace *space = cpSpaceNew();
  cpSpaceSetGravity(space, gravity);
  
  // Add a static line segment shape for the ground.
  // We'll make it slightly tilted so the ball will roll off.
  // We attach it to space->staticBody to tell Chipmunk it shouldn't be movable.
  cpShape *ground = cpSegmentShapeNew(space->staticBody, cpv(-20, 5), cpv(20, -5), 0);
  cpShapeSetFriction(ground, 1);
  cpSpaceAddShape(space, ground);
  
  // Now let's make a ball that falls onto the line and rolls off.
  // First we need to make a cpBody to hold the physical properties of the object.
  // These include the mass, position, velocity, angle, etc. of the object.
  // Then we attach collision shapes to the cpBody to give it a size and shape.
  
  cpFloat radius = 5;
  cpFloat mass = 1;
  
  // The moment of inertia is like mass for rotation
  // Use the cpMomentFor*() functions to help you approximate it.
  cpFloat moment = cpMomentForCircle(mass, 0, radius, cpvzero);
  
  // The cpSpaceAdd*() functions return the thing that you are adding.
  // It's convenient to create and add an object in one line.
  cpBody *ballBody = cpSpaceAddBody(space, cpBodyNew(mass, moment));
  cpBodySetPos(ballBody, cpv(0, 15));
  
  // Now we create the collision shape for the ball.
  // You can create multiple collision shapes that point to the same body.
  // They will all be attached to the body and move around to follow it.
  cpShape *ballShape = cpSpaceAddShape(space, cpCircleShapeNew(ballBody, radius, cpvzero));
  cpShapeSetFriction(ballShape, 0.7);
  
  // Now that it's all set up, we simulate all the objects in the space by
  // stepping forward through time in small increments called steps.
  // It is *highly* recommended to use a fixed size time step.
  cpFloat timeStep = 1.0/60.0;
  for(cpFloat time = 0; time < 2; time += timeStep){
    cpVect pos = cpBodyGetPos(ballBody);
    cpVect vel = cpBodyGetVel(ballBody);
    printf(
      "Time is %5.2f. ballBody is at (%5.2f, %5.2f). It's velocity is (%5.2f, %5.2f)\n",
      time, pos.x, pos.y, vel.x, vel.y
    );
    
    cpSpaceStep(space, timeStep);
  }
  
  // Clean up our objects and exit!
  cpShapeFree(ballShape);
  cpBodyFree(ballBody);
  cpShapeFree(ground);
  cpSpaceFree(space);
  
  return 0;
}
Chipmunk-6.1.5/doc/examples/JointRecipies.html000644 000765 000000 00000003563 12151675775 022273 0ustar00slembckewheel000000 000000
// Faked top down friction.

// A pivot joint configured this way will calculate friction against the ground for games with a top down perspective.
// Because the joint correction is disabled, the joint will not recenter itself and only apply to the velocity.
// The force the joint applies when changing the velocity will be clamped by the max force
// and this causes it to work exactly like friction!
cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, body, cpvzero, cpvzero));
pivot->maxBias = 0.0f; // disable joint correction
pivot->maxForce = 1000.0f;

// The pivot joint doesn't apply rotational forces, use a gear joint with a ratio of 1.0 for that.
cpConstraint *gear = cpSpaceAddConstraint(space, cpGearJointNew(staticBody, body, 0.0f, 1.0f));
gear->maxBias = 0.0f; // disable joint correction
gear->maxForce = 5000.0f;

// Also, instead of connecting the joints to a static body, you can connect them to an infinite mass rogue body.
// You can then use the rogue body as a control body to the connected body. See the Tank demo as an example.
Chipmunk-6.1.5/doc/examples/Moments.html000644 000765 000000 00000003555 12151675775 021147 0ustar00slembckewheel000000 000000
// Moment for a solid circle with a mass of 2 and radius 5.
cpFloat circle1 = cpMomentForCircle(2, 0, 5, cpvzero);

// Moment for a hollow circle with a mass of 1, inner radius of 2 and outer radius of 6.
cpFloat circle2 = cpMomentForCircle(1, 2, 6, cpvzero);

// Moment for a solid circle with a mass of 1, radius of 3 and
// centered 3 units along the x axis from the center of gravity.
cpFloat circle3 = cpMomentForCircle(2, 0, 5, cpv(3, 0));

// Composite object. 1x4 box centered on the center of gravity and a circle sitting on top.
// Just add the moments together.
cpFloat composite = cpMomentForBox(boxMass, 1, 4) + cpMomentForCircle(circleMass, 0, 1, cpv(0, 3));
Chipmunk-6.1.5/doc/examples/Sleeping.html000644 000765 000000 00000004016 12151675775 021264 0ustar00slembckewheel000000 000000
// Construct a pile of boxes.
// Force them to sleep until the first time they are touched.
// Group them together so that touching any box wakes all of them.
cpFloat size = 20;
cpFloat mass = 1;
cpFloat moment = cpMomentForBox(mass, size, size);

cpBody *lastBody = NULL;

for(int i=0; i<5; i++){
  cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, moment));
  cpBodySetPos(body, cpv(0, i*size));
  
  cpShape *shape = cpSpaceAddShape(space, cpBoxShapeNew(body, size, size));
  cpShapeSetFriction(shape, 0.7);
  
  // You can use any sleeping body as a group identifier.
  // Here we just keep a reference to the last body we initialized.
  // Passing NULL as the group starts a new sleeping group.
  // You MUST do this after completely initializing the object.
  // Attaching shapes or calling setter functions will wake the body back up.
  cpBodySleepWithGroup(body, lastBody);
  lastBody = body;
}
Chipmunk-6.1.5/Demo/Bench.c000644 000765 000000 00000064615 12151675775 016327 0ustar00slembckewheel000000 000000 #include "chipmunk.h" #include "ChipmunkDemo.h" #if 1 #define BENCH_SPACE_NEW cpSpaceNew #define BENCH_SPACE_FREE cpSpaceFree #define BENCH_SPACE_STEP cpSpaceStep #else #import "cpHastySpace.h" static cpSpace * MakeHastySpace() { cpSpace *space = cpHastySpaceNew(); cpHastySpaceSetThreads(space, 0); return space; } #define BENCH_SPACE_NEW MakeHastySpace #define BENCH_SPACE_FREE cpHastySpaceFree #define BENCH_SPACE_STEP cpHastySpaceStep #endif static cpVect simple_terrain_verts[] = { {350.00, 425.07}, {336.00, 436.55}, {272.00, 435.39}, {258.00, 427.63}, {225.28, 420.00}, {202.82, 396.00}, {191.81, 388.00}, {189.00, 381.89}, {173.00, 380.39}, {162.59, 368.00}, {150.47, 319.00}, {128.00, 311.55}, {119.14, 286.00}, {126.84, 263.00}, {120.56, 227.00}, {141.14, 178.00}, {137.52, 162.00}, {146.51, 142.00}, {156.23, 136.00}, {158.00, 118.27}, {170.00, 100.77}, {208.43, 84.00}, {224.00, 69.65}, {249.30, 68.00}, {257.00, 54.77}, {363.00, 45.94}, {374.15, 54.00}, {386.00, 69.60}, {413.00, 70.73}, {456.00, 84.89}, {468.09, 99.00}, {467.09, 123.00}, {464.92, 135.00}, {469.00, 141.03}, {497.00, 148.67}, {513.85, 180.00}, {509.56, 223.00}, {523.51, 247.00}, {523.00, 277.00}, {497.79, 311.00}, {478.67, 348.00}, {467.90, 360.00}, {456.76, 382.00}, {432.95, 389.00}, {417.00, 411.32}, {373.00, 433.19}, {361.00, 430.02}, {350.00, 425.07}, }; static int simple_terrain_count = sizeof(simple_terrain_verts)/sizeof(cpVect); static cpVect frand_unit_circle(){ cpVect v = cpv(frand()*2.0f - 1.0f, frand()*2.0f - 1.0f); return (cpvlengthsq(v) < 1.0f ? v : frand_unit_circle()); } //cpBody bodies[1000] = {}; //cpCircleShape circles[1000] = {}; static void add_circle(cpSpace *space, int index, cpFloat radius){ cpFloat mass = radius*radius/25.0f; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); // cpBody *body = cpSpaceAddBody(space, cpBodyInit(&bodies[i], mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); body->p = cpvmult(frand_unit_circle(), 180.0f); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero)); // cpShape *shape = cpSpaceAddShape(space, cpCircleShapeInit(&circles[i], body, radius, cpvzero)); shape->e = 0.0f; shape->u = 0.9f; } static void add_box(cpSpace *space, int index, cpFloat size){ cpFloat mass = size*size/100.0f; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForBox(mass, size, size))); // cpBody *body = cpSpaceAddBody(space, cpBodyInit(&bodies[i], mass, cpMomentForBox(mass, size, size))); body->p = cpvmult(frand_unit_circle(), 180.0f); cpShape *shape = cpSpaceAddShape(space, cpBoxShapeNew(body, size, size)); shape->e = 0.0f; shape->u = 0.9f; } static void add_hexagon(cpSpace *space, int index, cpFloat radius){ cpVect hexagon[6] = {}; for(int i=0; i<6; i++){ cpFloat angle = -M_PI*2.0f*i/6.0f; hexagon[i] = cpvmult(cpv(cos(angle), sin(angle)), radius); } cpFloat mass = radius*radius; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 6, hexagon, cpvzero))); body->p = cpvmult(frand_unit_circle(), 180.0f); cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 6, hexagon, cpvzero)); shape->e = 0.0f; shape->u = 0.9f; } static cpSpace * SetupSpace_simpleTerrain(){ cpSpace *space = BENCH_SPACE_NEW(); space->iterations = 10; space->gravity = cpv(0, -100); space->collisionSlop = 0.5f; cpVect offset = cpv(-320, -240); for(int i=0; i<(simple_terrain_count - 1); i++){ cpVect a = simple_terrain_verts[i], b = simple_terrain_verts[i+1]; cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpvadd(a, offset), cpvadd(b, offset), 0.0f)); } return space; } // SimpleTerrain constant sized objects static cpSpace *init_SimpleTerrainCircles_1000(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<1000; i++) add_circle(space, i, 5.0f); return space; } static cpSpace *init_SimpleTerrainCircles_500(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<500; i++) add_circle(space, i, 5.0f); return space; } static cpSpace *init_SimpleTerrainCircles_100(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<100; i++) add_circle(space, i, 5.0f); return space; } static cpSpace *init_SimpleTerrainBoxes_1000(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<1000; i++) add_box(space, i, 10.0f); return space; } static cpSpace *init_SimpleTerrainBoxes_500(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<500; i++) add_box(space, i, 10.0f); return space; } static cpSpace *init_SimpleTerrainBoxes_100(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<100; i++) add_box(space, i, 10.0f); return space; } static cpSpace *init_SimpleTerrainHexagons_1000(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<1000; i++) add_hexagon(space, i, 5.0f); return space; } static cpSpace *init_SimpleTerrainHexagons_500(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<500; i++) add_hexagon(space, i, 5.0f); return space; } static cpSpace *init_SimpleTerrainHexagons_100(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<100; i++) add_hexagon(space, i, 5.0f); return space; } // SimpleTerrain variable sized objects static cpFloat rand_size(){ return cpfpow(1.5, cpflerp(-1.5, 3.5, frand())); } static cpSpace *init_SimpleTerrainVCircles_200(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<200; i++) add_circle(space, i, 5.0f*rand_size()); return space; } static cpSpace *init_SimpleTerrainVBoxes_200(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<200; i++) add_box(space, i, 8.0f*rand_size()); return space; } static cpSpace *init_SimpleTerrainVHexagons_200(){ cpSpace *space = SetupSpace_simpleTerrain(); for(int i=0; i<200; i++) add_hexagon(space, i, 5.0f*rand_size()); return space; } // ComplexTerrain static cpVect complex_terrain_verts[] = { { 46.78, 479.00}, { 35.00, 475.63}, { 27.52, 469.00}, { 23.52, 455.00}, { 23.78, 441.00}, { 28.41, 428.00}, { 49.61, 394.00}, { 59.00, 381.56}, { 80.00, 366.03}, { 81.46, 358.00}, { 86.31, 350.00}, { 77.74, 320.00}, { 70.26, 278.00}, { 67.51, 270.00}, { 58.86, 260.00}, { 57.19, 247.00}, { 38.00, 235.60}, { 25.76, 221.00}, { 24.58, 209.00}, { 27.63, 202.00}, { 31.28, 198.00}, { 40.00, 193.72}, { 48.00, 193.73}, { 55.00, 196.70}, { 62.10, 204.00}, { 71.00, 209.04}, { 79.00, 206.55}, { 88.00, 206.81}, { 95.88, 211.00}, {103.00, 220.49}, {131.00, 220.51}, {137.00, 222.66}, {143.08, 228.00}, {146.22, 234.00}, {147.08, 241.00}, {145.45, 248.00}, {142.31, 253.00}, {132.00, 259.30}, {115.00, 259.70}, {109.28, 270.00}, {112.91, 296.00}, {119.69, 324.00}, {129.00, 336.26}, {141.00, 337.59}, {153.00, 331.57}, {175.00, 325.74}, {188.00, 325.19}, {235.00, 317.46}, {250.00, 317.19}, {255.00, 309.12}, {262.62, 302.00}, {262.21, 295.00}, {248.00, 273.59}, {229.00, 257.93}, {221.00, 255.48}, {215.00, 251.59}, {210.79, 246.00}, {207.47, 234.00}, {203.25, 227.00}, {179.00, 205.90}, {148.00, 189.54}, {136.00, 181.45}, {120.00, 180.31}, {110.00, 181.65}, { 95.00, 179.31}, { 63.00, 166.96}, { 50.00, 164.23}, { 31.00, 154.49}, { 19.76, 145.00}, { 15.96, 136.00}, { 16.65, 127.00}, { 20.57, 120.00}, { 28.00, 114.63}, { 40.00, 113.67}, { 65.00, 127.22}, { 73.00, 128.69}, { 81.96, 120.00}, { 77.58, 103.00}, { 78.18, 92.00}, { 59.11, 77.00}, { 52.00, 67.29}, { 31.29, 55.00}, { 25.67, 47.00}, { 24.65, 37.00}, { 27.82, 29.00}, { 35.00, 22.55}, { 44.00, 20.35}, { 49.00, 20.81}, { 61.00, 25.69}, { 79.00, 37.81}, { 88.00, 49.64}, { 97.00, 56.65}, {109.00, 49.61}, {143.00, 38.96}, {197.00, 37.27}, {215.00, 35.30}, {222.00, 36.65}, {228.42, 41.00}, {233.30, 49.00}, {234.14, 57.00}, {231.00, 65.80}, {224.00, 72.38}, {218.00, 74.50}, {197.00, 76.62}, {145.00, 78.81}, {123.00, 87.41}, {117.59, 98.00}, {117.79, 104.00}, {119.00, 106.23}, {138.73, 120.00}, {148.00, 129.50}, {158.50, 149.00}, {203.93, 175.00}, {229.00, 196.60}, {238.16, 208.00}, {245.20, 221.00}, {275.45, 245.00}, {289.00, 263.24}, {303.60, 287.00}, {312.00, 291.57}, {339.25, 266.00}, {366.33, 226.00}, {363.43, 216.00}, {364.13, 206.00}, {353.00, 196.72}, {324.00, 181.05}, {307.00, 169.63}, {274.93, 156.00}, {256.00, 152.48}, {228.00, 145.13}, {221.09, 142.00}, {214.87, 135.00}, {212.67, 127.00}, {213.81, 119.00}, {219.32, 111.00}, {228.00, 106.52}, {236.00, 106.39}, {290.00, 119.40}, {299.33, 114.00}, {300.52, 109.00}, {300.30, 53.00}, {301.46, 47.00}, {305.00, 41.12}, {311.00, 36.37}, {317.00, 34.43}, {325.00, 34.81}, {334.90, 41.00}, {339.45, 50.00}, {339.82, 132.00}, {346.09, 139.00}, {350.00, 150.26}, {380.00, 167.38}, {393.00, 166.48}, {407.00, 155.54}, {430.00, 147.30}, {437.78, 135.00}, {433.13, 122.00}, {410.23, 78.00}, {401.59, 69.00}, {393.48, 56.00}, {392.80, 44.00}, {395.50, 38.00}, {401.00, 32.49}, {409.00, 29.41}, {420.00, 30.84}, {426.92, 36.00}, {432.32, 44.00}, {439.49, 51.00}, {470.13, 108.00}, {475.71, 124.00}, {483.00, 130.11}, {488.00, 139.43}, {529.00, 139.40}, {536.00, 132.52}, {543.73, 129.00}, {540.47, 115.00}, {541.11, 100.00}, {552.18, 68.00}, {553.78, 47.00}, {559.00, 39.76}, {567.00, 35.52}, {577.00, 35.45}, {585.00, 39.58}, {591.38, 50.00}, {591.67, 66.00}, {590.31, 79.00}, {579.76, 109.00}, {582.25, 119.00}, {583.66, 136.00}, {586.45, 143.00}, {586.44, 151.00}, {580.42, 168.00}, {577.15, 173.00}, {572.00, 177.13}, {564.00, 179.49}, {478.00, 178.81}, {443.00, 184.76}, {427.10, 190.00}, {424.00, 192.11}, {415.94, 209.00}, {408.82, 228.00}, {405.82, 241.00}, {411.00, 250.82}, {415.00, 251.50}, {428.00, 248.89}, {469.00, 246.29}, {505.00, 246.49}, {533.00, 243.60}, {541.87, 248.00}, {547.55, 256.00}, {548.48, 267.00}, {544.00, 276.00}, {534.00, 282.24}, {513.00, 285.46}, {468.00, 285.76}, {402.00, 291.70}, {392.00, 290.29}, {377.00, 294.46}, {367.00, 294.43}, {356.44, 304.00}, {354.22, 311.00}, {362.00, 321.36}, {390.00, 322.44}, {433.00, 330.16}, {467.00, 332.76}, {508.00, 347.64}, {522.00, 357.67}, {528.00, 354.46}, {536.00, 352.96}, {546.06, 336.00}, {553.47, 306.00}, {564.19, 282.00}, {567.84, 268.00}, {578.72, 246.00}, {585.00, 240.97}, {592.00, 238.91}, {600.00, 239.72}, {606.00, 242.82}, {612.36, 251.00}, {613.35, 263.00}, {588.75, 324.00}, {583.25, 350.00}, {572.12, 370.00}, {575.45, 378.00}, {575.20, 388.00}, {589.00, 393.81}, {599.20, 404.00}, {607.14, 416.00}, {609.96, 430.00}, {615.45, 441.00}, {613.44, 462.00}, {610.48, 469.00}, {603.00, 475.63}, {590.96, 479.00}, }; static int complex_terrain_count = sizeof(complex_terrain_verts)/sizeof(cpVect); static cpSpace *init_ComplexTerrainCircles_1000(){ cpSpace *space = BENCH_SPACE_NEW(); space->iterations = 10; space->gravity = cpv(0, -100); space->collisionSlop = 0.5f; cpVect offset = cpv(-320, -240); for(int i=0; i<(complex_terrain_count - 1); i++){ cpVect a = complex_terrain_verts[i], b = complex_terrain_verts[i+1]; cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpvadd(a, offset), cpvadd(b, offset), 0.0f)); } for(int i=0; i<1000; i++){ cpFloat radius = 5.0f; cpFloat mass = radius*radius; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); body->p = cpvadd(cpvmult(frand_unit_circle(), 180.0f), cpv(0.0f, 300.0f)); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero)); shape->e = 0.0f; shape->u = 0.0f; } return space; } static cpSpace *init_ComplexTerrainHexagons_1000(){ cpSpace *space = BENCH_SPACE_NEW(); space->iterations = 10; space->gravity = cpv(0, -100); space->collisionSlop = 0.5f; cpVect offset = cpv(-320, -240); for(int i=0; i<(complex_terrain_count - 1); i++){ cpVect a = complex_terrain_verts[i], b = complex_terrain_verts[i+1]; cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpvadd(a, offset), cpvadd(b, offset), 0.0f)); } cpFloat radius = 5.0f; cpVect hexagon[6] = {}; for(int i=0; i<6; i++){ cpFloat angle = -M_PI*2.0f*i/6.0f; hexagon[i] = cpvmult(cpv(cos(angle), sin(angle)), radius); } for(int i=0; i<1000; i++){ cpFloat mass = radius*radius; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 6, hexagon, cpvzero))); body->p = cpvadd(cpvmult(frand_unit_circle(), 180.0f), cpv(0.0f, 300.0f)); cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 6, hexagon, cpvzero)); shape->e = 0.0f; shape->u = 0.0f; } return space; } // BouncyTerrain static cpVect bouncy_terrain_verts[] = { {537.18, 23.00}, {520.50, 36.00}, {501.53, 63.00}, {496.14, 76.00}, {498.86, 86.00}, {504.00, 90.51}, {508.00, 91.36}, {508.77, 84.00}, {513.00, 77.73}, {519.00, 74.48}, {530.00, 74.67}, {545.00, 54.65}, {554.00, 48.77}, {562.00, 46.39}, {568.00, 45.94}, {568.61, 47.00}, {567.94, 55.00}, {571.27, 64.00}, {572.92, 80.00}, {572.00, 81.39}, {563.00, 79.93}, {556.00, 82.69}, {551.49, 88.00}, {549.00, 95.76}, {538.00, 93.40}, {530.00, 102.38}, {523.00, 104.00}, {517.00, 103.02}, {516.22, 109.00}, {518.96, 116.00}, {526.00, 121.15}, {534.00, 116.48}, {543.00, 116.77}, {549.28, 121.00}, {554.00, 130.17}, {564.00, 125.67}, {575.60, 129.00}, {573.31, 121.00}, {567.77, 111.00}, {575.00, 106.47}, {578.51, 102.00}, {580.25, 95.00}, {577.98, 87.00}, {582.00, 85.71}, {597.00, 89.46}, {604.80, 95.00}, {609.28, 104.00}, {610.55, 116.00}, {609.30, 125.00}, {600.80, 142.00}, {597.31, 155.00}, {584.00, 167.23}, {577.86, 175.00}, {583.52, 184.00}, {582.64, 195.00}, {591.00, 196.56}, {597.81, 201.00}, {607.45, 219.00}, {607.51, 246.00}, {600.00, 275.46}, {588.00, 267.81}, {579.00, 264.91}, {557.00, 264.41}, {552.98, 259.00}, {548.00, 246.18}, {558.00, 247.12}, {565.98, 244.00}, {571.10, 237.00}, {571.61, 229.00}, {568.25, 222.00}, {562.00, 217.67}, {544.00, 213.93}, {536.73, 214.00}, {535.60, 204.00}, {539.69, 181.00}, {542.84, 171.00}, {550.43, 161.00}, {540.00, 156.27}, {536.62, 152.00}, {534.70, 146.00}, {527.00, 141.88}, {518.59, 152.00}, {514.51, 160.00}, {510.33, 175.00}, {519.38, 183.00}, {520.52, 194.00}, {516.00, 201.27}, {505.25, 206.00}, {507.57, 223.00}, {519.90, 260.00}, {529.00, 260.48}, {534.00, 262.94}, {538.38, 268.00}, {540.00, 275.00}, {537.06, 284.00}, {530.00, 289.23}, {520.00, 289.23}, {513.00, 284.18}, {509.71, 286.00}, {501.69, 298.00}, {501.56, 305.00}, {504.30, 311.00}, {512.00, 316.43}, {521.00, 316.42}, {525.67, 314.00}, {535.00, 304.98}, {562.00, 294.80}, {573.00, 294.81}, {587.52, 304.00}, {600.89, 310.00}, {596.96, 322.00}, {603.28, 327.00}, {606.52, 333.00}, {605.38, 344.00}, {597.65, 352.00}, {606.36, 375.00}, {607.16, 384.00}, {603.40, 393.00}, {597.00, 398.14}, {577.00, 386.15}, {564.35, 373.00}, {565.21, 364.00}, {562.81, 350.00}, {553.00, 346.06}, {547.48, 338.00}, {547.48, 330.00}, {550.00, 323.30}, {544.00, 321.53}, {537.00, 322.70}, {532.00, 326.23}, {528.89, 331.00}, {527.83, 338.00}, {533.02, 356.00}, {542.00, 360.73}, {546.68, 369.00}, {545.38, 379.00}, {537.58, 386.00}, {537.63, 388.00}, {555.00, 407.47}, {563.00, 413.52}, {572.57, 418.00}, {582.72, 426.00}, {578.00, 431.12}, {563.21, 440.00}, {558.00, 449.27}, {549.00, 452.94}, {541.00, 451.38}, {536.73, 448.00}, {533.00, 441.87}, {520.00, 437.96}, {514.00, 429.69}, {490.00, 415.15}, {472.89, 399.00}, {472.03, 398.00}, {474.00, 396.71}, {486.00, 393.61}, {492.00, 385.85}, {492.00, 376.15}, {489.04, 371.00}, {485.00, 368.11}, {480.00, 376.27}, {472.00, 379.82}, {463.00, 378.38}, {455.08, 372.00}, {446.00, 377.69}, {439.00, 385.24}, {436.61, 391.00}, {437.52, 404.00}, {440.00, 409.53}, {463.53, 433.00}, {473.80, 441.00}, {455.00, 440.30}, {443.00, 436.18}, {436.00, 431.98}, {412.00, 440.92}, {397.00, 442.46}, {393.59, 431.00}, {393.71, 412.00}, {400.00, 395.10}, {407.32, 387.00}, {408.54, 380.00}, {407.42, 375.00}, {403.97, 370.00}, {399.00, 366.74}, {393.00, 365.68}, {391.23, 374.00}, {387.00, 380.27}, {381.00, 383.52}, {371.56, 384.00}, {364.98, 401.00}, {362.96, 412.00}, {363.63, 435.00}, {345.00, 433.55}, {344.52, 442.00}, {342.06, 447.00}, {337.00, 451.38}, {330.00, 453.00}, {325.00, 452.23}, {318.00, 448.17}, {298.00, 453.70}, {284.00, 451.49}, {278.62, 449.00}, {291.47, 408.00}, {291.77, 398.00}, {301.00, 393.83}, {305.00, 393.84}, {305.60, 403.00}, {310.00, 409.47}, {318.00, 413.07}, {325.00, 412.40}, {332.31, 407.00}, {335.07, 400.00}, {334.40, 393.00}, {329.00, 385.69}, {319.00, 382.79}, {301.00, 389.23}, {289.00, 389.97}, {265.00, 389.82}, {251.00, 385.85}, {245.00, 389.23}, {239.00, 389.94}, {233.00, 388.38}, {226.00, 382.04}, {206.00, 374.75}, {206.00, 394.00}, {204.27, 402.00}, {197.00, 401.79}, {191.00, 403.49}, {186.53, 407.00}, {183.60, 412.00}, {183.60, 422.00}, {189.00, 429.31}, {196.00, 432.07}, {203.00, 431.40}, {209.47, 427.00}, {213.00, 419.72}, {220.00, 420.21}, {227.00, 418.32}, {242.00, 408.41}, {258.98, 409.00}, {250.00, 435.43}, {239.00, 438.78}, {223.00, 448.19}, {209.00, 449.70}, {205.28, 456.00}, {199.00, 460.23}, {190.00, 460.52}, {182.73, 456.00}, {178.00, 446.27}, {160.00, 441.42}, {148.35, 435.00}, {149.79, 418.00}, {157.72, 401.00}, {161.00, 396.53}, {177.00, 385.00}, {180.14, 380.00}, {181.11, 374.00}, {180.00, 370.52}, {170.00, 371.68}, {162.72, 368.00}, {158.48, 361.00}, {159.56, 349.00}, {154.00, 342.53}, {146.00, 339.85}, {136.09, 343.00}, {130.64, 351.00}, {131.74, 362.00}, {140.61, 374.00}, {130.68, 387.00}, {120.75, 409.00}, {118.09, 421.00}, {117.92, 434.00}, {100.00, 432.40}, { 87.00, 427.48}, { 81.59, 423.00}, { 73.64, 409.00}, { 72.57, 398.00}, { 74.62, 386.00}, { 78.80, 378.00}, { 88.00, 373.43}, { 92.49, 367.00}, { 93.32, 360.00}, { 91.30, 353.00}, {103.00, 342.67}, {109.00, 343.10}, {116.00, 340.44}, {127.33, 330.00}, {143.00, 327.24}, {154.30, 322.00}, {145.00, 318.06}, {139.77, 311.00}, {139.48, 302.00}, {144.95, 293.00}, {143.00, 291.56}, {134.00, 298.21}, {118.00, 300.75}, {109.40, 305.00}, { 94.67, 319.00}, { 88.00, 318.93}, { 81.00, 321.69}, { 67.24, 333.00}, { 56.68, 345.00}, { 53.00, 351.40}, { 47.34, 333.00}, { 50.71, 314.00}, { 56.57, 302.00}, { 68.00, 287.96}, { 91.00, 287.24}, {110.00, 282.36}, {133.80, 271.00}, {147.34, 256.00}, {156.47, 251.00}, {157.26, 250.00}, {154.18, 242.00}, {154.48, 236.00}, {158.72, 229.00}, {166.71, 224.00}, {170.15, 206.00}, {170.19, 196.00}, {167.24, 188.00}, {160.00, 182.67}, {150.00, 182.66}, {143.60, 187.00}, {139.96, 195.00}, {139.50, 207.00}, {136.45, 221.00}, {136.52, 232.00}, {133.28, 238.00}, {129.00, 241.38}, {119.00, 243.07}, {115.00, 246.55}, {101.00, 253.16}, { 86.00, 257.32}, { 63.00, 259.24}, { 57.00, 257.31}, { 50.54, 252.00}, { 47.59, 247.00}, { 46.30, 240.00}, { 47.58, 226.00}, { 50.00, 220.57}, { 58.00, 226.41}, { 69.00, 229.17}, { 79.00, 229.08}, { 94.50, 225.00}, {100.21, 231.00}, {107.00, 233.47}, {107.48, 224.00}, {109.94, 219.00}, {115.00, 214.62}, {122.57, 212.00}, {116.00, 201.49}, {104.00, 194.57}, { 90.00, 194.04}, { 79.00, 198.21}, { 73.00, 198.87}, { 62.68, 191.00}, { 62.58, 184.00}, { 64.42, 179.00}, { 75.00, 167.70}, { 80.39, 157.00}, { 68.79, 140.00}, { 61.67, 126.00}, { 61.47, 117.00}, { 64.43, 109.00}, { 63.10, 96.00}, { 56.48, 82.00}, { 48.00, 73.88}, { 43.81, 66.00}, { 43.81, 56.00}, { 50.11, 46.00}, { 59.00, 41.55}, { 71.00, 42.64}, { 78.00, 36.77}, { 83.00, 34.75}, { 99.00, 34.32}, {117.00, 38.92}, {133.00, 55.15}, {142.00, 50.70}, {149.74, 51.00}, {143.55, 68.00}, {153.28, 74.00}, {156.23, 79.00}, {157.00, 84.00}, {156.23, 89.00}, {153.28, 94.00}, {144.58, 99.00}, {151.52, 112.00}, {151.51, 124.00}, {150.00, 126.36}, {133.00, 130.25}, {126.71, 125.00}, {122.00, 117.25}, {114.00, 116.23}, {107.73, 112.00}, {104.48, 106.00}, {104.32, 99.00}, {106.94, 93.00}, {111.24, 89.00}, {111.60, 85.00}, {107.24, 73.00}, {102.00, 67.57}, { 99.79, 67.00}, { 99.23, 76.00}, { 95.00, 82.27}, { 89.00, 85.52}, { 79.84, 86.00}, { 86.73, 114.00}, { 98.00, 136.73}, { 99.00, 137.61}, {109.00, 135.06}, {117.00, 137.94}, {122.52, 146.00}, {122.94, 151.00}, {121.00, 158.58}, {134.00, 160.97}, {153.00, 157.45}, {171.30, 150.00}, {169.06, 142.00}, {169.77, 136.00}, {174.00, 129.73}, {181.46, 126.00}, {182.22, 120.00}, {182.20, 111.00}, {180.06, 101.00}, {171.28, 85.00}, {171.75, 80.00}, {182.30, 53.00}, {189.47, 50.00}, {190.62, 38.00}, {194.00, 33.73}, {199.00, 30.77}, {208.00, 30.48}, {216.00, 34.94}, {224.00, 31.47}, {240.00, 30.37}, {247.00, 32.51}, {249.77, 35.00}, {234.75, 53.00}, {213.81, 93.00}, {212.08, 99.00}, {213.00, 101.77}, {220.00, 96.77}, {229.00, 96.48}, {236.28, 101.00}, {240.00, 107.96}, {245.08, 101.00}, {263.00, 65.32}, {277.47, 48.00}, {284.00, 47.03}, {286.94, 41.00}, {292.00, 36.62}, {298.00, 35.06}, {304.00, 35.77}, {314.00, 43.81}, {342.00, 32.56}, {359.00, 31.32}, {365.00, 32.57}, {371.00, 36.38}, {379.53, 48.00}, {379.70, 51.00}, {356.00, 52.19}, {347.00, 54.74}, {344.38, 66.00}, {341.00, 70.27}, {335.00, 73.52}, {324.00, 72.38}, {317.00, 65.75}, {313.00, 67.79}, {307.57, 76.00}, {315.00, 78.62}, {319.28, 82.00}, {322.23, 87.00}, {323.00, 94.41}, {334.00, 92.49}, {347.00, 87.47}, {349.62, 80.00}, {353.00, 75.73}, {359.00, 72.48}, {366.00, 72.32}, {372.00, 74.94}, {377.00, 81.34}, {382.00, 83.41}, {392.00, 83.40}, {399.00, 79.15}, {404.00, 85.74}, {411.00, 85.06}, {417.00, 86.62}, {423.38, 93.00}, {425.05, 104.00}, {438.00, 110.35}, {450.00, 112.17}, {452.62, 103.00}, {456.00, 98.73}, {462.00, 95.48}, {472.00, 95.79}, {471.28, 92.00}, {464.00, 84.62}, {445.00, 80.39}, {436.00, 75.33}, {428.00, 68.46}, {419.00, 68.52}, {413.00, 65.27}, {408.48, 58.00}, {409.87, 46.00}, {404.42, 39.00}, {408.00, 33.88}, {415.00, 29.31}, {429.00, 26.45}, {455.00, 28.77}, {470.00, 33.81}, {482.00, 42.16}, {494.00, 46.85}, {499.65, 36.00}, {513.00, 25.95}, {529.00, 22.42}, {537.18, 23.00}, }; static int bouncy_terrain_count = sizeof(bouncy_terrain_verts)/sizeof(cpVect); static cpSpace *init_BouncyTerrainCircles_500(){ cpSpace *space = BENCH_SPACE_NEW(); space->iterations = 10; cpVect offset = cpv(-320, -240); for(int i=0; i<(bouncy_terrain_count - 1); i++){ cpVect a = bouncy_terrain_verts[i], b = bouncy_terrain_verts[i+1]; cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpvadd(a, offset), cpvadd(b, offset), 0.0f)); shape->e = 1.0f; } for(int i=0; i<500; i++){ cpFloat radius = 5.0f; cpFloat mass = radius*radius; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); body->p = cpvadd(cpvmult(frand_unit_circle(), 130.0f), cpvzero); body->v = cpvmult(frand_unit_circle(), 50.0f); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero)); shape->e = 1.0f; } return space; } static cpSpace *init_BouncyTerrainHexagons_500(){ cpSpace *space = BENCH_SPACE_NEW(); space->iterations = 10; cpVect offset = cpv(-320, -240); for(int i=0; i<(bouncy_terrain_count - 1); i++){ cpVect a = bouncy_terrain_verts[i], b = bouncy_terrain_verts[i+1]; cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpvadd(a, offset), cpvadd(b, offset), 0.0f)); shape->e = 1.0f; } cpFloat radius = 5.0f; cpVect hexagon[6] = {}; for(int i=0; i<6; i++){ cpFloat angle = -M_PI*2.0f*i/6.0f; hexagon[i] = cpvmult(cpv(cos(angle), sin(angle)), radius); } for(int i=0; i<500; i++){ cpFloat mass = radius*radius; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 6, hexagon, cpvzero))); body->p = cpvadd(cpvmult(frand_unit_circle(), 130.0f), cpvzero); body->v = cpvmult(frand_unit_circle(), 50.0f); cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 6, hexagon, cpvzero)); shape->e = 1.0f; } return space; } // No collisions static cpBool NoCollide_begin(cpArbiter *arb, cpSpace *space, void *data){ abort(); return cpTrue; } static cpSpace *init_NoCollide(){ cpSpace *space = BENCH_SPACE_NEW(); space->iterations = 10; cpSpaceAddCollisionHandler(space, 2, 2, NoCollide_begin, NULL, NULL, NULL, NULL); float radius = 4.5f; cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpv(-330-radius, -250-radius), cpv( 330+radius, -250-radius), 0.0f))->e = 1.0f; cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpv( 330+radius, 250+radius), cpv( 330+radius, -250-radius), 0.0f))->e = 1.0f; cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpv( 330+radius, 250+radius), cpv(-330-radius, 250+radius), 0.0f))->e = 1.0f; cpSpaceAddShape(space, cpSegmentShapeNew(space->staticBody, cpv(-330-radius, -250-radius), cpv(-330-radius, 250+radius), 0.0f))->e = 1.0f; for(int x=-320; x<=320; x+=20){ for(int y=-240; y<=240; y+=20){ cpSpaceAddShape(space, cpCircleShapeNew(space->staticBody, radius, cpv(x, y))); } } for(int y=10-240; y<=240; y+=40){ cpFloat mass = 7.0f; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); body->p = cpv(-320.0f, y); body->v = cpv(100.0f, 0.0f); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero)); shape->e = 1.0f; shape->collision_type = 2; } for(int x=30-320; x<=320; x+=40){ cpFloat mass = 7.0f; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); body->p = cpv(x, -240.0f); body->v = cpv(0.0f, 100.0f); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero)); shape->e = 1.0f; shape->collision_type = 2; } return space; } // TODO ideas: // addition/removal // Memory usage? (too small to matter?) // http://forums.tigsource.com/index.php?topic=18077.msg518578#msg518578 // Build benchmark list static void update(cpSpace *space){ BENCH_SPACE_STEP(space, 1.0f/60.0f); } static void destroy(cpSpace *space){ ChipmunkDemoFreeSpaceChildren(space); BENCH_SPACE_FREE(space); } // Make a second demo declaration for this demo to use in the regular demo set. ChipmunkDemo BouncyHexagons = { "Bouncy Hexagons", init_BouncyTerrainHexagons_500, update, ChipmunkDemoDefaultDrawImpl, destroy, }; #define BENCH(n) {"benchmark - " #n, init_##n, update, ChipmunkDemoDefaultDrawImpl, destroy} ChipmunkDemo bench_list[] = { BENCH(SimpleTerrainCircles_1000), BENCH(SimpleTerrainCircles_500), BENCH(SimpleTerrainCircles_100), BENCH(SimpleTerrainBoxes_1000), BENCH(SimpleTerrainBoxes_500), BENCH(SimpleTerrainBoxes_100), BENCH(SimpleTerrainHexagons_1000), BENCH(SimpleTerrainHexagons_500), BENCH(SimpleTerrainHexagons_100), BENCH(SimpleTerrainVCircles_200), BENCH(SimpleTerrainVBoxes_200), BENCH(SimpleTerrainVHexagons_200), BENCH(ComplexTerrainCircles_1000), BENCH(ComplexTerrainHexagons_1000), BENCH(BouncyTerrainCircles_500), BENCH(BouncyTerrainHexagons_500), BENCH(NoCollide), }; int bench_count = sizeof(bench_list)/sizeof(ChipmunkDemo); Chipmunk-6.1.5/Demo/Buoyancy.c000644 000765 000000 00000016227 12151675775 017075 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk.h" #include "constraints/util.h" #include "ChipmunkDemo.h" static void update(cpSpace *space) { int steps = 3; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; iv, cpvmult(cpvperp(r), body->w)); cpFloat k = k_scalar_body(body, r, cpvnormalize_safe(v_centroid)); cpFloat damping = clippedArea*FLUID_DRAG*FLUID_DENSITY; cpFloat v_coef = cpfexp(-damping*dt*k); // linear drag // cpFloat v_coef = 1.0/(1.0 + damping*dt*cpvlength(v_centroid)*k); // quadratic drag apply_impulse(body, cpvmult(cpvsub(cpvmult(v_centroid, v_coef), v_centroid), 1.0/k), r); // Apply angular damping for the fluid drag. cpFloat w_damping = cpMomentForPoly(FLUID_DRAG*FLUID_DENSITY*clippedArea, clippedCount, clipped, cpvneg(body->p)); body->w *= cpfexp(-w_damping*dt*body->i_inv); return cpTrue; } static cpSpace * init(void) { ChipmunkDemoMessageString = messageBuffer; cpSpace *space = cpSpaceNew(); cpSpaceSetIterations(space, 30); cpSpaceSetGravity(space, cpv(0, -500)); // cpSpaceSetDamping(space, 0.5); cpSpaceSetSleepTimeThreshold(space, 0.5f); cpSpaceSetCollisionSlop(space, 0.5f); cpBody *body, *staticBody = cpSpaceGetStaticBody(space); cpShape *shape; // Create segments around the edge of the screen. shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); { // Add the edges of the bucket cpBB bb = cpBBNew(-300, -200, 100, 0); cpFloat radius = 5.0f; shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(bb.l, bb.b), cpv(bb.l, bb.t), radius)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(bb.r, bb.b), cpv(bb.r, bb.t), radius)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(bb.l, bb.b), cpv(bb.r, bb.b), radius)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); // Add the sensor for the water. shape = cpSpaceAddShape(space, cpBoxShapeNew2(staticBody, bb)); cpShapeSetSensor(shape, cpTrue); cpShapeSetCollisionType(shape, 1); } { cpFloat width = 200.0f; cpFloat height = 50.0f; cpFloat mass = 0.3*FLUID_DENSITY*width*height; cpFloat moment = cpMomentForBox(mass, width, height); body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); cpBodySetPos(body, cpv(-50, -100)); cpBodySetVel(body, cpv(0, -100)); cpBodySetAngVel(body, 1); shape = cpSpaceAddShape(space, cpBoxShapeNew(body, width, height)); cpShapeSetFriction(shape, 0.8f); } { cpFloat width = 40.0f; cpFloat height = width*2; cpFloat mass = 0.3*FLUID_DENSITY*width*height; cpFloat moment = cpMomentForBox(mass, width, height); body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); cpBodySetPos(body, cpv(-200, -50)); cpBodySetVel(body, cpv(0, -100)); cpBodySetAngVel(body, 1); shape = cpSpaceAddShape(space, cpBoxShapeNew(body, width, height)); cpShapeSetFriction(shape, 0.8f); } cpSpaceAddCollisionHandler(space, 1, 0, NULL, (cpCollisionPreSolveFunc)waterPreSolve, NULL, NULL, NULL); return space; } static void destroy(cpSpace *space) { ChipmunkDemoFreeSpaceChildren(space); cpSpaceFree(space); } ChipmunkDemo Buoyancy = { "Simple Sensor based fluids.", init, update, ChipmunkDemoDefaultDrawImpl, destroy, }; Chipmunk-6.1.5/Demo/Chains.c000644 000765 000000 00000011355 12151675775 016506 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk.h" #include "ChipmunkDemo.h" #define CHAIN_COUNT 8 #define LINK_COUNT 10 static void BreakablejointPostStepRemove(cpSpace *space, cpConstraint *joint, void *unused) { cpSpaceRemoveConstraint(space, joint); cpConstraintFree(joint); } static void BreakableJointPostSolve(cpConstraint *joint, cpSpace *space) { cpFloat dt = cpSpaceGetCurrentTimeStep(space); // Convert the impulse to a force by dividing it by the timestep. cpFloat force = cpConstraintGetImpulse(joint)/dt; cpFloat maxForce = cpConstraintGetMaxForce(joint); // If the force is almost as big as the joint's max force, break it. if(force > 0.9*maxForce){ cpSpaceAddPostStepCallback(space, (cpPostStepFunc)BreakablejointPostStepRemove, joint, NULL); } } static void update(cpSpace *space) { int steps = 3; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; i #include #ifdef __APPLE__ #include "OpenGL/gl.h" #include "OpenGL/glu.h" #include #else #ifdef WIN32 #include #endif #include #include #include #endif #include "chipmunk_private.h" #include "ChipmunkDebugDraw.h" /* IMPORTANT - READ ME! This file sets up a simple interface that the individual demos can use to get a Chipmunk space running and draw what's in it. In order to keep the Chipmunk examples clean and simple, they contain no graphics code. All drawing is done by accessing the Chipmunk structures at a very low level. It is NOT recommended to write a game or application this way as it does not scale beyond simple shape drawing and is very dependent on implementation details about Chipmunk which may change with little to no warning. */ const Color LINE_COLOR = {200.0/255.0, 210.0/255.0, 230.0/255.0, 1.0}; const Color CONSTRAINT_COLOR = {0.0, 0.75, 0.0, 1.0}; const float SHAPE_ALPHA = 1.0; float ChipmunkDebugDrawPointLineScale = 1.0; static Color ColorFromHash(cpHashValue hash, float alpha) { unsigned long val = (unsigned long)hash; // scramble the bits up using Robert Jenkins' 32 bit integer hash function val = (val+0x7ed55d16) + (val<<12); val = (val^0xc761c23c) ^ (val>>19); val = (val+0x165667b1) + (val<<5); val = (val+0xd3a2646c) ^ (val<<9); val = (val+0xfd7046c5) + (val<<3); val = (val^0xb55a4f09) ^ (val>>16); GLfloat r = (val>>0) & 0xFF; GLfloat g = (val>>8) & 0xFF; GLfloat b = (val>>16) & 0xFF; GLfloat max = cpfmax(cpfmax(r, g), b); GLfloat min = cpfmin(cpfmin(r, g), b); GLfloat intensity = 0.75; // Saturate and scale the color if(min == max){ return RGBAColor(intensity, 0.0, 0.0, alpha); } else { GLfloat coef = alpha*intensity/(max - min); return RGBAColor( (r - min)*coef, (g - min)*coef, (b - min)*coef, alpha ); } } static inline void glColor_from_color(Color color){ glColor4fv((GLfloat *)&color); } static Color ColorForShape(cpShape *shape) { if(cpShapeGetSensor(shape)){ return LAColor(1, 0); } else { cpBody *body = shape->body; if(cpBodyIsSleeping(body)){ return LAColor(0.2, 1); } else if(body->node.idleTime > shape->space->sleepTimeThreshold) { return LAColor(0.66, 1); } else { return ColorFromHash(shape->hashid, SHAPE_ALPHA); } } } static const GLfloat circleVAR[] = { 0.0000f, 1.0000f, 0.2588f, 0.9659f, 0.5000f, 0.8660f, 0.7071f, 0.7071f, 0.8660f, 0.5000f, 0.9659f, 0.2588f, 1.0000f, 0.0000f, 0.9659f, -0.2588f, 0.8660f, -0.5000f, 0.7071f, -0.7071f, 0.5000f, -0.8660f, 0.2588f, -0.9659f, 0.0000f, -1.0000f, -0.2588f, -0.9659f, -0.5000f, -0.8660f, -0.7071f, -0.7071f, -0.8660f, -0.5000f, -0.9659f, -0.2588f, -1.0000f, -0.0000f, -0.9659f, 0.2588f, -0.8660f, 0.5000f, -0.7071f, 0.7071f, -0.5000f, 0.8660f, -0.2588f, 0.9659f, 0.0000f, 1.0000f, 0.0f, 0.0f, // For an extra line to see the rotation. }; static const int circleVAR_count = sizeof(circleVAR)/sizeof(GLfloat)/2; void ChipmunkDebugDrawCircle(cpVect center, cpFloat angle, cpFloat radius, Color lineColor, Color fillColor) { glVertexPointer(2, GL_FLOAT, 0, circleVAR); glPushMatrix(); { glTranslatef(center.x, center.y, 0.0f); glRotatef(angle*180.0f/M_PI, 0.0f, 0.0f, 1.0f); glScalef(radius, radius, 1.0f); if(fillColor.a > 0){ glColor_from_color(fillColor); glDrawArrays(GL_TRIANGLE_FAN, 0, circleVAR_count - 1); } if(lineColor.a > 0){ glColor_from_color(lineColor); glDrawArrays(GL_LINE_STRIP, 0, circleVAR_count); } } glPopMatrix(); } static const GLfloat pillVAR[] = { 0.0000f, 1.0000f, 1.0f, 0.2588f, 0.9659f, 1.0f, 0.5000f, 0.8660f, 1.0f, 0.7071f, 0.7071f, 1.0f, 0.8660f, 0.5000f, 1.0f, 0.9659f, 0.2588f, 1.0f, 1.0000f, 0.0000f, 1.0f, 0.9659f, -0.2588f, 1.0f, 0.8660f, -0.5000f, 1.0f, 0.7071f, -0.7071f, 1.0f, 0.5000f, -0.8660f, 1.0f, 0.2588f, -0.9659f, 1.0f, 0.0000f, -1.0000f, 1.0f, 0.0000f, -1.0000f, 0.0f, -0.2588f, -0.9659f, 0.0f, -0.5000f, -0.8660f, 0.0f, -0.7071f, -0.7071f, 0.0f, -0.8660f, -0.5000f, 0.0f, -0.9659f, -0.2588f, 0.0f, -1.0000f, -0.0000f, 0.0f, -0.9659f, 0.2588f, 0.0f, -0.8660f, 0.5000f, 0.0f, -0.7071f, 0.7071f, 0.0f, -0.5000f, 0.8660f, 0.0f, -0.2588f, 0.9659f, 0.0f, 0.0000f, 1.0000f, 0.0f, }; static const int pillVAR_count = sizeof(pillVAR)/sizeof(GLfloat)/3; void ChipmunkDebugDrawSegment(cpVect a, cpVect b, Color color) { GLfloat verts[] = { a.x, a.y, b.x, b.y, }; glVertexPointer(2, GL_FLOAT, 0, verts); glColor_from_color(color); glDrawArrays(GL_LINES, 0, 2); } void ChipmunkDebugDrawFatSegment(cpVect a, cpVect b, cpFloat radius, Color lineColor, Color fillColor) { if(radius){ glVertexPointer(3, GL_FLOAT, 0, pillVAR); glPushMatrix(); { cpVect d = cpvsub(b, a); cpVect r = cpvmult(d, radius/cpvlength(d)); const GLfloat matrix[] = { r.x, r.y, 0.0f, 0.0f, -r.y, r.x, 0.0f, 0.0f, d.x, d.y, 0.0f, 0.0f, a.x, a.y, 0.0f, 1.0f, }; glMultMatrixf(matrix); if(fillColor.a > 0){ glColor_from_color(fillColor); glDrawArrays(GL_TRIANGLE_FAN, 0, pillVAR_count); } if(lineColor.a > 0){ glColor_from_color(lineColor); glDrawArrays(GL_LINE_LOOP, 0, pillVAR_count); } } glPopMatrix(); } else { ChipmunkDebugDrawSegment(a, b, lineColor); } } void ChipmunkDebugDrawPolygon(int count, cpVect *verts, Color lineColor, Color fillColor) { #if CP_USE_DOUBLES glVertexPointer(2, GL_DOUBLE, 0, verts); #else glVertexPointer(2, GL_FLOAT, 0, verts); #endif if(fillColor.a > 0){ glColor_from_color(fillColor); glDrawArrays(GL_TRIANGLE_FAN, 0, count); } if(lineColor.a > 0){ glColor_from_color(lineColor); glDrawArrays(GL_LINE_LOOP, 0, count); } } void ChipmunkDebugDrawPoints(cpFloat size, int count, cpVect *verts, Color color) { #if CP_USE_DOUBLES glVertexPointer(2, GL_DOUBLE, 0, verts); #else glVertexPointer(2, GL_FLOAT, 0, verts); #endif glPointSize(size*ChipmunkDebugDrawPointLineScale); glColor_from_color(color); glDrawArrays(GL_POINTS, 0, count); } void ChipmunkDebugDrawBB(cpBB bb, Color color) { cpVect verts[] = { cpv(bb.l, bb.b), cpv(bb.l, bb.t), cpv(bb.r, bb.t), cpv(bb.r, bb.b), }; ChipmunkDebugDrawPolygon(4, verts, color, LAColor(0, 0)); } static void drawShape(cpShape *shape, void *unused) { cpBody *body = shape->body; Color color = ColorForShape(shape); switch(shape->klass->type){ case CP_CIRCLE_SHAPE: { cpCircleShape *circle = (cpCircleShape *)shape; ChipmunkDebugDrawCircle(circle->tc, body->a, circle->r, LINE_COLOR, color); break; } case CP_SEGMENT_SHAPE: { cpSegmentShape *seg = (cpSegmentShape *)shape; ChipmunkDebugDrawFatSegment(seg->ta, seg->tb, seg->r, LINE_COLOR, color); break; } case CP_POLY_SHAPE: { cpPolyShape *poly = (cpPolyShape *)shape; ChipmunkDebugDrawPolygon(poly->numVerts, poly->tVerts, LINE_COLOR, color); break; } default: break; } } void ChipmunkDebugDrawShape(cpShape *shape) { drawShape(shape, NULL); } void ChipmunkDebugDrawShapes(cpSpace *space) { cpSpaceEachShape(space, drawShape, NULL); } static const GLfloat springVAR[] = { 0.00f, 0.0f, 0.20f, 0.0f, 0.25f, 3.0f, 0.30f,-6.0f, 0.35f, 6.0f, 0.40f,-6.0f, 0.45f, 6.0f, 0.50f,-6.0f, 0.55f, 6.0f, 0.60f,-6.0f, 0.65f, 6.0f, 0.70f,-3.0f, 0.75f, 6.0f, 0.80f, 0.0f, 1.00f, 0.0f, }; static const int springVAR_count = sizeof(springVAR)/sizeof(GLfloat)/2; static void drawSpring(cpDampedSpring *spring, cpBody *body_a, cpBody *body_b) { cpVect a = cpvadd(body_a->p, cpvrotate(spring->anchr1, body_a->rot)); cpVect b = cpvadd(body_b->p, cpvrotate(spring->anchr2, body_b->rot)); cpVect points[] = {a, b}; ChipmunkDebugDrawPoints(5, 2, points, CONSTRAINT_COLOR); cpVect delta = cpvsub(b, a); glVertexPointer(2, GL_FLOAT, 0, springVAR); glPushMatrix(); { GLfloat x = a.x; GLfloat y = a.y; GLfloat cos = delta.x; GLfloat sin = delta.y; GLfloat s = 1.0f/cpvlength(delta); const GLfloat matrix[] = { cos, sin, 0.0f, 0.0f, -sin*s, cos*s, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, x, y, 0.0f, 1.0f, }; glMultMatrixf(matrix); glDrawArrays(GL_LINE_STRIP, 0, springVAR_count); } glPopMatrix(); } static void drawConstraint(cpConstraint *constraint, void *unused) { cpBody *body_a = constraint->a; cpBody *body_b = constraint->b; const cpConstraintClass *klass = constraint->klass; if(klass == cpPinJointGetClass()){ cpPinJoint *joint = (cpPinJoint *)constraint; cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot)); cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot)); cpVect points[] = {a, b}; ChipmunkDebugDrawPoints(5, 2, points, CONSTRAINT_COLOR); ChipmunkDebugDrawSegment(a, b, CONSTRAINT_COLOR); } else if(klass == cpSlideJointGetClass()){ cpSlideJoint *joint = (cpSlideJoint *)constraint; cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot)); cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot)); cpVect points[] = {a, b}; ChipmunkDebugDrawPoints(5, 2, points, CONSTRAINT_COLOR); ChipmunkDebugDrawSegment(a, b, CONSTRAINT_COLOR); } else if(klass == cpPivotJointGetClass()){ cpPivotJoint *joint = (cpPivotJoint *)constraint; cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot)); cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot)); cpVect points[] = {a, b}; ChipmunkDebugDrawPoints(10, 2, points, CONSTRAINT_COLOR); } else if(klass == cpGrooveJointGetClass()){ cpGrooveJoint *joint = (cpGrooveJoint *)constraint; cpVect a = cpvadd(body_a->p, cpvrotate(joint->grv_a, body_a->rot)); cpVect b = cpvadd(body_a->p, cpvrotate(joint->grv_b, body_a->rot)); cpVect c = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot)); ChipmunkDebugDrawPoints(5, 1, &c, CONSTRAINT_COLOR); ChipmunkDebugDrawSegment(a, b, CONSTRAINT_COLOR); } else if(klass == cpDampedSpringGetClass()){ drawSpring((cpDampedSpring *)constraint, body_a, body_b); } } void ChipmunkDebugDrawConstraint(cpConstraint *constraint) { drawConstraint(constraint, NULL); } void ChipmunkDebugDrawConstraints(cpSpace *space) { cpSpaceEachConstraint(space, drawConstraint, NULL); } void ChipmunkDebugDrawCollisionPoints(cpSpace *space) { cpArray *arbiters = space->arbiters; glColor3f(1.0f, 0.0f, 0.0f); glPointSize(4.0f*ChipmunkDebugDrawPointLineScale); glBegin(GL_POINTS); { for(int i=0; inum; i++){ cpArbiter *arb = (cpArbiter*)arbiters->arr[i]; for(int j=0; jnumContacts; j++){ cpVect v = arb->contacts[j].p; glVertex2f(v.x, v.y); } } } glEnd(); } Chipmunk-6.1.5/Demo/ChipmunkDebugDraw.h000644 000765 000000 00000004211 12151675775 020642 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ typedef struct Color { float r, g, b, a; } Color; static inline Color RGBAColor(float r, float g, float b, float a){ Color color = {r, g, b, a}; return color; } static inline Color LAColor(float l, float a){ Color color = {l, l, l, a}; return color; } extern float ChipmunkDebugDrawPointLineScale; void ChipmunkDebugDrawCircle(cpVect center, cpFloat angle, cpFloat radius, Color lineColor, Color fillColor); void ChipmunkDebugDrawSegment(cpVect a, cpVect b, Color color); void ChipmunkDebugDrawFatSegment(cpVect a, cpVect b, cpFloat radius, Color lineColor, Color fillColor); void ChipmunkDebugDrawPolygon(int count, cpVect *verts, Color lineColor, Color fillColor); void ChipmunkDebugDrawPoints(cpFloat size, int count, cpVect *verts, Color color); void ChipmunkDebugDrawBB(cpBB bb, Color color); void ChipmunkDebugDrawConstraint(cpConstraint *constraint); void ChipmunkDebugDrawShape(cpShape *shape); void ChipmunkDebugDrawShapes(cpSpace *space); void ChipmunkDebugDrawConstraints(cpSpace *space); void ChipmunkDebugDrawCollisionPoints(cpSpace *space); Chipmunk-6.1.5/Demo/ChipmunkDemo.c000644 000765 000000 00000034675 12151675775 017676 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* IMPORTANT - READ ME! This file sets up a simple interface that the individual demos can use to get a Chipmunk space running and draw what's in it. In order to keep the Chipmunk examples clean and simple, they contain no graphics code. All drawing is done by accessing the Chipmunk structures at a very low level. It is NOT recommended to write a game or application this way as it does not scale beyond simple shape drawing and is very dependent on implementation details about Chipmunk which may change with little to no warning. */ #include #include #include #include #ifdef __APPLE__ #include "OpenGL/gl.h" #include "OpenGL/glu.h" #include #else #ifdef WIN32 #include #endif #include #include #include #endif #include "chipmunk_private.h" #include "ChipmunkDemo.h" #define SLEEP_TICKS 16 static ChipmunkDemo *demos; static int demoCount = 0; static int demoIndex = 'a' - 'a'; static cpBool paused = cpFalse; static cpBool step = cpFalse; static cpBool drawBBs = cpFalse; static cpSpace *space; int ChipmunkDemoTicks = 0; cpFloat ChipmunkDemoTime; static cpBody *mouseBody = NULL; static cpConstraint *mouseJoint = NULL; cpVect ChipmunkDemoMouse; cpBool ChipmunkDemoRightClick = cpFalse; cpBool ChipmunkDemoRightDown = cpFalse; char *ChipmunkDemoMessageString = NULL; static int key_up = 0; static int key_down = 0; static int key_left = 0; static int key_right = 0; cpVect ChipmunkDemoKeyboard = {}; GLfloat translate_x = 0.0; GLfloat translate_y = 0.0; GLfloat scale = 1.0; static void shapeFreeWrap(cpSpace *space, cpShape *shape, void *unused){ cpSpaceRemoveShape(space, shape); cpShapeFree(shape); } static void postShapeFree(cpShape *shape, cpSpace *space){ cpSpaceAddPostStepCallback(space, (cpPostStepFunc)shapeFreeWrap, shape, NULL); } static void constraintFreeWrap(cpSpace *space, cpConstraint *constraint, void *unused){ cpSpaceRemoveConstraint(space, constraint); cpConstraintFree(constraint); } static void postConstraintFree(cpConstraint *constraint, cpSpace *space){ cpSpaceAddPostStepCallback(space, (cpPostStepFunc)constraintFreeWrap, constraint, NULL); } static void bodyFreeWrap(cpSpace *space, cpBody *body, void *unused){ cpSpaceRemoveBody(space, body); cpBodyFree(body); } static void postBodyFree(cpBody *body, cpSpace *space){ cpSpaceAddPostStepCallback(space, (cpPostStepFunc)bodyFreeWrap, body, NULL); } // Safe and future proof way to remove and free all objects that have been added to the space. void ChipmunkDemoFreeSpaceChildren(cpSpace *space) { // Must remove these BEFORE freeing the body or you will access dangling pointers. cpSpaceEachShape(space, (cpSpaceShapeIteratorFunc)postShapeFree, space); cpSpaceEachConstraint(space, (cpSpaceConstraintIteratorFunc)postConstraintFree, space); cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)postBodyFree, space); } void ChipmunkDemoDefaultDrawImpl(cpSpace *space) { ChipmunkDebugDrawShapes(space); ChipmunkDebugDrawConstraints(space); ChipmunkDebugDrawCollisionPoints(space); } static void drawString(int x, int y, const char *str) { glColor3f(1.0f, 1.0f, 1.0f); glRasterPos2i(x, y); for(int i=0, len=strlen(str); iarbiters->num; int points = 0; for(int i=0; iarbiters->arr[i]))->numContacts; int constraints = (space->constraints->num + points)*space->iterations; maxArbiters = arbiters > maxArbiters ? arbiters : maxArbiters; maxPoints = points > maxPoints ? points : maxPoints; maxConstraints = constraints > maxConstraints ? constraints : maxConstraints; char buffer[1024]; const char *format = "Arbiters: %d (%d) - " "Contact Points: %d (%d)\n" "Other Constraints: %d, Iterations: %d\n" "Constraints x Iterations: %d (%d)\n" "Time:% 5.2fs, KE:% 5.2e"; cpArray *bodies = space->bodies; cpFloat ke = 0.0f; for(int i=0; inum; i++){ cpBody *body = (cpBody *)bodies->arr[i]; if(body->m == INFINITY || body->i == INFINITY) continue; ke += body->m*cpvdot(body->v, body->v) + body->i*body->w*body->w; } sprintf(buffer, format, arbiters, maxArbiters, points, maxPoints, space->constraints->num, space->iterations, constraints, maxConstraints, ChipmunkDemoTime, (ke < 1e-10f ? 0.0f : ke) ); drawString(0, 220, buffer); } static void reshape(int width, int height) { glViewport(0, 0, width, height); double scale = cpfmin(width/640.0, height/480.0); double hw = width*(0.5/scale); double hh = height*(0.5/scale); ChipmunkDebugDrawPointLineScale = scale; glLineWidth(scale); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-hw, hw, -hh, hh, -1.0, 1.0); glTranslated(0.5, 0.5, 0.0); } static void drawShapeBB(cpShape *shape, void *unused) { ChipmunkDebugDrawBB(shape->bb, RGBAColor(0.3f, 0.5f, 0.3f, 1.0f)); } static char PrintStringBuffer[1024*8]; static char *PrintStringCursor; void ChipmunkDemoPrintString(char *fmt, ...) { ChipmunkDemoMessageString = PrintStringBuffer; va_list args; va_start(args, fmt); PrintStringCursor += vsprintf(PrintStringCursor, fmt, args); va_end(args); } static void display(void) { PrintStringBuffer[0] = 0; PrintStringCursor = PrintStringBuffer; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glScalef(scale, scale, 1.0); glTranslatef(translate_x, translate_y, 0.0); demos[demoIndex].drawFunc(space); if(!paused || step){ cpVect newPoint = cpvlerp(mouseBody->p, ChipmunkDemoMouse, 0.25f); mouseBody->v = cpvmult(cpvsub(newPoint, mouseBody->p), 60.0f); mouseBody->p = newPoint; demos[demoIndex].updateFunc(space); ChipmunkDemoTicks++; ChipmunkDemoTime = ChipmunkDemoTicks/60.0; step = cpFalse; ChipmunkDemoRightDown = cpFalse; } if(drawBBs) cpSpaceEachShape(space, drawShapeBB, NULL); glMatrixMode(GL_MODELVIEW); glPushMatrix(); { // Draw the text at fixed positions, // but save the drawing matrix for the mouse picking glLoadIdentity(); drawInstructions(); drawInfo(); drawString(-300, -200, ChipmunkDemoMessageString); } glPopMatrix(); glutSwapBuffers(); glClear(GL_COLOR_BUFFER_BIT); } static char * demoTitle(int index) { static char title[1024]; sprintf(title, "Demo(%c): %s", 'a' + index, demos[demoIndex].name); return title; } static void runDemo(int index) { srand(45073); demoIndex = index; ChipmunkDemoTicks = 0; mouseJoint = NULL; ChipmunkDemoMessageString = ""; maxArbiters = 0; maxPoints = 0; maxConstraints = 0; space = demos[demoIndex].initFunc(); glutSetWindowTitle(demoTitle(index)); } static void keyboard(unsigned char key, int x, int y) { int index = key - 'a'; if(0 <= index && index < demoCount){ demos[demoIndex].destroyFunc(space); runDemo(index); } else if(key == '\r'){ demos[demoIndex].destroyFunc(space); runDemo(demoIndex); } else if(key == '`'){ paused = !paused; } else if(key == '1'){ step = cpTrue; } else if(key == '='){ drawBBs = !drawBBs; } else if(key == '\\'){ glDisable(GL_LINE_SMOOTH); glDisable(GL_POINT_SMOOTH); } GLfloat translate_increment = 50.0/scale; GLfloat scale_increment = 1.2; if(key == '5'){ translate_x = 0.0; translate_y = 0.0; scale = 1.0; }else if(key == '4'){ translate_x += translate_increment; }else if(key == '6'){ translate_x -= translate_increment; }else if(key == '2'){ translate_y += translate_increment; }else if(key == '8'){ translate_y -= translate_increment; }else if(key == '7'){ scale /= scale_increment; }else if(key == '9'){ scale *= scale_increment; } } static cpVect mouseToSpace(int x, int y) { GLdouble model[16]; glGetDoublev(GL_MODELVIEW_MATRIX, model); GLdouble proj[16]; glGetDoublev(GL_PROJECTION_MATRIX, proj); GLint view[4]; glGetIntegerv(GL_VIEWPORT, view); GLdouble mx, my, mz; gluUnProject(x, glutGet(GLUT_WINDOW_HEIGHT) - y, 0.0f, model, proj, view, &mx, &my, &mz); return cpv(mx, my); } static void mouse(int x, int y) { ChipmunkDemoMouse = mouseToSpace(x, y); } static void click(int button, int state, int x, int y) { if(button == GLUT_LEFT_BUTTON){ if(state == GLUT_DOWN){ cpVect point = mouseToSpace(x, y); cpShape *shape = cpSpacePointQueryFirst(space, point, GRABABLE_MASK_BIT, CP_NO_GROUP); if(shape){ cpBody *body = shape->body; mouseJoint = cpPivotJointNew2(mouseBody, body, cpvzero, cpBodyWorld2Local(body, point)); mouseJoint->maxForce = 50000.0f; mouseJoint->errorBias = cpfpow(1.0f - 0.15f, 60.0f); cpSpaceAddConstraint(space, mouseJoint); } } else if(mouseJoint){ cpSpaceRemoveConstraint(space, mouseJoint); cpConstraintFree(mouseJoint); mouseJoint = NULL; } } else if(button == GLUT_RIGHT_BUTTON){ ChipmunkDemoRightDown = ChipmunkDemoRightClick = (state == GLUT_DOWN); } } static void timercall(int value) { glutTimerFunc(SLEEP_TICKS, timercall, 0); glutPostRedisplay(); } static void set_arrowDirection() { int x = 0, y = 0; if(key_up) y += 1; if(key_down) y -= 1; if(key_right) x += 1; if(key_left) x -= 1; ChipmunkDemoKeyboard = cpv(x, y); } static void arrowKeyDownFunc(int key, int x, int y) { if(key == GLUT_KEY_UP) key_up = 1; else if(key == GLUT_KEY_DOWN) key_down = 1; else if(key == GLUT_KEY_LEFT) key_left = 1; else if(key == GLUT_KEY_RIGHT) key_right = 1; set_arrowDirection(); } static void arrowKeyUpFunc(int key, int x, int y) { if(key == GLUT_KEY_UP) key_up = 0; else if(key == GLUT_KEY_DOWN) key_down = 0; else if(key == GLUT_KEY_LEFT) key_left = 0; else if(key == GLUT_KEY_RIGHT) key_right = 0; set_arrowDirection(); } //static void //idle(void) //{ // glutPostRedisplay(); //} static void initGL(void) { glClearColor(52.0/255.0, 62.0/255.0, 72.0/255.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_LINE_SMOOTH); glEnable(GL_POINT_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } static void glutStuff(int argc, const char *argv[]) { glutInit(&argc, (char**)argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(640, 480); glutCreateWindow(demoTitle(demoIndex)); initGL(); glutReshapeFunc(reshape); glutDisplayFunc(display); // glutIdleFunc(idle); glutTimerFunc(SLEEP_TICKS, timercall, 0); glutIgnoreKeyRepeat(1); glutKeyboardFunc(keyboard); glutSpecialFunc(arrowKeyDownFunc); glutSpecialUpFunc(arrowKeyUpFunc); glutMotionFunc(mouse); glutPassiveMotionFunc(mouse); glutMouseFunc(click); } #ifdef WIN32 static double GetMilliseconds(){ __int64 count, freq; QueryPerformanceCounter((LARGE_INTEGER*)&count); QueryPerformanceFrequency((LARGE_INTEGER*)&freq); return 1000.0*(double)count/(double)freq; } #else #include #include static double GetMilliseconds(){ struct timeval time; gettimeofday(&time, NULL); return (time.tv_sec*1000.0 + time.tv_usec/1000.0); } #endif void time_trial(int index, int count) { space = demos[index].initFunc(); double start_time = GetMilliseconds(); for(int i=0; imagnitudeSum += cpvlength(j); context->vectorSum = cpvadd(context->vectorSum, j); } #endif static void update(cpSpace *space) { int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; i 10.0f){ ChipmunkDemoPrintString("The ball is being crushed. (f: %.2f)", crushForce); } else { ChipmunkDemoPrintString("The ball is not being crushed. (f: %.2f)", crushForce); } } #define WIDTH 4.0f #define HEIGHT 30.0f static cpSpace * init(void) { cpSpace *space = cpSpaceNew(); cpSpaceSetIterations(space, 30); cpSpaceSetGravity(space, cpv(0, -300)); cpSpaceSetCollisionSlop(space, 0.5); // For cpBodyEachArbiter() to work you must explicitly enable the contact graph or enable sleeping. // Generating the contact graph is a small but measurable ~5-10% performance hit so it's not enabled by default. // cpSpaceSetEnableContactGraph(space, cpTrue); cpSpaceSetSleepTimeThreshold(space, 1.0f); cpBody *body, *staticBody = cpSpaceGetStaticBody(space); cpShape *shape; // Create segments around the edge of the screen. shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); scaleStaticBody = cpBodyNewStatic(); shape = cpSpaceAddShape(space, cpSegmentShapeNew(scaleStaticBody, cpv(-240,-180), cpv(-140,-180), 4.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); // add some boxes to stack on the scale for(int i=0; i<5; i++){ body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForBox(1.0f, 30.0f, 30.0f))); cpBodySetPos(body, cpv(0, i*32 - 220)); shape = cpSpaceAddShape(space, cpBoxShapeNew(body, 30.0f, 30.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.8f); } // Add a ball that we'll track which objects are beneath it. cpFloat radius = 15.0f; ballBody = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 0.0f, radius, cpvzero))); cpBodySetPos(ballBody, cpv(120, -240 + radius+5)); shape = cpSpaceAddShape(space, cpCircleShapeNew(ballBody, radius, cpvzero)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.9f); return space; } static void destroy(cpSpace *space) { ChipmunkDemoFreeSpaceChildren(space); cpSpaceFree(space); cpBodyFree(scaleStaticBody); } ChipmunkDemo ContactGraph = { "Contact Graph", init, update, ChipmunkDemoDefaultDrawImpl, destroy, }; Chipmunk-6.1.5/Demo/Convex.c000644 000765 000000 00000007425 12151675775 016546 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk.h" #include "chipmunk_unsafe.h" #include "ChipmunkDemo.h" #define DENSITY (1.0/10000.0) static cpShape *shape; static void update(cpSpace *space) { cpFloat tolerance = 2.0; if(ChipmunkDemoRightClick && cpShapeNearestPointQuery(shape, ChipmunkDemoMouse, NULL) > tolerance){ cpBody *body = cpShapeGetBody(shape); int count = cpPolyShapeGetNumVerts(shape); // Allocate the space for the new vertexes on the stack. cpVect *verts = (cpVect *)alloca((count + 1)*sizeof(cpVect)); for(int i=0; i>3) + y*image_row_length]>>(~x&0x7)) & 1; } static int bodyCount = 0; static void update(cpSpace *space) { int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; in) < 0){ cpArbiterIgnore(arb); return cpFalse; } return cpTrue; } static void update(cpSpace *space) { int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; ivelocity_func = planetGravityVelocityFunc; cpBodySetPos(body, pos); // Set the box's velocity to put it into a circular orbit from its // starting position. cpFloat r = cpvlength(pos); cpFloat v = cpfsqrt(gravityStrength / r) / r; cpBodySetVel(body, cpvmult(cpvperp(pos), v)); // Set the box's angular velocity to match its orbital period and // align its initial angle with its position. cpBodySetAngVel(body, v); cpBodySetAngle(body, cpfatan2(pos.y, pos.x)); cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 4, verts, cpvzero)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.7f); } static cpSpace * init(void) { // Create a rouge body to control the planet manually. planetBody = cpBodyNew(INFINITY, INFINITY); cpBodySetAngVel(planetBody, 0.2f); cpSpace *space = cpSpaceNew(); cpSpaceSetIterations(space, 20); for(int i=0; i<30; i++) add_box(space); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(planetBody, 70.0f, cpvzero)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); return space; } static void destroy(cpSpace *space) { ChipmunkDemoFreeSpaceChildren(space); cpBodyFree(planetBody); cpSpaceFree(space); } ChipmunkDemo Planet = { "Planet", init, update, ChipmunkDemoDefaultDrawImpl, destroy, }; Chipmunk-6.1.5/Demo/Player.c000644 000765 000000 00000012546 12151675775 016540 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk_private.h" #include "ChipmunkDemo.h" #define PLAYER_VELOCITY 500.0 #define PLAYER_GROUND_ACCEL_TIME 0.1 #define PLAYER_GROUND_ACCEL (PLAYER_VELOCITY/PLAYER_GROUND_ACCEL_TIME) #define PLAYER_AIR_ACCEL_TIME 0.25 #define PLAYER_AIR_ACCEL (PLAYER_VELOCITY/PLAYER_AIR_ACCEL_TIME) #define JUMP_HEIGHT 50.0 #define JUMP_BOOST_HEIGHT 55.0 #define FALL_VELOCITY 900.0 #define GRAVITY 2000.0 static cpBody *playerBody = NULL; static cpShape *playerShape = NULL; static cpFloat remainingBoost = 0; static cpBool grounded = cpFalse; static cpBool lastJumpState = cpFalse; static void SelectPlayerGroundNormal(cpBody *body, cpArbiter *arb, cpVect *groundNormal){ cpVect n = cpvneg(cpArbiterGetNormal(arb, 0)); if(n.y > groundNormal->y){ (*groundNormal) = n; } } static void playerUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt) { int jumpState = (ChipmunkDemoKeyboard.y > 0.0f); // Grab the grounding normal from last frame cpVect groundNormal = cpvzero; cpBodyEachArbiter(playerBody, (cpBodyArbiterIteratorFunc)SelectPlayerGroundNormal, &groundNormal); grounded = (groundNormal.y > 0.0); if(groundNormal.y < 0.0f) remainingBoost = 0.0f; // Do a normal-ish update cpBool boost = (jumpState && remainingBoost > 0.0f); cpVect g = (boost ? cpvzero : gravity); cpBodyUpdateVelocity(body, g, damping, dt); // Target horizontal speed for air/ground control cpFloat target_vx = PLAYER_VELOCITY*ChipmunkDemoKeyboard.x; // Update the surface velocity and friction cpVect surface_v = cpv(target_vx, 0.0); playerShape->surface_v = surface_v; playerShape->u = (grounded ? PLAYER_GROUND_ACCEL/GRAVITY : 0.0); // Apply air control if not grounded if(!grounded){ // Smoothly accelerate the velocity playerBody->v.x = cpflerpconst(playerBody->v.x, target_vx, PLAYER_AIR_ACCEL*dt); } body->v.y = cpfclamp(body->v.y, -FALL_VELOCITY, INFINITY); } static void update(cpSpace *space) { int jumpState = (ChipmunkDemoKeyboard.y > 0.0f); // If the jump key was just pressed this frame, jump! if(jumpState && !lastJumpState && grounded){ cpFloat jump_v = cpfsqrt(2.0*JUMP_HEIGHT*GRAVITY); playerBody->v = cpvadd(playerBody->v, cpv(0.0, jump_v)); remainingBoost = JUMP_BOOST_HEIGHT/jump_v; } // Step the space int steps = 3; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; iiterations = 10; space->gravity = cpv(0, -GRAVITY); // space->sleepTimeThreshold = 1000; space->enableContactGraph = cpTrue; cpBody *body, *staticBody = space->staticBody; cpShape *shape; // Create segments around the edge of the screen. shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f)); shape->e = 1.0f; shape->u = 1.0f; shape->layers = NOT_GRABABLE_MASK; shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f)); shape->e = 1.0f; shape->u = 1.0f; shape->layers = NOT_GRABABLE_MASK; shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f)); shape->e = 1.0f; shape->u = 1.0f; shape->layers = NOT_GRABABLE_MASK; shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f)); shape->e = 1.0f; shape->u = 1.0f; shape->layers = NOT_GRABABLE_MASK; // Set up the player cpFloat radius = 25.0f; body = cpSpaceAddBody(space, cpBodyNew(1.0f, INFINITY)); body->p = cpv(0, -200); body->velocity_func = playerUpdateVelocity; playerBody = body; shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero)); shape->e = 0.0f; shape->u = 0.0f; shape->collision_type = 1; playerShape = shape; // Add some boxes to jump on for(int i=0; i<6; i++){ for(int j=0; j<3; j++){ body = cpSpaceAddBody(space, cpBodyNew(4.0f, INFINITY)); body->p = cpv(100 + j*60, -200 + i*60); shape = cpSpaceAddShape(space, cpBoxShapeNew(body, 50, 50)); shape->e = 0.0f; shape->u = 0.7f; } } return space; } static void destroy(cpSpace *space) { ChipmunkDemoFreeSpaceChildren(space); cpSpaceFree(space); } ChipmunkDemo Player = { "Platformer Player Controls", init, update, ChipmunkDemoDefaultDrawImpl, destroy, }; Chipmunk-6.1.5/Demo/Plink.c000644 000765 000000 00000007500 12151675775 016353 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk.h" #include "ChipmunkDemo.h" static cpFloat pentagon_mass = 0.0f; static cpFloat pentagon_moment = 0.0f; // Iterate over all of the bodies and reset the ones that have fallen offscreen. static void eachBody(cpBody *body, void *unused) { cpVect pos = cpBodyGetPos(body); if(pos.y < -260 || cpfabs(pos.x) > 340){ cpFloat x = rand()/(cpFloat)RAND_MAX*640 - 320; cpBodySetPos(body, cpv(x, 260)); } } static void update(cpSpace *space) { if(ChipmunkDemoRightDown){ cpShape *nearest = cpSpaceNearestPointQueryNearest(space, ChipmunkDemoMouse, 0.0, GRABABLE_MASK_BIT, CP_NO_GROUP, NULL); if(nearest){ cpBody *body = cpShapeGetBody(nearest); if(cpBodyIsStatic(body)){ cpSpaceConvertBodyToDynamic(space, body, 1.0f, cpMomentForBox(1.0f, 30.0f, 30.0f)); cpSpaceAddBody(space, body); } else { cpSpaceRemoveBody(space, body); cpSpaceConvertBodyToStatic(space, body); } } } int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; i 320.0f){ cpBodySetVel(ball, cpvzero); cpBodySetPos(ball, cpv(-224.0f, 200.0f)); } } } } static cpBody * add_ball(cpSpace *space, cpVect pos) { cpBody *body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 30, 0, cpvzero))); cpBodySetPos(body, pos); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, 30, cpvzero)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); return body; } static cpSpace * init(void) { ChipmunkDemoMessageString = "Use the arrow keys to control the machine."; cpSpace *space = cpSpaceNew(); cpSpaceSetGravity(space, cpv(0, -600)); cpBody *staticBody = cpSpaceGetStaticBody(space); cpShape *shape; // beveling all of the line segments slightly helps prevent things from getting stuck on cracks shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-256,16), cpv(-256,300), 2.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-256,16), cpv(-192,0), 2.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192,0), cpv(-192, -64), 2.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-128,-64), cpv(-128,144), 2.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192,80), cpv(-192,176), 2.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192,176), cpv(-128,240), 2.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-128,144), cpv(192,64), 2.0f)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); cpVect verts[] = { cpv(-30,-80), cpv(-30, 80), cpv( 30, 64), cpv( 30,-80), }; cpBody *plunger = cpSpaceAddBody(space, cpBodyNew(1.0f, INFINITY)); cpBodySetPos(plunger, cpv(-160,-80)); shape = cpSpaceAddShape(space, cpPolyShapeNew(plunger, 4, verts, cpvzero)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 0.5f); cpShapeSetLayers(shape, 1); // add balls to hopper for(int i=0; i>16) & 0xFFFF)/(cpFloat)0xFFFF) ); } static cpVect WorleyPoint(int i, int j, struct WorleyContex *context) { cpFloat size = context->cellSize; int width = context->width; int height = context->height; cpBB bb = context->bb; // cpVect fv = cpv(0.5, 0.5); cpVect fv = HashVect(i, j, context->seed); return cpv( cpflerp(bb.l, bb.r, 0.5f) + size*(i + fv.x - width*0.5f), cpflerp(bb.b, bb.t, 0.5f) + size*(j + fv.y - height*0.5f) ); } static int ClipCell(cpShape *shape, cpVect center, int i, int j, struct WorleyContex *context, cpVect *verts, cpVect *clipped, int count) { cpVect other = WorleyPoint(i, j, context); // printf(" other %dx%d: (% 5.2f, % 5.2f) ", i, j, other.x, other.y); if(cpShapeNearestPointQuery(shape, other, NULL) > 0.0f){ // printf("excluded\n"); memcpy(clipped, verts, count*sizeof(cpVect)); return count; } else { // printf("clipped\n"); } cpVect n = cpvsub(other, center); cpFloat dist = cpvdot(n, cpvlerp(center, other, 0.5f)); int clipped_count = 0; for(int j=0, i=count-1; j MAX_VERTEXES_PER_VORONOI ? MAX_VERTEXES_PER_VORONOI : count); for(int i=0; iwidth; i++){ for(int j=0; jheight; j++){ if( !(i == cell_i && j == cell_j) && cpShapeNearestPointQuery(shape, cell, NULL) < 0.0f ){ count = ClipCell(shape, cell, i, j, context, ping, pong, count); memcpy(ping, pong, count*sizeof(cpVect)); } } } cpVect centroid = cpCentroidForPoly(count, ping); cpFloat mass = cpAreaForPoly(count, ping)*DENSITY; cpFloat moment = cpMomentForPoly(mass, count, ping, cpvneg(centroid)); cpBody *new_body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); cpBodySetPos(new_body, centroid); cpBodySetVel(new_body, cpBodyGetVelAtWorldPoint(body, centroid)); cpBodySetAngVel(new_body, cpBodyGetAngVel(body)); cpShape *new_shape = cpSpaceAddShape(space, cpPolyShapeNew(new_body, count, ping, cpvneg(centroid))); // Copy whatever properties you have set on the original shape that are important cpShapeSetFriction(new_shape, cpShapeGetFriction(shape)); } static void ShatterShape(cpSpace *space, cpShape *shape, cpFloat cellSize, cpVect focus) { cpSpaceRemoveShape(space, shape); cpSpaceRemoveBody(space, shape->body); cpBB bb = cpShapeGetBB(shape); int width = (bb.r - bb.l)/cellSize + 1; int height = (bb.t - bb.b)/cellSize + 1; // printf("Splitting as %dx%d\n", width, height); struct WorleyContex context = {rand(), cellSize, width, height, bb, focus}; for(int i=0; ibody); cpShapeFree(shape); } static void update(cpSpace *space) { int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; i 5.0f){ ShatterShape(space, info.shape, cell_size, ChipmunkDemoMouse); } else { printf("Too small to splinter %f\n", cell_size); } } } } static cpSpace * init(void) { ChipmunkDemoMessageString = "Right click something to shatter it."; cpSpace *space = cpSpaceNew(); cpSpaceSetIterations(space, 30); cpSpaceSetGravity(space, cpv(0, -500)); cpSpaceSetSleepTimeThreshold(space, 0.5f); cpSpaceSetCollisionSlop(space, 0.5f); cpBody *body, *staticBody = cpSpaceGetStaticBody(space); cpShape *shape; // Create segments around the edge of the screen. shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-1000, -240), cpv( 1000, -240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); cpFloat width = 200.0f; cpFloat height = 200.0f; cpFloat mass = width*height*DENSITY; cpFloat moment = cpMomentForBox(mass, width, height); body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); shape = cpSpaceAddShape(space, cpBoxShapeNew(body, width, height)); cpShapeSetFriction(shape, 0.6f); return space; } static void destroy(cpSpace *space) { ChipmunkDemoFreeSpaceChildren(space); cpSpaceFree(space); } ChipmunkDemo Shatter = { "Shatter.", init, update, ChipmunkDemoDefaultDrawImpl, destroy, }; Chipmunk-6.1.5/Demo/Slice.c000644 000765 000000 00000013400 12151675775 016331 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "chipmunk.h" #include "constraints/util.h" #include "ChipmunkDemo.h" #define DENSITY (1.0/10000.0) static void ClipPoly(cpSpace *space, cpShape *shape, cpVect n, cpFloat dist) { cpBody *body = cpShapeGetBody(shape); int count = cpPolyShapeGetNumVerts(shape); int clippedCount = 0; cpVect *clipped = (cpVect *)alloca((count + 1)*sizeof(cpVect)); for(int i=0, j=count-1; ia; cpVect b = context->b; // Clipping plane normal and distance. cpVect n = cpvnormalize(cpvperp(cpvsub(b, a))); cpFloat dist = cpvdot(a, n); ClipPoly(space, shape, n, dist); ClipPoly(space, shape, cpvneg(n), -dist); cpBody *body = cpShapeGetBody(shape); cpSpaceRemoveShape(space, shape); cpSpaceRemoveBody(space, body); cpShapeFree(shape); cpBodyFree(body); } static void SliceQuery(cpShape *shape, cpFloat t, cpVect n, struct SliceContext *context) { cpVect a = context->a; cpVect b = context->b; // Check that the slice was complete by checking that the endpoints aren't in the sliced shape. if(!cpShapePointQuery(shape, a) && !cpShapePointQuery(shape, b)){ // Can't modify the space during a query. // Must make a post-step callback to do the actual slicing. cpSpaceAddPostStepCallback(context->space, (cpPostStepFunc)SliceShapePostStep, shape, context); } } static void update(cpSpace *space) { int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; i #include "chipmunk.h" #include "ChipmunkDemo.h" static cpFloat springForce(cpConstraint *spring, cpFloat dist) { cpFloat clamp = 20.0f; return cpfclamp(cpDampedSpringGetRestLength(spring) - dist, -clamp, clamp)*cpDampedSpringGetStiffness(spring); } static cpConstraint * new_spring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiff, cpFloat damp) { cpConstraint *spring = cpDampedSpringNew(a, b, anchr1, anchr2, restLength, stiff, damp); cpDampedSpringSetSpringForceFunc(spring, springForce); return spring; } static void update(cpSpace *space) { int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; i 0.0 ? 1.0 : -1.0); cpBodySetVel(tankControlBody, cpvrotate(cpBodyGetRot(tankBody), cpv(30.0f*direction, 0.0f))); } cpSpaceStep(space, dt); } } static cpBody * add_box(cpSpace *space, cpFloat size, cpFloat mass) { cpFloat radius = cpvlength(cpv(size, size)); cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForBox(mass, size, size))); cpBodySetPos(body, cpv(frand()*(640 - 2*radius) - (320 - radius), frand()*(480 - 2*radius) - (240 - radius))); cpShape *shape = cpSpaceAddShape(space, cpBoxShapeNew(body, size, size)); cpShapeSetElasticity(shape, 0.0f); cpShapeSetFriction(shape, 0.7f); return body; } static cpSpace * init(void) { ChipmunkDemoMessageString = "Use the mouse to drive the tank, it will follow the cursor."; cpSpace *space = cpSpaceNew(); cpSpaceSetIterations(space, 10); cpSpaceSetSleepTimeThreshold(space, 0.5f); cpBody *staticBody = cpSpaceGetStaticBody(space); cpShape *shape; // Create segments around the edge of the screen. shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); for(int i=0; i<50; i++){ cpBody *body = add_box(space, 20, 1); cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, body, cpvzero, cpvzero)); cpConstraintSetMaxBias(pivot, 0); // disable joint correction cpConstraintSetMaxForce(pivot, 1000.0f); // emulate linear friction cpConstraint *gear = cpSpaceAddConstraint(space, cpGearJointNew(staticBody, body, 0.0f, 1.0f)); cpConstraintSetMaxBias(gear, 0); // disable joint correction cpConstraintSetMaxForce(gear, 5000.0f); // emulate angular friction } // We joint the tank to the control body and control the tank indirectly by modifying the control body. tankControlBody = cpBodyNew(INFINITY, INFINITY); tankBody = add_box(space, 30, 10); cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(tankControlBody, tankBody, cpvzero, cpvzero)); cpConstraintSetMaxBias(pivot, 0); // disable joint correction cpConstraintSetMaxForce(pivot, 10000.0f); // emulate linear friction cpConstraint *gear = cpSpaceAddConstraint(space, cpGearJointNew(tankControlBody, tankBody, 0.0f, 1.0f)); cpConstraintSetErrorBias(gear, 0); // attempt to fully correct the joint each step cpConstraintSetMaxBias(gear, 1.2f); // but limit it's angular correction rate cpConstraintSetMaxForce(gear, 50000.0f); // emulate angular friction return space; } static void destroy(cpSpace *space) { ChipmunkDemoFreeSpaceChildren(space); cpBodyFree(tankControlBody); cpSpaceFree(space); } ChipmunkDemo Tank = { "Tank", init, update, ChipmunkDemoDefaultDrawImpl, destroy, }; Chipmunk-6.1.5/Demo/TheoJansen.c000644 000765 000000 00000013213 12151675775 017332 0ustar00slembckewheel000000 000000 /* Copyright (c) 2007 Scott Lembcke * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /* * The previous WalkBot demo I designed was fairly disappointing, so I implemented * the mechanism that Theo Jansen uses in his kinetic sculptures. Brilliant. * Read more here: http://en.wikipedia.org/wiki/Theo_Jansen */ #include "chipmunk.h" #include "ChipmunkDemo.h" static cpConstraint *motor; static void update(cpSpace *space) { cpFloat coef = (2.0f + ChipmunkDemoKeyboard.y)/3.0f; cpFloat rate = ChipmunkDemoKeyboard.x*10.0f*coef; cpSimpleMotorSetRate(motor, rate); cpConstraintSetMaxForce(motor, (rate) ? 100000.0f : 0.0f); int steps = 3; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; ip.x)/dt, -max_v, max_v); cpFloat error_v = (target_v - balance_body->v.x); cpFloat target_sin = 3.0e-3*bias_coef(0.1, dt)*error_v/dt; cpFloat max_sin = cpfsin(0.6); balance_sin = cpfclamp(balance_sin - 6.0e-5*bias_coef(0.2, dt)*error_v/dt, -max_sin, max_sin); cpFloat target_a = asin(cpfclamp(-target_sin + balance_sin, -max_sin, max_sin)); cpFloat angular_diff = asin(cpvcross(balance_body->rot, cpvforangle(target_a))); cpFloat target_w = bias_coef(0.1, dt/0.4)*(angular_diff)/dt; cpFloat max_rate = 50.0; cpFloat rate = cpfclamp(wheel_body->w + balance_body->w - target_w, -max_rate, max_rate); cpSimpleMotorSetRate(motor, cpfclamp(rate, -max_rate, max_rate)); cpConstraintSetMaxForce(motor, 8.0e4); } static void update(cpSpace *space) { int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; istaticBody; shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-3200,-240), cpv(3200,-240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(0,-200), cpv(240,-240), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-240,-240), cpv(0,-200), 0.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); } { cpFloat radius = 20.0; cpFloat mass = 1.0; cpFloat moment = cpMomentForCircle(mass, 0.0, radius, cpvzero); wheel_body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); wheel_body->p = cpv(0.0, -160.0 + radius); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(wheel_body, radius, cpvzero)); shape->u = 0.7; shape->group = 1; } { cpFloat cog_offset = 30.0; cpBB bb1 = cpBBNew(-5.0, 0.0 - cog_offset, 5.0, cog_offset*1.2 - cog_offset); cpBB bb2 = cpBBNew(-25.0, bb1.t, 25.0, bb1.t + 10.0); cpFloat mass = 3.0; cpFloat moment = cpMomentForBox2(mass, bb1) + cpMomentForBox2(mass, bb2); balance_body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); balance_body->p = cpv(0.0, wheel_body->p.y + cog_offset); cpShape *shape = NULL; shape = cpSpaceAddShape(space, cpBoxShapeNew2(balance_body, bb1)); shape->u = 1.0; shape->group = 1; shape = cpSpaceAddShape(space, cpBoxShapeNew2(balance_body, bb2)); shape->u = 1.0; shape->group = 1; } cpVect anchr1 = cpBodyWorld2Local(balance_body, wheel_body->p); cpVect groove_a = cpvadd(anchr1, cpv(0.0, 30.0)); cpVect groove_b = cpvadd(anchr1, cpv(0.0, -10.0)); cpSpaceAddConstraint(space, cpGrooveJointNew(balance_body, wheel_body, groove_a, groove_b, cpvzero)); cpSpaceAddConstraint(space, cpDampedSpringNew(balance_body, wheel_body, anchr1, cpvzero, 0.0, 6.0e2, 30.0)); motor = cpSpaceAddConstraint(space, cpSimpleMotorNew(wheel_body, balance_body, 0.0)); motor->preSolve = motor_preSolve; { cpFloat width = 100.0; cpFloat height = 20.0; cpFloat mass = 3.0; cpBody *boxBody = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForBox(mass, width, height))); cpBodySetPos(boxBody, cpv(200, -100)); cpShape *shape = cpSpaceAddShape(space, cpBoxShapeNew(boxBody, width, height)); cpShapeSetFriction(shape, 0.7); } return space; } static void destroy(cpSpace *space) { ChipmunkDemoFreeSpaceChildren(space); cpSpaceFree(space); } ChipmunkDemo Unicycle = { "Unicycle", init, update, ChipmunkDemoDefaultDrawImpl, destroy, };