ode-0.14/0000775000000000000000000000000012635012023010677 5ustar rootrootode-0.14/.hg_archival.txt0000644000000000000000000000017012635011627013772 0ustar rootrootrepo: 5ec20c9e20a4a77b0aa9c21aa4c7a1e1f60978f8 node: a77b1d06e3a62b0116e7d3c4be4c6beaac8726ea branch: default tag: 0.14 ode-0.14/.hgignore0000644000000000000000000000123212635011627012507 0ustar rootrootsyntax: glob *~ *.dll *.la *.lo *.o .deps .libs aclocal.m4 autom4te.cache compile config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh Makefile.in Makefile missing ode.pc ode-config stamp-h1 test-driver # these need to be matched in specific directories ./m4/libtool.m4 ./m4/lt*.m4 drawstuff/dstest/dstest include/ode/precision.h include/ode/version.h libccd/src/ccd/precision.h ou/test/outest tests/tests tests/tests.log tests/tests.trs tests/test-suite.log ode/doc/Doxyfile syntax: regexp # ignore all demo binaries, but not the sources ode/demo/demo_.+\.exe$ ode/demo/demo_[^\.]+$ ode/doc/html/.* ode-0.14/.hgtags0000644000000000000000000000122112635011627012160 0ustar rootroot02323d9c578ea6e8402a4cc94ba83f7b01fdf9da 0.11.1 04753789554b7371c98fbc5b7a57d6c9fee3c77e 0.11 0c6e0b202f5fae5edd153ca07db7bda309120ca4 0.13 11593854d3a22631d4b844ab7623e7e7f356463f 0.10 343c198c9c354109607b851a4ed24a4acb1e82f2 0.5.0 4c5b2efcfe76121081ce91fc3ab2467a1d647ae4 0.0.25 4d088b69715a2322e16b3c151d6ba5488741689f 0.12 5d74d867a1160d5e2710ad6ca741a37302e75444 0.8 89e0edc22deac01374d422bf24b0621957ff8d4d 0.0.35 c528f26e7eb8e95aa14d68e0c76f2acf0bca2ddf 0.0.1 f89ea1ff3fc1b669d5f7b8d8475580b00f28ba9c 0.10.1 f6383a55d1a34cf18200dcc38b19536387cee7f5 0.13.1 4cf81eb385f506785054e0773d94f89eff7484f9 0.13.2 7b0c5226eb9c3090e1b8a63aa202f2d8588fea6b 0.14 ode-0.14/CHANGELOG.txt0000644000000000000000000011477512635011627012755 0ustar rootrootODE CHANGELOG ------------- the rules for this file: * entries are sorted newest-first. * summarize sets of changes - dont reproduce every CVS log comment here. * don't ever delete anything. * keep the format consistent (79 char width, M/D/Y date format). ------------------------------------------------------------------------------ 11/28/2015 Oleh Derevenko * Convex-Trimesh collider added (libccd+GIMPACT only)(by Piotr Piastucki) * dCreateConvex() and dGeomSetConvex() public APIs changed to expect their parameter arrays as const pointers 11/01/2015 Oleh Derevenko * OPCODE mesh colliders' input coordinates have been offset to mesh-relative frames to decrease potential computational errors (suggested by luckytrashsc2@g***l.com) 08/05/2015 Oleh Derevenko * Implemented change to return highest depth contacts subset for GIMPACT in cases if contacts count exceeds requested maximum (as suggested in the issue #36 by Piotr Piastucki) 11/17/2014 Daniel K. O. * Added support for using libccd from the system (if found via pkg-config) 11/10/2014 Oleh Derevenko * Floating point division by zero in capsule-ray collision routine in case if the ray axis was parallel the cylinder and the ray started from within it fixed (issue #26) 11/08/2014 Oleh Derevenko * Threading support has been extended to complete implementation of QuickStep 10/29/2014 Daniel K. O. * Added dJointSetDBallDistance 10/19/2014 Oleh Derevenko * Built-in threading implementation compilation fixed for OSX (clock_gettime() is missing from the system - reported by Bram) 08/10/2014 Oleh Derevenko * Declarations of dWorld[Get/Set]AutoDisableLinearAverageThreshold and dWorld[Get/Set]AutoDisableAngularAverageThreshold have been removed from public headers (were orphaned since rev.1052) 07/16/2014 Oleh Derevenko * Two fixes by Francesco Cat applied (fixes for mistakes made during code style improvements in the past) 02/27/14 Daniel K. O. * Added dODE_VERSION macro to public headers (issue #24). 02/11/14 Daniel K. O. * Added dJointGetHinge2Angle2 (issue #12). 02/07/14 Daniel K. O. * Added dWorldSetData/dWorldGetData (issue #21). 01/31/14 Daniel K. O. * Applied patch #185: Stable, implicit gyroscopic forces. 01/27/14 Daniel K. O. * Fixed cylinder AABB computation. 01/25/14 Daniel K. O. * Removed ALLOCA calls from dHashSpace; it should not depend on stack size limits anymore. 12/06/13 Daniel K. O. * Applied patch #181: fix some bugs in AMotor joint. * Applied patch #186: fix some bugs in PU joint. * Applied patch #182: Transmission joint. * Applied patch #184: implement rolling friction for contacts. 08/08/13 Oleh Derevenko * Joint feedback forces application fixed in QuickStep implementation (was broken since revision #1919 in old repository (#1927 in new one)) 08/04/13 Oleh Derevenko * Bugfix #89 by Luc applied (dJointAddSliderForce() adds a zero force when the parent body is NULL) 05/18/13 Oleh Derevenko * OU library has been included in ODE at revision #46 instead of being used as an external link due to difficulties using external references with new protocol used for storage at SF. 03/03/13 Oleh Derevenko * Fixed issue with "findex==-1" constraints being intermixed with "findex!=-1" ones during constraints random reordering in QuickStep. 02/03/13 Oleh Derevenko * [u]int[8/16/32] renamed to contain "d" prefix so that global namespace was not polluted with these names unconditionally. If your project depended on these types other than just for passing parameters to ODE calls, add similar typedefs for yourself in some of your project's global headers. 01/02/13 Oleh Derevenko * Applied patch #183 by Joseph Cooper (complementary matrix calculation fix). 12/28/12 Oleh Derevenko * A bug with heightfield data assigned to a wrong field in dGeomHeightfieldSetHeightfieldData fixed (bug report #88 by Luc). 12/18/12 Oleh Derevenko * Fixed issue with some kinds of joints (Ball, DBall, DHinge, Fixed) might overwrite world ERP value with their custom ERP during getInfo2() call and that inappropriate value would then be passed to subsequent joints in solver instead of world ERP. 12/01/12 Oleh Derevenko * Fixed issues reported in patches #151 and #22 (collisions with SAPSpace and QuadTreeSpace might not work because geometries list was misused in them). * Applied patch #160 "IsPointInPolygon in convex.cpp returns wrong results" (by Janis Rucis) 11/25/12 Oleh Derevenko * Configuration option --disable-threading-intf added (--no-threading-intf for Windows/Premake). This allows disabling threading interface support (external implementations may not be assigned) but eliminates dependency on OU and use of atomics in steppers. 11/05/12 Oleh Derevenko * Fixed zero comparisons in OPCODE to use relative error instead of absolute epsilon value (found by Bill Sellers) 06/08/12 Daniel K. O. * Removed the need for defining dSINGLE/dDOUBLE; this is stored now in the generated ode/precision.h header. * Some code cleanup to get rid of GCC warnings. 05/30/12 Daniel K. O. * Made drawstuff draw shadows for lines. * Fixed dhinge's last constraint to properly handle rotations. 05/03/12 Daniel K. O. * Added two new joints: Double Ball and Double Hinge. 04/22/12 Daniel K. O. * Fixed plane2d joint: uninitialized variables (reported by Dimitris Papavasiliou) 04/14/12 Oleh Derevenko * Assertion checking macros moved into library private headers. 04/13/12 Daniel K. O. * Applied patch from bug #3431829 - better handling of capsule-box with deep penetrations. * Fixed zero-mu issues: now either mu or mu2 can be set to zero. 03/17/12 Oleh Derevenko * Threaded execution support interface added. Optional built-in threading implementation added. Internal threading implementation is excluded by default and to be used, it must be enabled with configure/premake. At present, if threading interface is assigned to a world, island selection and stepping is performed in multiple threads (one thread per island). 03/12/12 Oleh Derevenko * PURE_INLINE macro renamed to ODE_PURE_INLINE and definition of dNextAfter()/dCopySign() corrected to avoid creating conflicts with other libraries. 02/03/12 Oleh Derevenko * Assertion checking macros moved from common.h to error.h 12/18/11 Oleh Derevenko * dIVERIFY macro added (same as dIASSERT in debug mode but evaluates its expression in release mode) to be used to assert variable value which is not used further in text while avoiding compiler warning. * dICHECK macro added (same as dIASSERT but evaluates its expression and raises assertion fault regardless of compilation mode) to be used to generate a fault in cases when error is very unlikely but must be handled and handling is very troublesome (e.g. failure to lock a mutex due to lack of resources). 12/07/11 Oleh Derevenko * Partially fixed size_t to integer conversion warnings * Fixed type signedness and added casts to size_t wherever necessary in Step/QuickStep 11/04/11 Daniel K. O. * Applied patch #3429454 - fix compilation on some platforms. 10/28/11 Daniel K. O. * Fixed a box-capsule bug: more reasonable normal for deep penetrations (contributed by Georg Martius.) 10/27/11 Daniel K. O. * Disabled merging of contacts for trimesh-sphere by default. * Added new demo: demo_tracks. 10/17/11 Daniel K. O. * Added python bindings, contributed by Gideon Klompje. * Updated some build scripts. * Changed spheres distribution in demo_space_stress. 05/17/11 Oleh Derevenko * A typo in step.cpp fixed (assignment operator in a conditional instead of comparison) (reported by Bram Stolk) 01/29/11 Oleh Derevenko * Heightfield zone boundaries calculation code fixed to also consider whole next cell after the AABB if the AABB ends exactly at the cell boundary. 01/23/11 Daniel K. O. * Applied patch from Daniel Fiser, add libccd collider for box-cylinder. 01/20/11 Daniel K. O. * Applied patch from Daniel Fiser, fix infinite loop in libccd caused by numerical problems. 01/06/11 Daniel K. O. * Applied patch from Daniel Fiser, efficient libccd tests when using CONTACTS_UNIMPORTANT. 12/17/10 Daniel K. O. * Applied patches from Daniel Fiser for new colliders based on libccd. 11/08/10 Daniel K. O. * Applied patches from Daniel Fiser to incorporate libccd for Cylinder-Cylinder collision tests. 08/21/10 Oleh Derevenko * Fix applied to dxReallocateTemporayWorldProcessContext() to remove typo which caused segmentation fault (by Kyle McKay). dTestSolveLCP() fixed to avoid exceeding allocated memory pool (by Kyle McKay). 07/19/10 Oleh Derevenko * Patch applied (#3030783) to fix drawstuff dimensions being ignored in OSX GLUT port (by Danny Price). Daniel K. O. * Applied patch #2991622: dGeomGetRelPointPos, dGeomGetPosRelPoint, dGeomVectorToWorld, and dGeomVectorFromWorld. 07/16/10 Daniel K. O. * Fixed bug #2937076: don't try to build demos if drawstuff is disabled. 05/02/10 Oleh Derevenko * Missing extern "C" wrapper has been added to include/ode/export-dif.h (reported by Danny Price). The change affects dWorldExportDIF() public function. 05/02/10 Oleh Derevenko * Patch applied (#2995450) to generate up to four contacts for box- plane collision test (by alexdu) and fix contact depths. 05/02/10 Oleh Derevenko * dGeomLowLevelControl function added with ability to change/query OPCODE trimesh-sphere contact merging behavior at runtime. 02/18/10 Daniel K. O. * Fixed bug affecting disabled joints and dWorldStep. 01/16/10 Oleh Derevenko * Patch applied (#2931174) to make demos work for recent MacOS. * Patch applied (#2931177) to fix the demos' framerate on X11. 12/20/09 Oleh Derevenko * QuadTreeSpace implementation corrected to avoid object-block relation ambiguity due to numeric errors. 12/04/09 Oleh Derevenko * odecpp classes changed to be inheritable and easily expandable 11/29/09 Oleh Derevenko * Improvement for trimesh-plane collision (also used in trimesh-heightfield) to exclude mesh vertices that have already generated contacts from further examination and contact generation in other triangles (suggested by LR). 10/25/09 Oleh Derevenko * Macros changed to static inline functions in odemath.h and related files. Some code duplication has been eliminated across the files. * Fixed handling of --disable-asserts and --enable-double-precision (absence of --enable-double-precision) in configure script. The script was not appending compiler defines correctly. * dWorldStep implementation changed to remove allocation on stack. dUSE_MALLOC_FOR_ALLOCA define has been removed as well as corresponding configuration parameter. Also dMemoryFlag public variable has been removed. (look for presence of ODE_EXT_malloc_not_alloca configuration string if your application is dependent on that variable). 09/05/09 Oleh Derevenko * dWorldStepFast1 API removed along with dWorld[Get/Set]AutoEnableDepthSF1 08/29/09 Oleh Derevenko * Fixed uninitialized floating point array used in computations. 08/12/09 Oleh Derevenko * A typo fixed in dGeomCopyOffsetRotation() (final_posr was used instead of offset_posr). Reported by Tilmann. 08/11/09 Daniel K. O. * Made sure neither dSINGLE or dDOUBLE is defined by default; the user should always explicitly specify the precision. 06/27/09 Oleh Derevenko * New functions have been added: - dWorldUseSharedWorkingMemory - dWorldCleanupWorkingMemory - dWorldSetStepMemoryReservationPolicy - dWorldSetStepMemoryManager 06/25/09 Remi Ricard (papaDoc) * Add limit to the to the second axis of the universal joint for the pu joint. 06/14/09 Oleh Derevenko * dWorldQuickStep re-implemented to avoid memory allocation on stack. Also several optimizations have been made to decrease memory requirements and optimize algorithm implementation of dWorldQuickStep. dWorldStep still remains with old memory allocation however new APIs mentioned below are fully functional for it. Both dWorldStep and dWorldQuickStep have been changed to return boolean success status. * dInitODE2() changed to automatically call AllocateODEDataForThread(dAllocateFlagBasicData) after library initialization as this is a required initialization minimum that must always be performed anyway. 06/05/09 Daniel K. O. * Removed aliasing issues from OPCODE/Ice, plus some other warnings. Now it builds on gcc 4.3.2 with '-Wall -Werror -O3". 05/30/09 Oleh Derevenko * A minor memory usage optimization for QuickStep. 05/24/09 Daniel K. O. * Made the new trimesh collider the default. * Added a "-texturepath" option to drawstuff. 05/18/09 Oleh Derevenko * Heightfield rotation fixed to avoid NaNs while rotating infinite MIN/MAX heights. 05/03/09 Oleh Derevenko * Incorrect parameter order fixed on contact merging in Sphere-Trimesh collisions. The bug resulted in merged contact remaining with normal of first contact found. Thanks to Dimitris Papavasiliou for reporting. 04/23/09 Daniel K. O. * Fixed bug #2685170: use the C99 __func__ instead of __FUNCTION__ when a C99 implementation is available. 04/07/09 Remi Ricard (papaDoc) * Remove unused code in demo_joints.cpp, reported by Tilmann. 04/07/09 Remi Ricard (papaDoc) * Fix bug in collision categories in demo_jointPU, reported by Tilmann 03/14/09 Oleh Derevenko * A possibility to initialize/close ODE multiple times recursively has been added. Also, now a call to dSpaceSetManualCleanup() is required for each space right after creation if ODE has been initialized in thread data manual cleanup mode. 03/07/09 Oleh Derevenko * Thread local data has been cleaned up from OPCODE and OdeTls as it is not used (OPC_SweepAndPrune.* and OPC_BoxPruning.* have been removed - rebuilding project files is necessary). 02/07/09 Daniel K. O. * New house of cards demo, which stresses the friction handling stability. 01/29/09 Remi Ricard (papaDoc) * Fix bug: Fix problem when attaching no body to a joint. Before calling setRelativeValues a check is made for bodies. * Add unittest 01/28/09 Daniel K. O. * Applied patch #2538046: Heightfield AABB bounds patch. 01/23/09 Remi Ricard (papaDoc) * Add new function dJointSetUniversalAxis1Offset and dJointSetUniversalAxis2Offset * Add unittest for those funcitons. 01/23/09 Remi Ricard (papaDoc) * Fix problem with dJointGetUniversalAngle2 when the joint is attached to only a body 2. The sign was inverted. * Add unit test to verify for this problem 01/21/09 Remi Ricard (papaDoc) * Fix bug reported by Tilman: dxJointPU::getInfo1 was setting twice the limit of limot1 to zero and not limot2 01/17/09 Daniel K. O. * Fixed a bug in dSpaceCollide2: if both geoms are not in spaces they would not have valid AABBs. 12/20/08 Daniel K. O. * New functions: dJointEnable, dJointDisable, dJointIsEnabled (patch #2454764). 12/19/08 Daniel K. O. * Removed inline asm statements that break builds on 64-bit VC++. 12/09/08 Daniel K. O. * Applied patch #2381592, which adds support for Kinematic Bodies. 12/06/08 Oleh Derevenko * Applied a patch by Martijn Buijs to make GIMPACT trimesh-ray collisions to be consistent with those in OPCODE. * Swapped geometries returned in contacts for OPCODE Trimesh-Plane collisions as they were returned in unnatural order being different from that in GIMPACT * Applied a patch by Martijn Buijs to make side1, side2 fields of contact structure be always initialized, either with -1 for non-trmesh geometries or with triangle index for trimeshes. These fields were only assigned for trimesh-trimesh collisions before. * dGeomTriMeshSetTriMergeCallback/dGeomTriMeshGetTriMergeCallback API added to set/get user defined callback procedure for trimeshes that would be invoked when contacts are merged to let user code accumulate attributes of original contact triangles and generate a fake index by which it would later be able to determine those attributes. If the callback is not assigned (the default) -1 is generated as triangle index for merged contacts (there was an index of first of merged triangles before!!!). The callback is currently used within OPCODE trimesh-sphere and OPCODE new trimesh-trimesh collisions. 11/20/08 Remi Ricard (papaDoc) * Fix problem with dJointGetPUPosition and dJointGetPUPositionRate when the joint is attached to only a body 2. The sign was inverted. * Fix bug: When a pu joint had only one body attached to position 2, dJointAttach(jId, 0, bId). The body was not push in the right direction to move back between the limits. * Add unit test to check the above problem * Add the function void dJointSetPUAnchorOffset * Make the function void dJointSetPUAnchorDelta deprecated 11/19/08 Remi Ricard (papaDoc) * Fix bug: When a pr joint had only one body attached to position 2, dJointAttach(jId, 0, bId). The body was not push in the right direction to move back between the limits. * Add unit test to check the above problem 11/19/08 Remi Ricard (papaDoc) * Fix problem with dJointGetPRPosition and dJointGetPRPositionRate when the joint is attached to only a body 2. The sign was inverted. * Add unit test to check the above problem * Increase the tolerance to remove failure in unit test * Remove compilation warning in unit test with the use of REAL() 11/18/08 Remi Ricard (papaDoc) * Fix bug: When a piston joint had only one body attached to position 2, dJointAttach(jId, 0, bId). The body was not push in the right direction to move back between the limits. * Add more functionality to demo_piston.cpp * Run astyle on modified files. 11/18/08 Remi Ricard (papaDoc) * Fix bug: When a slider joint had only one body attached to position 2, dJointAttach(jId, 0, bId). The body was not push in the right direction to move back between the limits. 10/29/08 Oleh Derevenko * Premake scripts changed to only include chosen collision library sources in project on Windows. --all-collis-libs premake option added to allow inclusion of all collision library sources into the project 10/15/08 Remi Ricard (papaDoc) * Applying patch #2158425 64-bit GIMPACT provided by Mark William. This patch enable GIMPACT to works on 64-bit machine. 10/15/08 Remi Ricard (papaDoc) * Add function dJointGetPRAngle and dJointGetPRAngleRate 10/15/08 Remi Ricard (papaDoc) * Enable the motor on the rotoide part of the PR joint 10/15/08 Remi Ricard (papaDoc) * Add unit test to check if using directly a joint or using after setting with default values is the same. * Add function setRelativeValues called in dJointAttach for all joints. 10/10/08 Remi Ricard (papaDoc) * Fix bug in dJointGetPUAxis2. The axis was not multiplied with the the rotation matrix of the good body. * Fix bug if there is only one body on the PU joint the axis returned was not the right one. * Add unit test to verify previous bug. 10/03/08 Rodrigo Hernandez (Kwizatz) * Added Blender script to create ODE convex geoms under tools. 10/01/08 Rodrigo Hernandez (Kwizatz) * Convex-Convex collision detection code is finally stable. 08/31/08 Daniel K. O. * Applied patch 2080674: Improved dBodySetRotation; now exact rotation matrices are preserved until the next simulation step. 08/07/08 Daniel K. O. * Fixed strict aliasing issue that was breaking the new trimesh collider. 07/24/08 Daniel K. O. * New functions: dBodyGetGyroscopicMode and dBodySetGyroscopicMode (patch #2019242). 07/15/08 Remi Ricard (papaDoc) * Add a new define ODE_API_DEPRECATED to mark function as deprecated when necessary. 07/14/08 Remi Ricard (papaDoc) * Finish adding patch 1336066: Joint feedback in quickstep by jsinecky * demo_boxstack.cpp can now print joint feedback 07/11/08 Daniel K. O. * Bumped version for 0.10.1 * Added proper usage of libtool's version info. 07/10/08 Remi Ricard (papaDoc) * Add new function dJointSetPistonAnchorOffset * Add unittest for the piston joint * Fix problem with dJointGetPistonPosition and dJointGetPistonPositionRate when the joint is attached to only a body 2. The sign was inverted. 07/09/08 Remi Ricard (papaDoc) * Optimize function Multiply1_12q1 in quickstep Patch proposed by Riemer v.d. Zee and modified by Patrick Baggett 07/08/08 Remi Ricard (papaDoc) * Update the slider joint to have the same behavior as the other joint when there is only a body2 attached to it. * Update documentation for the slider joint. * Remove warning by using REAL() * Add new unittest for dJointGetSliderPositionRate 07/08/08 Remi Ricard (papaDoc) * Update unittest for the slider. * Rename the new function dJointSetHingeAxisDelta to dJointSetHingeAxisOffset. This remove will remove confusion with the old function dJointSetHingeAnchorDelta * Update documentation for the Hinge unittest * Remove warning by using REAL() 07/07/08 Daniel K. O. * Max Correcting Vel doesn't affect bounciness, as before. 07/03/08 Remi Ricard (papaDoc) * Add new function dJointSetHingeAxisDelta * Add unittest for this new function 06/17/08 Remi Ricard (papaDoc) * Move the computation of the Relative Rotation for the slider joint into a function. * Add unittest for to check qrel 06/17/08 Remi Ricard (papaDoc) * Remove unused variables. * Remove a conversion warning between unsigned int and int 06/17/08 Remi Ricard (papaDoc) * Move the function hingeComputeRelativeRotation as a member of the hinge structure/class. 06/17/08 Remi Ricard (papaDoc) * Move the computation of the Relative Rotation for the fixed joint into a function. 06/16/08 Remi Ricard (papaDoc) * Add testunit for the dxJointFixed 06/04/08 Daniel K. O. * Moved joints to ode/src/joints, converted them to true virtual methods. 06/02/08 Daniel K. O. * Added an Auto template to step.cpp to handle memory deallocation. 05/09/08 Daniel K. O. * Applied patch #1335202: Contact Joint Motion (with some corrections), and added demo_motion. 05/01/08 Oleh Derevenko * Memory leak in GIMPACT fixed (reported by Derek) 04/28/08 Oleh Derevenko * Added possibility to collide a space of lower sublevel as a geometry against another space of a higher level with dSpaceCollide2. dSpaceSetSublevel/dSpaceGetSublevel are used for sublevel assignment/ retrieval. 04/27/08 Oleh Derevenko * Fixed incorrect memory copying which could lead to memory corruption in GIMPACT (luckily, in unused code) * Fixed possible memory read beyond the end of allocated buffer along with unnecessary extra memory copying in GIMPACT. * Fixed buffer reserve being incorrectly reset to zero for bitsets what resulted in unnecessary memory reallocations in GIMPACT. * Implemented support for ability to run collision detection from multiple threads for separate spaces. 04/14/08 Oleh Derevenko * Fixed possible memory corruption in new trimesh-trimesh collider in case if two degenerated triangles are checked against each other. 04/12/08 Oleh Derevenko * Fixed sporadic assertion failure on vector normalization caused by small triangles degenerating into segments during space transformations. 03/28/08 Remi * Fix a bug in dJointXXXGetInfo. The value in limot.limit was not always updated. (Ex: If hi and lo limit were changed). 03/27/08 Remi * Added a new Joint: Prismatic Universal (patch #1828454). Daniel K. O. * Fixed bug #1841309: collide2() method buggy. 03/18/08 Rodrigo * New function: dVector4Copy. 03/14/08 david * Added stub calls for trimesh functions. * Applied patch #1914232: dGetConfiguration. * Applied patch #1655333: Optimize the function dNormalize3. * New function: dSetColliderOverride. * New function: dCheckConfiguration. Daniel K. O. * Disabled building shared library by default with autotools. 03/13/08 david * New function: dJointGetNumBodies (patch #1901550). * New function: dSpaceGetClass (patch #1901637). * Applied patch #1901649: Add missing function in the export 03/12/08 Rodrigo * Fixed drawstuff build issues on OSX. 01/12/08 Daniel K. O. * Fixed a typedef bug in configure.in. * Added dCylinder to the C++ wrappers. * Applied patch 1851394: support for GIMPACT with double precision, dCollide fix. * Moved bunny geometry to bunny_geom.h. 12/11/07 Daniel K. O. * Added damping and MaxAngularVel() functions. * Const-correctness: added const qualifier to some dWorldGet and dBodyGet functions. * Updated the odecpp.h header. 12/07/07 Daniel K. O. * Removed most of the compiler warnings from Drawstuff, ODE and OPCODE * Upgraded automake requirement to 1.10, and change some Makefile.am 12/06/07 Rodrigo * Modified autotools to use libtool for library generation and administration * Removed release and debug flags for configure.in CPPFLAGS, CFLAGS, CXXFLAGS should be set by the user to their liking, respecting autotools policies. 11/30/07 Daniel K. O. * Applied patch 1813079 (moved callback) * Replaced moveAndRotateBody by dxStepBody in stepfast.cpp 11/10/07 david * Added 'Sweep and Prune' collision space. * New Piston joint type with demo, by Remi Ricard * Added build option to use 16-bit indices for OPCODE trimesh 11/03/06 david * Integrated Christoph Beyer's average based sampling system for body disabling. 10/26/06 Francisco Leon * Totally refactored trimesh collision system. Using GIMPACT instead of OPCODE. Now works correctly, and faster. Visit http://gimpact.sourceforge.net. * Finally, test_moving_trimesh.exe works nicely. * Fixed autodisable system. Now is possible to set bigger sleeping threshold values and objects won't be sleeping on the air. They will rest on the floor properly. * dInitODE function added. * Is Obligatory to call dInitODE() at the beginning for initialize ODE, and calling dCloseODE() when the program ends. 09/20/06 bram * Fixed two bugs in cyl/plane collision test. 09/13/06 Remi * New Rotoide - Prismatic joint type * dJointGetUniversalAngles for efficient angle retrieval. 08/09/06 david * Integrated plane2d joint type which constrains bodies to z == 0. 07/06/06 david * Added heightfield primitive collision code. Simple test available in ode/test/test_heightfield 04/03/06 rodrigo * Added Convex primitive collision code, currently only convex-sphere and convex-plane work 04/01/06 bram * Added program to test trimesh vs sphere: ode/test/test_basket 03/20/06 jason379 * Added new autogenerated Visual Studio projects, with Premake scripts 03/17/06 bram * Added plane/cyl intersection test * Renamed CCylinder to Capsule 02/04/06 gcarlton * Added support for geom offsets. 10/26/05 rodrigo * Removed LIBTOOL from autotools since it was not really required. * Added a target to build ODE as a shared library, this shared library gets build alongside the static one, no flags required. 10/24/05 tfautre (Backported patches from STABLE branch, applied by Adam) * dRandInt changed for a non-double all-int version. * mics minor fixes and improvements. 04/05/05 tfautre * Fixed segmentation fault with OPCODE on 64 bits systems. 03/31/05 tfautre * Fixed timer.cpp compiler error on x86-64 using GCC. 03/29/05 colin * Added trimesh preprocessing to mark unneeded edges and verts. Also added support for preprocessed info to the ccylinder-trimesh collider. 12/07/04 adam * Important AMotors bugfix 09/22/04 jeff * Assorted small bugfixes and tweaks for trimesh_{box,ccylinder,trimesh} collisions 09/21/04 jeff * added functions to joint.cpp to allow joint attachment to moving geoms. * added malloc-based memory allocation in step.cpp & lcp.cpp (turned on with a #define switch in common.h) 05/29/04 russ * added joint feedback to the QuickStep solver 05/18/04 russ * added warm starting to the QuickStep solver 05/18/04 russ * added the QuickStep solver * added contact parameter functions. 05/05/04 adam * use dRandInt instead of rand() in stepfast. 04/21/04 russ * added auto-disable support from Aras Pranckevicius (with modifications by russ). this useful feature can speed up simulation significantly in some cases. * various internal tidyups. 04/20/04 russ * changed the meaning of the 'index' argument to dJointGetBody(): it was the only remaining API function that does not respect dJOINT_REVERSE (spotted by Matthew D. Hancher). * updated the C++ headers: fixed two minor bugs and added support for dQuadTreeSpace, dRay, and the dGeom::getSpace() method (from Matthew D. Hancher). 04/18/04 russ * changed the way that the dInfinity constant is implemented: now it is #defined to be one of: FLT_MAX, DBL_MAX, HUGE_VAL, HUGE_VALF, or a large numeric constant. previously it was a variable that was exported from the library. this simplifies the configuration and build process quite a bit, especially in the case of DLLs. * removed the old, deprecated collision system (geom.cpp,space.cpp, geom.h,space.h,odecpp_old_collision.h). the ODE_OLD_COLLISION configuration setting no longer has any meaning. * removed support for dGeomGroups, which have been deprecated for a while and are equivalent to 'spaces' anyway. 04/13/04 russ * bug fix in dMassSetCappedCylinder(), from Matthew D. Hancher. 04/08/04 russ * added trimesh-CCylinder capability, from Vadim Macagon . 04/04/04 adam * yet another rewrite of triangle-box collision code, this time based on code donated by Croteam, ported by asko@jetti.org and tweaked by Erwin. 04/04/04 adam * merged trimesh-trimesh collision code by Jeffrey Smith . * changed it to not break the trimesh interface, fix some GCC compilation problems, bring it up to date with ODE changes from 2003-11-15 -> 2004-04-04. * add ability to drop meshes on meshes in test_moving_trimesh, not as good as it could be but it's illustrative. 01/16/04 adam * implement a bunch of ultra-simple TriMesh functions that were in the headers but not in the code -- patch by Vadim Macagon * disable temporal coherence on trimeshes by default, since it has scaleability issues that don't make it a general clear win. 12/01/03 adam * implement dxHashSpace::collide2(), not particularly efficiently. 11/14/03 adam * applied several Trimesh fixes and improvements from Aras Pranckevicius 10/22/03 adam * apply Nguyen Binh's work for removing many dSetZero() calls and some other extraneous initializations. 07/29/03 martin * added dJointAdd*Torque/Force(). 07/10/03 russ * added the StepFast code, by David Whittaker. 07/02/03 martin * added dMassSet*Total(). 07/01/03 martin * added joint limits and motors to universal joints. * reversed the polarity of the dJOINT_REVERSE flag. 06/30/03 russ * added the TriMesh geom class and the quad tree space to the ODE core. both of these were developed by Erwin de Vries. added OPCODE to the ODE distribution, this is required by TriMesh. 06/23/03 martin * added dGeomSetQuaternion() and dGeomGetQuaternion() * added dJointGet*Anchor2() 05/07/03 russ * added dGeomGetSpace(). 02/05/03 russ * added dMassSetCylinder(). 12/07/02 russ * added dAreConnectedExcluding(). 11/30/02 russ * added the ray geom class. * added the dGeomXXXPointDepth() functions. * added a collision test infrastructure, and some more tests. 11/24/02 russ * added support for multiple box-box contacts. 11/10/02 russ * added new collision system. select between the old/new system by setting the ODE_OLD_COLLISION variable in config/user-settings. 10/28/02 russ * fixed two problems in the LCP code to improve the reliability of the dContactApprox1 contact mode. * added a FAQ question about rolling bodies getting stuck when they hit multiple geoms. 09/08/02 russ * added dClosestLineSegmentPoints(). * implemented dCollideCB(). 08/28/02 russ * added dJointSetFeedback() and dJointGetFeedback(). 08/05/02 russ * added dGeomTransformSetInfo() and dGeomTransformGetInfo(). 07/13/02 russ * added dBodySetForce(), dBodySetTorque(), dWorldImpulseToForce(), dBodyGetPosRelPoint(), dBodyGetPosRelPoint(), dBodyVectorToWorld(), dBodyVectorFromWorld(). * added dBodyGetPointVel() (thanks to Colin Reed). * added a new C++ interface (from Martin C. Martin, with modifications by russ). the old C++ interface is now in odecpp_old.h. 06/25/02 russ * added an additional BSD-style licensing option for ODE. 06/23/02 russ * added dCloseODE(), contributed by Nate Waddoups and David McClurg. 05/16/02 russ * added dSpaceQuery(), contributed by Nate Waddoups. 04/07/02 russ * added a section to the documentation for universal joints. this includes a picture of the joint. 04/05/02 russ * added a universal joint class (generously contributed by Martin C. Martin). it doesn't (yet) have a motor or joint limits, but it does come with tests. 03/11/02 russ * makefile changes to accomodate OSs with command line length limitations (thanks to Norman Lin). 01/06/02 russ * added the dBodySetGravityMode() and dBodyGetGravityMode() functions, which change the dxBodyNoGravity body flag. * added support for building a DLL with MSVC - there is now a msvc-dll target. thanks to Norman Lin for doing this. 12/28/01 russ * added the dParamCFM joint parameter. 12/24/01 russ * reworked the build system to make it more cross-platform. there is now a single top-level makefile and a configurator.c program. see the INSTALL file for details. 12/04/01 russ * the "angular motor" joint has been completed, and a new section has been added to the documentation. 11/26/01 russ * added a new joint type: "angular motor". using this joint is a good way to get ball-joint motors and limits. this is work in progress - it has not been fully implemented or tested yet. 11/22/01 russ * replaced the mmap()-based joint group stack (stack.cpp) with a malloc()-based arena stack (obstack.cpp). this will be more portable and should not impact performance. 11/12/01 russ * changed the meaning of the 'flags' parameter to dCollide() and related functions: now the size of the contact buffer is kept in the lower 16 bits. this change will be backward compatible. * added dBodyGetFiniteRotationMode() and dBodyGetFiniteRotationAxis(). * added dBodyAddForceAtRelPos() function. 11/11/01 russ * added the ability to manually enable and disable bodies. see dBodyEnable(), dBodyDisable(), dBodyIsEnabled(). * fixed a potential bug: when a world is destroyed that contains joints in joint groups, those joints are marked as "deactivated" in the joint group, so when the joint group is destroyed they can be ignored. * the test_boxstack demo has new options to enable and disable bodies. * new configuration parameter in config.h: dEFFICIENT_SIZE. 11/11/01 russ * started the change log for ODE. changes older than today were added to this file by inspecting the CVS logs. 11/05/01 russ * added REAL() constructions for floating point numbers, to prevent many warnings when compiling under VC++. 11/03/01 russ * added geometry transform class, documented composite objects. * added collision rule: no contacts if both geoms on the same body. this is not the best rule, may have to remove this in the future. * new dMassAdd() function. * capped cylinder to capped cylinder collision function. 10/31/01 russ * increase CFM in some demos to make them more robust. 10/29/01 russ * added new accessor functions. 10/19/01 russ * added the dJOINT_TWOBODIES flag to the joint, that says it can not be attached to just one body. 10/12/01 russ * fixed a collision bug in dCollide() that was causing memory corruption when multiple contacts were being returned. 10/11/01 russ * joints can now return m=0 to be "inactive". added a "null" joint to test this. 10/09/01 russ * in the LCP solver, try to fail gracefully when s <= 0. * dAABBTestFn() API change. 10/08/01 russ * fixed a contact swapping bug in dCollide(). 10/07/01 russ * added capped cylinder geometry object. 09/30/01 russ * the test_buggy demo now uses geometry groups. * added a dAABBTestFn field in the geometry classes. 09/29/01 russ * added geometry groups. 09/20/01 russ * added finite rotation stuff. ode-0.14/COPYING0000644000000000000000000000162212635011627011742 0ustar rootrootODE is dual-licensed under either: * GNU Lesser General Public License v 2.1 or later. see LICENSE.TXT * Modified 3-clause BSD license. see LICENSE-BSD.TXT Third-party libraries bundled with ODE: * GIMPACT: dual-licensed under either: - GNU Lesser General Public License v 2.1 or later. see GIMPACT-LICENSE-LGPL.TXT - Modified 3-clause BSD license. see GIMPACT/GIMPACT-LICENSE-BSD.TXT * libccd: Modified 3-clause BSD License see libccd/BSD-LICENSE * OU/ODER: triple-licensed under either: - GNU Lesser General Public License v 3 or later. see ou/LICENSE.TXT see ou/LICENSE-LESSER.TXT - Modified 3-clause BSD license. see ou/LICENSE-BSD.TXT - ZLIB license. see ou/LICENSE-ZLIB.TXT * OPCODE: under the same terms as ODE see OPCODE/COPYING ode-0.14/GIMPACT/0000775000000000000000000000000012635012022011762 5ustar rootrootode-0.14/GIMPACT/GIMPACT-LICENSE-BSD.TXT0000644000000000000000000000310212635011627015141 0ustar rootrootGIMPACT : Geometric tools for VR. Copyright (c) 2006 , Francisco Len. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the GIMPACT nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.ode-0.14/GIMPACT/GIMPACT-LICENSE-LGPL.TXT0000644000000000000000000006346512635011627015311 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ode-0.14/GIMPACT/Makefile.am0000644000000000000000000000012612635011627014025 0ustar rootrootEXTRA_DIST = GIMPACT-LICENSE-BSD.TXT GIMPACT-LICENSE-LGPL.TXT SUBDIRS = include src ode-0.14/GIMPACT/include/0000775000000000000000000000000012635012022013405 5ustar rootrootode-0.14/GIMPACT/include/GIMPACT/0000775000000000000000000000000012635012022014471 5ustar rootrootode-0.14/GIMPACT/include/GIMPACT/Makefile.am0000644000000000000000000000044112635011627016534 0ustar rootrootnoinst_HEADERS = \ gim_boxpruning.h gim_contact.h gim_geometry.h \ gim_math.h gim_memory.h gimpact.h \ gim_radixsort.h gim_tri_capsule_collision.h gim_tri_collision.h \ gim_trimesh.h gim_tri_sphere_collision.h ode-0.14/GIMPACT/include/GIMPACT/gim_boxpruning.h0000644000000000000000000003254112635011627017706 0ustar rootroot#ifndef GIM_BOXPRUNING_H_INCLUDED #define GIM_BOXPRUNING_H_INCLUDED /*! \file gim_boxpruning.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_radixsort.h" #include "GIMPACT/gim_geometry.h" /*! \defgroup BOX_PRUNNING \brief Tools for find overlapping objects on a scenary. These functions sort boxes for faster collisioin queries, using radix sort or quick sort as convenience. See \ref SORTING .
  • For using these collision routines, you must create a \ref GIM_AABB_SET by using this function : \ref gim_aabbset_alloc.
  • The GIM_AABB_SET objects must be updated on their boxes on each query, and they must be update by calling \ref gim_aabbset_update
  • Before calling collision functions, you must create a pair set with \ref GIM_CREATE_PAIR_SET
  • For finding collision pairs on a scene (common space for objects), call \ref gim_aabbset_self_intersections
  • For finding collision pairs between two box sets , call \ref gim_aabbset_box_collision
  • After using collision routines, you must destroy the pairset with \ref GIM_DESTROY_PAIR_SET
  • When the box set is no longer used, you must destroy it by calling \ref gim_aabbset_destroy
*/ //! @{ //! Overlapping pair struct GIM_PAIR { GUINT32 m_index1; GUINT32 m_index2; }; //typedef struct _GIM_PAIR GIM_PAIR; //! Box container struct GIM_AABB_SET { GUINT32 m_count; aabb3f m_global_bound;//!< Global calculated bound of all boxes aabb3f * m_boxes; GUINT32 * m_maxcoords;//!m_sorted_mincoords == 0, then it allocs the sorted coordinates */ void gim_aabbset_sort(GIM_AABB_SET * aabbset, char calc_global_bound); //! log(N) Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. /*! \pre aabbset must be allocated and sorted, the boxes must be already set. \param aabbset Must be sorted. Global bound isn't required \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_self_intersections_sorted(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs); //! NxN Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. /*! \pre aabbset must be allocated, the boxes must be already set. \param aabbset Global bound isn't required. Doen't need to be sorted. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_self_intersections_brute_force(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs); //! log(N) Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. /*! \pre aabbset1 and aabbset2 must be allocated and sorted, the boxes must be already set. \param aabbset1 Must be sorted, Global bound is required. \param aabbset2 Must be sorted, Global bound is required. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_bipartite_intersections_sorted(GIM_AABB_SET * aabbset1, GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs); //! NxM Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. /*! \pre aabbset1 and aabbset2 must be allocated and sorted, the boxes must be already set. \param aabbset1 Must be sorted, Global bound is required. \param aabbset2 Must be sorted, Global bound is required. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_bipartite_intersections_brute_force(GIM_AABB_SET * aabbset1,GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs); /* Brute-Force Vs Sorted pruning Different approaches must be applied when colliding sets with different number of elements. When sets have less of 100 boxes, is often better to apply force brute approach instead of sorted methods, because at lowlevel bruteforce routines gives better perormance and consumes less resources, due of their simplicity. But when sets are larger, the complexiity of bruteforce increases exponencially. In the case of large sets, sorted approach is applied. So GIMPACT has the following strategies: On Sorting sets: !) When sets have more of 140 boxes, the boxes are sorted by its coded min coord and the global box is calculated. But when sets are smaller (less of 140 boxes), Is convenient to apply brute force approach. *******************************************************************************/ //! Constant for apply approaches between brute force and sorted pruning on bipartite queries #define GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES 600 //! Constant for apply approaches between brute force and sorted pruning for box collision #define GIM_MIN_SORTED_PRUNING_BOXES 140 //Use these functions for general initialization //! Initalizes the set. Sort Boxes if needed. /*! \pre aabbset must be allocated. And the boxes must be already set. \post If the set has less of GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES boxes, only calcs the global box, else it Sorts the entire set( Only applicable for large sets) */ void gim_aabbset_update(GIM_AABB_SET * aabbset); ///Use these functions for general collision //! Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. /*! This function sorts the set and then it calls to gim_aabbset_self_intersections_brute_force or gim_aabbset_self_intersections_sorted. This is an example of how to use this function: \code //Create contact list GDYNAMIC_ARRAY collision_pairs; GIM_CREATE_PAIR_SET(collision_pairs); //Do collision gim_aabbset_self_intersections(&aabbset,&collision_pairs); if(collision_pairs.m_size==0) { GIM_DYNARRAY_DESTROY(collision_pairs);// return; //no collisioin } //pair pointer GIM_PAIR *pairs = GIM_DYNARRAY_POINTER(GIM_PAIR,collision_pairs); GUINT i, ti1,ti2; for (i=0;im_count >= GIM_MIN_SORTED_PRUNING_BOXES, then it calls to gim_aabbset_sort and then to gim_aabbset_self_intersections_sorted. Global box won't be calculated. */ void gim_aabbset_self_intersections(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs); //! Collides two sets. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. /*! \pre aabbset1 and aabbset2 must be allocated and updated. See gim_aabbset_update. \param aabbset1 Must be updated. \param aabbset2 Must be updated. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_bipartite_intersections(GIM_AABB_SET * aabbset1, GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs); ///Function for create Box collision result set #define GIM_CREATE_BOXQUERY_LIST(dynarray) GIM_DYNARRAY_CREATE(GUINT32,dynarray,G_ARRAY_GROW_SIZE) //! Finds intersections between a box and a set. Return the colliding boxes of the set /*! \pre aabbset must be allocated and initialized. \param test_aabb Box for collision query \param aabbset Set of boxes .Global bound is required. \param collided Array of GUINT elements, indices of boxes. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_box_collision(aabb3f *test_aabb, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided); //! Finds intersections between a box and a set. Return the colliding boxes of the set /*! \pre aabbset must be allocated and initialized. \param vorigin Origin point of ray. \param vdir Direction vector of ray. \param tmax Max distance param for ray. \param aabbset Set of boxes .Global bound is required. \param collided Array of GUINT elements, indices of boxes. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_ray_collision(vec3f vorigin,vec3f vdir, GREAL tmax, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided); /* For sorting, each box corner must be discretized to a 32 bit integer. For this, we take the x and z coordinates from the box corner (a vector vec3f) Then convert the (x,z) pair to an integer. For convenience, we choose an error constant for converting the coordinates (0.05). *******************************************************************************/ /** For fitting the coordinate to an integer, we need to constraint the range of its values. So each coord component (x, z) must lie between 0 and 65536. 20 give us a 0.05 floating point error */ #define ERROR_AABB 20.0f /** An error of 0.05 allows to make coordinates up to 1638.0f and no less of -1638.0f. So the maximum size of a room should be about 3276x3276 . Its dimensions must lie between [-1638,1638.0f] */ #define MAX_AABB_SIZE 1638.0f //! Converts a vector coordinate to an integer for box sorting /*! \param vx X component \param vz Z component \param uint_key a GUINT */ #define GIM_CONVERT_VEC3F_GUINT_XZ(vx,vz,uint_key)\ {\ GUINT32 _z = ((GUINT32)(vz*ERROR_AABB))+32768;\ uint_key = ((GUINT32)(vx*ERROR_AABB))+32768;\ uint_key = (uint_key<<16) + _z;\ }\ //! Converts a vector coordinate to an integer for box sorting,rounding to the upper int /*! \param vx X component \param vz Z component \param uint_key a GUINT */ #define GIM_CONVERT_VEC3F_GUINT_XZ_UPPER(vx,vz,uint_key)\ {\ GUINT32 _z = ((GUINT32)ceilf(vz*ERROR_AABB))+32768;\ uint_key = ((GUINT32)ceilf(vx*ERROR_AABB))+32768;\ uint_key = (uint_key<<16) + _z;\ }\ //! Converts a vector coordinate to an integer for box sorting. Secure clamped /*! \param vx X component \param vz Z component \param uint_key a GUINT */ #define GIM_CONVERT_VEC3F_GUINT_XZ_CLAMPED(vx,vz,uint_key)\ {\ GREAL _cx = CLAMP(vx,-MAX_AABB_SIZE,MAX_AABB_SIZE);\ GREAL _cz = CLAMP(vz,-MAX_AABB_SIZE,MAX_AABB_SIZE);\ GUINT32 _z = ((GUINT32)(_cz*ERROR_AABB))+32768;\ uint_key = ((GUINT32)(_cx*ERROR_AABB))+32768;\ uint_key = (uint_key<<16) + _z;\ }\ //! Converts a vector coordinate to an integer for box sorting. Secure clamped, rounded /*! \param vx X component \param vz Z component \param uint_key a GUINT */ #define GIM_CONVERT_VEC3F_GUINT_XZ_UPPER_CLAMPED(vx,vz,uint_key)\ {\ GREAL _cx = CLAMP(vx,-MAX_AABB_SIZE,MAX_AABB_SIZE);\ GREAL _cz = CLAMP(vz,-MAX_AABB_SIZE,MAX_AABB_SIZE);\ GUINT32 _z = ((GUINT32)ceilf(_cz*ERROR_AABB))+32768;\ uint_key = ((GUINT32)ceilf(_cx*ERROR_AABB))+32768;\ uint_key = (uint_key<<16) + _z;\ }\ //! @} #endif // GIM_BOXPRUNING_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_contact.h0000644000000000000000000000757412635011627017156 0ustar rootroot#ifndef GIM_CONTACT_H_INCLUDED #define GIM_CONTACT_H_INCLUDED /*! \file gim_contact.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_geometry.h" #include "GIMPACT/gim_radixsort.h" /*! \defgroup CONTACTS \brief Functions for managing and sorting contacts resulting from a collision query.
  • Contact lists must be create by calling \ref GIM_CREATE_CONTACT_LIST
  • After querys, contact lists must be destroy by calling \ref GIM_DYNARRAY_DESTROY
  • Contacts can be merge for avoid duplicate results by calling \ref gim_merge_contacts
*/ //! @{ /// Structure for collision results struct GIM_CONTACT { vec3f m_point; vec3f m_normal; GREAL m_depth;//Positive value indicates interpenetration void * m_handle1; void * m_handle2; GUINT32 m_feature1;//Face number GUINT32 m_feature2;//Face number }; //typedef struct _GIM_CONTACT GIM_CONTACT; #define CONTACT_DIFF_EPSILON 0.00001f #define GIM_CALC_KEY_CONTACT(pos,hash)\ {\ GINT32 _coords[] = {(GINT32)(pos[0]*1000.0f+1.0f),(GINT32)(pos[1]*1333.0f),(GINT32)(pos[2]*2133.0f+3.0f)};\ GUINT32 _hash=0;\ GUINT32 *_uitmp = (GUINT32 *)(&_coords[0]);\ _hash = *_uitmp;\ _uitmp++;\ _hash += (*_uitmp)<<4;\ _uitmp++;\ _hash += (*_uitmp)<<8;\ hash = _hash;\ }\ ///Creates a contact list for queries #define GIM_CREATE_CONTACT_LIST(contact_array) GIM_DYNARRAY_CREATE(GIM_CONTACT,contact_array,100) #define GIM_PUSH_CONTACT(contact_array, point, normal, deep,handle1, handle2, feat1, feat2)\ {\ GIM_DYNARRAY_PUSH_EMPTY(GIM_CONTACT,contact_array);\ GIM_CONTACT * _last = GIM_DYNARRAY_POINTER_LAST(GIM_CONTACT,contact_array);\ VEC_COPY(_last->m_point,point);\ VEC_COPY(_last->m_normal,normal);\ _last->m_depth = deep;\ _last->m_handle1 = handle1;\ _last->m_handle2 = handle2;\ _last->m_feature1 = feat1;\ _last->m_feature2 = feat2;\ }\ ///Receive pointer to contacts #define GIM_COPY_CONTACTS(dest_contact, source_contact)\ {\ VEC_COPY(dest_contact->m_point,source_contact->m_point);\ VEC_COPY(dest_contact->m_normal,source_contact->m_normal);\ dest_contact->m_depth = source_contact->m_depth;\ dest_contact->m_handle1 = source_contact->m_handle1;\ dest_contact->m_handle2 = source_contact->m_handle2;\ dest_contact->m_feature1 = source_contact->m_feature1;\ dest_contact->m_feature2 = source_contact->m_feature2;\ }\ //! Merges duplicate contacts with minimum depth criterion void gim_merge_contacts(GDYNAMIC_ARRAY * source_contacts, GDYNAMIC_ARRAY * dest_contacts); //! Merges to an unique contact void gim_merge_contacts_unique(GDYNAMIC_ARRAY * source_contacts, GDYNAMIC_ARRAY * dest_contacts); //! @} #endif // GIM_CONTACT_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_geometry.h0000644000000000000000000013416512635011627017353 0ustar rootroot#ifndef GIM_VECTOR_H_INCLUDED #define GIM_VECTOR_H_INCLUDED /*! \file gim_geometry.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_math.h" /*! \defgroup GEOMETRIC_TYPES \brief Basic types and constants for geometry */ //! @{ //! Integer vector 2D typedef GINT32 vec2i[2]; //! Integer vector 3D typedef GINT32 vec3i[3]; //! Integer vector 4D typedef GINT32 vec4i[4]; //! Float vector 2D typedef GREAL vec2f[2]; //! Float vector 3D typedef GREAL vec3f[3]; //! Float vector 4D typedef GREAL vec4f[4]; //! Matrix 2D, row ordered typedef GREAL mat2f[2][2]; //! Matrix 3D, row ordered typedef GREAL mat3f[3][3]; //! Matrix 4D, row ordered typedef GREAL mat4f[4][4]; //! Quaternion typedef GREAL quatf[4]; //! Axis aligned box struct aabb3f{ GREAL minX; GREAL maxX; GREAL minY; GREAL maxY; GREAL minZ; GREAL maxZ; }; //typedef struct _aabb3f aabb3f; //! @} /*! \defgroup VECTOR_OPERATIONS Operations for vectors : vec2f,vec3f and vec4f */ //! @{ //! Zero out a 2D vector #define VEC_ZERO_2(a) \ { \ (a)[0] = (a)[1] = 0.0f; \ }\ //! Zero out a 3D vector #define VEC_ZERO(a) \ { \ (a)[0] = (a)[1] = (a)[2] = 0.0f; \ }\ /// Zero out a 4D vector #define VEC_ZERO_4(a) \ { \ (a)[0] = (a)[1] = (a)[2] = (a)[3] = 0.0f; \ }\ /// Vector copy #define VEC_COPY_2(b,a) \ { \ (b)[0] = (a)[0]; \ (b)[1] = (a)[1]; \ }\ /// Copy 3D vector #define VEC_COPY(b,a) \ { \ (b)[0] = (a)[0]; \ (b)[1] = (a)[1]; \ (b)[2] = (a)[2]; \ }\ /// Copy 4D vector #define VEC_COPY_4(b,a) \ { \ (b)[0] = (a)[0]; \ (b)[1] = (a)[1]; \ (b)[2] = (a)[2]; \ (b)[3] = (a)[3]; \ }\ /// Vector difference #define VEC_DIFF_2(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] - (v1)[0]; \ (v21)[1] = (v2)[1] - (v1)[1]; \ }\ /// Vector difference #define VEC_DIFF(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] - (v1)[0]; \ (v21)[1] = (v2)[1] - (v1)[1]; \ (v21)[2] = (v2)[2] - (v1)[2]; \ }\ /// Vector difference #define VEC_DIFF_4(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] - (v1)[0]; \ (v21)[1] = (v2)[1] - (v1)[1]; \ (v21)[2] = (v2)[2] - (v1)[2]; \ (v21)[3] = (v2)[3] - (v1)[3]; \ }\ /// Vector sum #define VEC_SUM_2(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] + (v1)[0]; \ (v21)[1] = (v2)[1] + (v1)[1]; \ }\ /// Vector sum #define VEC_SUM(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] + (v1)[0]; \ (v21)[1] = (v2)[1] + (v1)[1]; \ (v21)[2] = (v2)[2] + (v1)[2]; \ }\ /// Vector sum #define VEC_SUM_4(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] + (v1)[0]; \ (v21)[1] = (v2)[1] + (v1)[1]; \ (v21)[2] = (v2)[2] + (v1)[2]; \ (v21)[3] = (v2)[3] + (v1)[3]; \ }\ /// scalar times vector #define VEC_SCALE_2(c,a,b) \ { \ (c)[0] = (a)*(b)[0]; \ (c)[1] = (a)*(b)[1]; \ }\ /// scalar times vector #define VEC_SCALE(c,a,b) \ { \ (c)[0] = (a)*(b)[0]; \ (c)[1] = (a)*(b)[1]; \ (c)[2] = (a)*(b)[2]; \ }\ /// scalar times vector #define VEC_SCALE_4(c,a,b) \ { \ (c)[0] = (a)*(b)[0]; \ (c)[1] = (a)*(b)[1]; \ (c)[2] = (a)*(b)[2]; \ (c)[3] = (a)*(b)[3]; \ }\ /// accumulate scaled vector #define VEC_ACCUM_2(c,a,b) \ { \ (c)[0] += (a)*(b)[0]; \ (c)[1] += (a)*(b)[1]; \ }\ /// accumulate scaled vector #define VEC_ACCUM(c,a,b) \ { \ (c)[0] += (a)*(b)[0]; \ (c)[1] += (a)*(b)[1]; \ (c)[2] += (a)*(b)[2]; \ }\ /// accumulate scaled vector #define VEC_ACCUM_4(c,a,b) \ { \ (c)[0] += (a)*(b)[0]; \ (c)[1] += (a)*(b)[1]; \ (c)[2] += (a)*(b)[2]; \ (c)[3] += (a)*(b)[3]; \ }\ /// Vector dot product #define VEC_DOT_2(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1]) /// Vector dot product #define VEC_DOT(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2]) /// Vector dot product #define VEC_DOT_4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3]) /// vector impact parameter (squared) #define VEC_IMPACT_SQ(bsq,direction,position) {\ GREAL _llel_ = VEC_DOT(direction, position);\ bsq = VEC_DOT(position, position) - _llel_*_llel_;\ }\ /// vector impact parameter #define VEC_IMPACT(bsq,direction,position) {\ VEC_IMPACT_SQ(bsq,direction,position); \ GIM_SQRT(bsq,bsq); \ }\ /// Vector length #define VEC_LENGTH_2(a,l)\ {\ GREAL _pp = VEC_DOT_2(a,a);\ GIM_SQRT(_pp,l);\ }\ /// Vector length #define VEC_LENGTH(a,l)\ {\ GREAL _pp = VEC_DOT(a,a);\ GIM_SQRT(_pp,l);\ }\ /// Vector length #define VEC_LENGTH_4(a,l)\ {\ GREAL _pp = VEC_DOT_4(a,a);\ GIM_SQRT(_pp,l);\ }\ /// Vector inv length #define VEC_INV_LENGTH_2(a,l)\ {\ GREAL _pp = VEC_DOT_2(a,a);\ GIM_INV_SQRT(_pp,l);\ }\ /// Vector inv length #define VEC_INV_LENGTH(a,l)\ {\ GREAL _pp = VEC_DOT(a,a);\ GIM_INV_SQRT(_pp,l);\ }\ /// Vector inv length #define VEC_INV_LENGTH_4(a,l)\ {\ GREAL _pp = VEC_DOT_4(a,a);\ GIM_INV_SQRT(_pp,l);\ }\ /// distance between two points #define VEC_DISTANCE(_len,_va,_vb) {\ vec3f _tmp_; \ VEC_DIFF(_tmp_, _vb, _va); \ VEC_LENGTH(_tmp_,_len); \ }\ /// Vector length #define VEC_CONJUGATE_LENGTH(a,l)\ {\ GREAL _pp = 1.0 - a[0]*a[0] - a[1]*a[1] - a[2]*a[2];\ GIM_SQRT(_pp,l);\ }\ /// Vector length #define VEC_NORMALIZE(a) { \ GREAL len;\ VEC_INV_LENGTH(a,len); \ if(len Last column is added as the position */ #define MAT_DOT_VEC_3X4(p,m,v) \ { \ p[0] = m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]*v[2] + m[0][3]; \ p[1] = m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]*v[2] + m[1][3]; \ p[2] = m[2][0]*v[0] + m[2][1]*v[1] + m[2][2]*v[2] + m[2][3]; \ }\ /*! vector transpose times matrix */ /*! p[j] = v[0]*m[0][j] + v[1]*m[1][j] + v[2]*m[2][j]; */ #define VEC_DOT_MAT_3X3(p,v,m) \ { \ p[0] = v[0]*m[0][0] + v[1]*m[1][0] + v[2]*m[2][0]; \ p[1] = v[0]*m[0][1] + v[1]*m[1][1] + v[2]*m[2][1]; \ p[2] = v[0]*m[0][2] + v[1]*m[1][2] + v[2]*m[2][2]; \ }\ /*! affine matrix times vector */ /** The matrix is assumed to be an affine matrix, with last two * entries representing a translation */ #define MAT_DOT_VEC_2X3(p,m,v) \ { \ p[0] = m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]; \ p[1] = m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]; \ }\ /** inverse transpose of matrix times vector * * This macro computes inverse transpose of matrix m, * and multiplies vector v into it, to yeild vector p * * DANGER !!! Do Not use this on normal vectors!!! * It will leave normals the wrong length !!! * See macro below for use on normals. */ #define INV_TRANSP_MAT_DOT_VEC_2X2(p,m,v) \ { \ GREAL det; \ \ det = m[0][0]*m[1][1] - m[0][1]*m[1][0]; \ p[0] = m[1][1]*v[0] - m[1][0]*v[1]; \ p[1] = - m[0][1]*v[0] + m[0][0]*v[1]; \ \ /* if matrix not singular, and not orthonormal, then renormalize */ \ if ((det!=1.0f) && (det != 0.0f)) { \ det = 1.0f / det; \ p[0] *= det; \ p[1] *= det; \ } \ }\ /** transform normal vector by inverse transpose of matrix * and then renormalize the vector * * This macro computes inverse transpose of matrix m, * and multiplies vector v into it, to yeild vector p * Vector p is then normalized. */ #define NORM_XFORM_2X2(p,m,v) \ { \ double len; \ \ /* do nothing if off-diagonals are zero and diagonals are \ * equal */ \ if ((m[0][1] != 0.0) || (m[1][0] != 0.0) || (m[0][0] != m[1][1])) { \ p[0] = m[1][1]*v[0] - m[1][0]*v[1]; \ p[1] = - m[0][1]*v[0] + m[0][0]*v[1]; \ \ len = p[0]*p[0] + p[1]*p[1]; \ GIM_INV_SQRT(len,len); \ p[0] *= len; \ p[1] *= len; \ } else { \ VEC_COPY_2 (p, v); \ } \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define OUTER_PRODUCT_2X2(m,v,t) \ { \ m[0][0] = v[0] * t[0]; \ m[0][1] = v[0] * t[1]; \ \ m[1][0] = v[1] * t[0]; \ m[1][1] = v[1] * t[1]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define OUTER_PRODUCT_3X3(m,v,t) \ { \ m[0][0] = v[0] * t[0]; \ m[0][1] = v[0] * t[1]; \ m[0][2] = v[0] * t[2]; \ \ m[1][0] = v[1] * t[0]; \ m[1][1] = v[1] * t[1]; \ m[1][2] = v[1] * t[2]; \ \ m[2][0] = v[2] * t[0]; \ m[2][1] = v[2] * t[1]; \ m[2][2] = v[2] * t[2]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define OUTER_PRODUCT_4X4(m,v,t) \ { \ m[0][0] = v[0] * t[0]; \ m[0][1] = v[0] * t[1]; \ m[0][2] = v[0] * t[2]; \ m[0][3] = v[0] * t[3]; \ \ m[1][0] = v[1] * t[0]; \ m[1][1] = v[1] * t[1]; \ m[1][2] = v[1] * t[2]; \ m[1][3] = v[1] * t[3]; \ \ m[2][0] = v[2] * t[0]; \ m[2][1] = v[2] * t[1]; \ m[2][2] = v[2] * t[2]; \ m[2][3] = v[2] * t[3]; \ \ m[3][0] = v[3] * t[0]; \ m[3][1] = v[3] * t[1]; \ m[3][2] = v[3] * t[2]; \ m[3][3] = v[3] * t[3]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define ACCUM_OUTER_PRODUCT_2X2(m,v,t) \ { \ m[0][0] += v[0] * t[0]; \ m[0][1] += v[0] * t[1]; \ \ m[1][0] += v[1] * t[0]; \ m[1][1] += v[1] * t[1]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define ACCUM_OUTER_PRODUCT_3X3(m,v,t) \ { \ m[0][0] += v[0] * t[0]; \ m[0][1] += v[0] * t[1]; \ m[0][2] += v[0] * t[2]; \ \ m[1][0] += v[1] * t[0]; \ m[1][1] += v[1] * t[1]; \ m[1][2] += v[1] * t[2]; \ \ m[2][0] += v[2] * t[0]; \ m[2][1] += v[2] * t[1]; \ m[2][2] += v[2] * t[2]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define ACCUM_OUTER_PRODUCT_4X4(m,v,t) \ { \ m[0][0] += v[0] * t[0]; \ m[0][1] += v[0] * t[1]; \ m[0][2] += v[0] * t[2]; \ m[0][3] += v[0] * t[3]; \ \ m[1][0] += v[1] * t[0]; \ m[1][1] += v[1] * t[1]; \ m[1][2] += v[1] * t[2]; \ m[1][3] += v[1] * t[3]; \ \ m[2][0] += v[2] * t[0]; \ m[2][1] += v[2] * t[1]; \ m[2][2] += v[2] * t[2]; \ m[2][3] += v[2] * t[3]; \ \ m[3][0] += v[3] * t[0]; \ m[3][1] += v[3] * t[1]; \ m[3][2] += v[3] * t[2]; \ m[3][3] += v[3] * t[3]; \ }\ /** determinant of matrix * * Computes determinant of matrix m, returning d */ #define DETERMINANT_2X2(d,m) \ { \ d = m[0][0] * m[1][1] - m[0][1] * m[1][0]; \ }\ /** determinant of matrix * * Computes determinant of matrix m, returning d */ #define DETERMINANT_3X3(d,m) \ { \ d = m[0][0] * (m[1][1]*m[2][2] - m[1][2] * m[2][1]); \ d -= m[0][1] * (m[1][0]*m[2][2] - m[1][2] * m[2][0]); \ d += m[0][2] * (m[1][0]*m[2][1] - m[1][1] * m[2][0]); \ }\ /** i,j,th cofactor of a 4x4 matrix * */ #define COFACTOR_4X4_IJ(fac,m,i,j) \ { \ int __ii[4], __jj[4], __k; \ \ for (__k=0; __k (aabb2).maxX ||\ (aabb1).maxX < (aabb2).minX ||\ (aabb1).minY > (aabb2).maxY ||\ (aabb1).maxY < (aabb2).minY ||\ (aabb1).minZ > (aabb2).maxZ ||\ (aabb1).maxZ < (aabb2).minZ )\ {\ intersected = 0;\ }\ }\ #define AXIS_INTERSECT(min,max, a, d,tfirst, tlast,is_intersected) {\ if(IS_ZERO(d))\ {\ is_intersected = !(a < min || a > max);\ }\ else\ {\ GREAL a0, a1;\ a0 = (min - a) / (d);\ a1 = (max - a) / (d);\ if(a0 > a1) SWAP_NUMBERS(a0, a1);\ tfirst = MAX(a0, tfirst);\ tlast = MIN(a1, tlast);\ if (tlast < tfirst)\ {\ is_intersected = 0;\ }\ else\ {\ is_intersected = 1;\ }\ }\ }\ /*! \brief Finds the Ray intersection parameter. \param aabb Aligned box \param vorigin A vec3f with the origin of the ray \param vdir A vec3f with the direction of the ray \param tparam Output parameter \param tmax Max lenght of the ray \param is_intersected 1 if the ray collides the box, else false */ #define BOX_INTERSECTS_RAY(aabb, vorigin, vdir, tparam, tmax,is_intersected) { \ GREAL _tfirst = 0.0f, _tlast = tmax;\ AXIS_INTERSECT(aabb.minX,aabb.maxX,vorigin[0], vdir[0], _tfirst, _tlast,is_intersected);\ if(is_intersected)\ {\ AXIS_INTERSECT(aabb.minY,aabb.maxY,vorigin[1], vdir[1], _tfirst, _tlast,is_intersected);\ }\ if(is_intersected)\ {\ AXIS_INTERSECT(aabb.minZ,aabb.maxZ,vorigin[2], vdir[2], _tfirst, _tlast,is_intersected);\ }\ tparam = _tfirst;\ }\ #define AABB_PROJECTION_INTERVAL(aabb,direction, vmin, vmax)\ {\ GREAL _center[] = {(aabb.minX + aabb.maxX)*0.5f, (aabb.minY + aabb.maxY)*0.5f, (aabb.minZ + aabb.maxZ)*0.5f};\ \ GREAL _extend[] = {aabb.maxX-_center[0],aabb.maxY-_center[1],aabb.maxZ-_center[2]};\ GREAL _fOrigin = VEC_DOT(direction,_center);\ GREAL _fMaximumExtent = _extend[0]*fabsf(direction[0]) + \ _extend[1]*fabsf(direction[1]) + \ _extend[2]*fabsf(direction[2]); \ \ vmin = _fOrigin - _fMaximumExtent; \ vmax = _fOrigin + _fMaximumExtent; \ }\ /*! classify values:
  1. 0 : In back of plane
  2. 1 : Spanning
  3. 2 : In front of
*/ #define PLANE_CLASSIFY_BOX(plane,aabb,classify)\ {\ GREAL _fmin,_fmax; \ AABB_PROJECTION_INTERVAL(aabb,plane, _fmin, _fmax); \ if(plane[3] >= _fmax) \ { \ classify = 0;/*In back of*/ \ } \ else \ { \ if(plane[3]+0.000001f>=_fmin) \ { \ classify = 1;/*Spanning*/ \ } \ else \ { \ classify = 2;/*In front of*/ \ } \ } \ }\ //! @} /*! \defgroup GEOMETRIC_OPERATIONS */ //! @{ #define PLANEDIREPSILON 0.0000001f #define PARALELENORMALS 0.000001f #define TRIANGLE_NORMAL(v1,v2,v3,n){\ vec3f _dif1,_dif2; \ VEC_DIFF(_dif1,v2,v1); \ VEC_DIFF(_dif2,v3,v1); \ VEC_CROSS(n,_dif1,_dif2); \ VEC_NORMALIZE(n); \ }\ /// plane is a vec4f #define TRIANGLE_PLANE(v1,v2,v3,plane) {\ TRIANGLE_NORMAL(v1,v2,v3,plane);\ plane[3] = VEC_DOT(v1,plane);\ }\ /// Calc a plane from an edge an a normal. plane is a vec4f #define EDGE_PLANE(e1,e2,n,plane) {\ vec3f _dif; \ VEC_DIFF(_dif,e2,e1); \ VEC_CROSS(plane,_dif,n); \ VEC_NORMALIZE(plane); \ plane[3] = VEC_DOT(e1,plane);\ }\ #define DISTANCE_PLANE_POINT(plane,point) (VEC_DOT(plane,point) - plane[3]) #define PROJECT_POINT_PLANE(point,plane,projected) {\ GREAL _dis;\ _dis = DISTANCE_PLANE_POINT(plane,point);\ VEC_SCALE(projected,-_dis,plane);\ VEC_SUM(projected,projected,point); \ }\ #define POINT_IN_HULL(point,planes,plane_count,outside)\ {\ GREAL _dis;\ outside = 0;\ GUINT32 _i = 0;\ do\ {\ _dis = DISTANCE_PLANE_POINT(planes[_i],point);\ if(_dis>0.0f) outside = 1;\ _i++;\ }while(_i
  • 0 : Segment in front of plane, s1 closest
  • 1 : Segment in front of plane, s2 closest
  • 2 : Segment in back of plane, s1 closest
  • 3 : Segment in back of plane, s2 closest
  • 4 : Segment collides plane, s1 in back
  • 5 : Segment collides plane, s2 in back */ #define PLANE_CLIP_SEGMENT2(s1,s2,plane,clipped,intersection_type) \ {\ GREAL _dis1,_dis2;\ _dis1 = DISTANCE_PLANE_POINT(plane,s1);\ _dis2 = DISTANCE_PLANE_POINT(plane,s2);\ if(_dis1 >-G_EPSILON && _dis2 >-G_EPSILON)\ {\ if(_dis1<_dis2) intersection_type = 0;\ else intersection_type = 1;\ }\ else if(_dis1 _dis2) intersection_type = 2;\ else intersection_type = 3; \ }\ else\ {\ if(_dis1<_dis2) intersection_type = 4;\ else intersection_type = 5;\ VEC_DIFF(clipped,s2,s1);\ _dis2 = VEC_DOT(clipped,plane);\ VEC_SCALE(clipped,-_dis1/_dis2,clipped);\ VEC_SUM(clipped,clipped,s1); \ }\ }\ //! Confirms if the plane intersect the edge or not /*! clipped1 and clipped2 are the vertices behind the plane. clipped1 is the closest intersection_type must have the following values
    • 0 : Segment in front of plane, s1 closest
    • 1 : Segment in front of plane, s2 closest
    • 2 : Segment in back of plane, s1 closest
    • 3 : Segment in back of plane, s2 closest
    • 4 : Segment collides plane, s1 in back
    • 5 : Segment collides plane, s2 in back
    */ #define PLANE_CLIP_SEGMENT_CLOSEST(s1,s2,plane,clipped1,clipped2,intersection_type)\ {\ PLANE_CLIP_SEGMENT2(s1,s2,plane,clipped1,intersection_type);\ if(intersection_type == 0)\ {\ VEC_COPY(clipped1,s1);\ VEC_COPY(clipped2,s2);\ }\ else if(intersection_type == 1)\ {\ VEC_COPY(clipped1,s2);\ VEC_COPY(clipped2,s1);\ }\ else if(intersection_type == 2)\ {\ VEC_COPY(clipped1,s1);\ VEC_COPY(clipped2,s2);\ }\ else if(intersection_type == 3)\ {\ VEC_COPY(clipped1,s2);\ VEC_COPY(clipped2,s1);\ }\ else if(intersection_type == 4)\ { \ VEC_COPY(clipped2,s1);\ }\ else if(intersection_type == 5)\ { \ VEC_COPY(clipped2,s2);\ }\ }\ //! Finds the 2 smallest cartesian coordinates of a plane normal #define PLANE_MINOR_AXES(plane, i0, i1)\ {\ GREAL A[] = {fabs(plane[0]),fabs(plane[1]),fabs(plane[2])};\ if(A[0]>A[1])\ {\ if(A[0]>A[2])\ {\ i0=1; /* A[0] is greatest */ \ i1=2;\ }\ else \ {\ i0=0; /* A[2] is greatest */ \ i1=1; \ }\ }\ else /* A[0]<=A[1] */ \ {\ if(A[2]>A[1]) \ { \ i0=0; /* A[2] is greatest */ \ i1=1; \ }\ else \ {\ i0=0; /* A[1] is greatest */ \ i1=2; \ }\ } \ }\ //! Ray plane collision #define RAY_PLANE_COLLISION(plane,vDir,vPoint,pout,tparam,does_intersect)\ {\ GREAL _dis,_dotdir; \ _dotdir = VEC_DOT(plane,vDir);\ if(_dotdir1.0f)\ {\ VEC_COPY(cp,e2);\ }\ else \ {\ VEC_SCALE(cp,_scalar,_n);\ VEC_SUM(cp,cp,e1);\ } \ }\ /*! \brief Finds the line params where these lines intersect. \param dir1 Direction of line 1 \param point1 Point of line 1 \param dir2 Direction of line 2 \param point2 Point of line 2 \param t1 Result Parameter for line 1 \param t2 Result Parameter for line 2 \param dointersect 0 if the lines won't intersect, else 1 */ #define LINE_INTERSECTION_PARAMS(dir1,point1, dir2, point2,t1,t2,dointersect) {\ GREAL det;\ GREAL e1e1 = VEC_DOT(dir1,dir1);\ GREAL e1e2 = VEC_DOT(dir1,dir2);\ GREAL e2e2 = VEC_DOT(dir2,dir2);\ vec3f p1p2;\ VEC_DIFF(p1p2,point1,point2);\ GREAL p1p2e1 = VEC_DOT(p1p2,dir1);\ GREAL p1p2e2 = VEC_DOT(p1p2,dir2);\ det = e1e2*e1e2 - e1e1*e2e2;\ if(IS_ZERO(det))\ {\ dointersect = 0;\ }\ else\ {\ t1 = (e1e2*p1p2e2 - e2e2*p1p2e1)/det;\ t2 = (e1e1*p1p2e2 - e1e2*p1p2e1)/det;\ dointersect = 1;\ }\ }\ //! Find closest points on segments #define SEGMENT_COLLISION(vA1,vA2,vB1,vB2,vPointA,vPointB)\ {\ vec3f _AD,_BD,_N;\ vec4f _M;\ VEC_DIFF(_AD,vA2,vA1);\ VEC_DIFF(_BD,vB2,vB1);\ VEC_CROSS(_N,_AD,_BD);\ VEC_CROSS(_M,_N,_BD);\ _M[3] = VEC_DOT(_M,vB1);\ float _tp; \ LINE_PLANE_COLLISION(_M,_AD,vA1,vPointA,_tp,0.0f, 1.0f);\ /*Closest point on segment*/ \ VEC_DIFF(vPointB,vPointA,vB1);\ _tp = VEC_DOT(vPointB, _BD); \ _tp/= VEC_DOT(_BD, _BD); \ _tp = CLAMP(_tp,0.0f,1.0f); \ VEC_SCALE(vPointB,_tp,_BD);\ VEC_SUM(vPointB,vPointB,vB1);\ }\ //! @} ///Additional Headers for Collision #include "GIMPACT/gim_tri_collision.h" #include "GIMPACT/gim_tri_sphere_collision.h" #include "GIMPACT/gim_tri_capsule_collision.h" #endif // GIM_VECTOR_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_math.h0000644000000000000000000001022612635011627016440 0ustar rootroot#ifndef GIM_MATH_H_INCLUDED #define GIM_MATH_H_INCLUDED /*! \file gim_math.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "config.h" #include #include #if HAVE_SYS_TYPES_H #include #elif defined(_MSC_VER) typedef __int32 int32_t; typedef unsigned __int32 uint32_t; #elif defined(__GNUC__) #include #else #error "GIMPACT: Must define int32_t and uint32_t" #endif /*! \defgroup BASIC_TYPES Basic types and constants Conventions: Types starting with G Constants starting with G_ */ //! @{ /*! Types */ #define GREAL float #define GINT32 int32_t #define GUINT32 uint32_t #ifdef GPTR #undef GPTR #endif #define GPTR void* /*! Constants for integers*/ #define GUINT32_BIT_COUNT 32 #define GUINT32_EXPONENT 5 #define G_FASTMATH 1 #define G_PI 3.14159265358979f #define G_HALF_PI 1.5707963f //267948966 #define G_TWO_PI 6.28318530f //71795864 #define G_ROOT3 1.73205f #define G_ROOT2 1.41421f #define G_UINT_INFINITY 65534 #define G_REAL_INFINITY FLT_MAX #define G_SIGN_BITMASK 0x80000000 #define G_USE_EPSILON_TEST #define G_EPSILON 0.0000001f //! @} /*! \defgroup MATH_FUNCTIONS mathematical functions */ //! @{ #define G_DEGTORAD(X) ((X)*3.1415926f/180.0f) #define G_RADTODEG(X) ((X)*180.0f/3.1415926f) //! Integer representation of a floating-point value. #define IR(x) ((GUINT32&)(x)) //! Signed integer representation of a floating-point value. #define SIR(x) ((GINT32&)(x)) //! Absolute integer representation of a floating-point value #define AIR(x) (IR(x)&0x7fffffff) //! Floating-point representation of an integer value. #define FR(x) ((GREAL&)(x)) #define MAX(a,b) ((a)<(b)?(b):(a)) #define MIN(a,b) ((a)>(b)?(b):(a)) #define MAX3(a,b,c) MAX(a,MAX(b,c)) #define MIN3(a,b,c) MIN(a,MIN(b,c)) #define IS_ZERO(value) ((value) < G_EPSILON && (value) > -G_EPSILON) #define IS_NEGATIVE(value) ((value) <= -G_EPSILON) #define IS_POSISITVE(value) ((value) >= G_EPSILON) ///returns a clamped number #define CLAMP(number,minval,maxval) ((number)<(minval)?(minval):((number)>(maxval)?(maxval):(number))) ///Swap numbers #define SWAP_NUMBERS(a,b){ \ (a) = (a)+(b); \ (b) = (a)-(b); \ (a) = (a)-(b); \ }\ #define GIM_INV_SQRT(va,isva)\ {\ if((va)<=0.0000001f)\ {\ (isva) = G_REAL_INFINITY;\ }\ else\ {\ GREAL _x = (va) * 0.5f;\ GUINT32 _y = 0x5f3759df - ( IR(va) >> 1);\ (isva) = FR(_y);\ (isva) = (isva) * ( 1.5f - ( _x * (isva) * (isva) ) );\ }\ }\ #define GIM_SQRT(va,sva)\ {\ GIM_INV_SQRT(va,sva);\ (sva) = 1.0f/(sva);\ }\ //! Computes 1.0f / sqrtf(x). Comes from Quake3. See http://www.magic-software.com/3DGEDInvSqrt.html GREAL gim_inv_sqrt(GREAL f); //! Computes sqrtf(x) faster. /*! \sa gim_inv_sqrt */ GREAL gim_sqrt(GREAL f); //!Initializes mathematical functions void gim_init_math(); //! Generates an unit random GREAL gim_unit_random(); //! @} #endif // GIM_MATH_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_memory.h0000644000000000000000000010642512635011627017026 0ustar rootroot#ifndef GIM_MEMORY_H_INCLUDED #define GIM_MEMORY_H_INCLUDED /*! \file gim_memory.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_math.h" #include //#define PREFETCH 1 //! \defgroup PREFETCH //! @{ #ifdef PREFETCH #include // for prefetch #define pfval 64 #define pfval2 128 //! Prefetch 64 #define pf(_x,_i) _mm_prefetch((void *)(_x + _i + pfval), 0) //! Prefetch 128 #define pf2(_x,_i) _mm_prefetch((void *)(_x + _i + pfval2), 0) #else //! Prefetch 64 #define pf(_x,_i) //! Prefetch 128 #define pf2(_x,_i) #endif //! @} /*! \defgroup ARRAY_UTILITIES \brief Functions for manip packed arrays of numbers */ //! @{ #define GIM_COPY_ARRAYS(dest_array, source_array, element_count)\ {\ GUINT32 _i_;\ for (_i_ = 0; _i_ < (element_count); _i_++)\ {\ (dest_array)[_i_] = (source_array)[_i_];\ }\ }\ #define GIM_COPY_ARRAYS_1(dest_array, source_array, element_count, copy_macro)\ {\ GUINT32 _i_;\ for (_i_=0; _i_ < (element_count); _i_++)\ {\ copy_macro((dest_array)[_i_], (source_array)[_i_]);\ }\ }\ #define GIM_ZERO_ARRAY(array, element_count)\ {\ GUINT32 _i_;\ for (_i_=0; _i_ < (element_count); _i_++)\ {\ (array)[_i_] = 0;\ }\ }\ #define GIM_CONSTANT_ARRAY(array, element_count, constant)\ {\ GUINT32 _i_;\ for (_i_ = 0; _i_ < (element_count); _i_++)\ {\ (array)[_i_] = (constant);\ }\ }\ //! @} /*! \defgroup MEMORY_FUNCTION_PROTOTYPES Function prototypes to allocate and free memory. */ //! @{ typedef void * gim_alloc_function (size_t size); typedef void * gim_alloca_function (size_t size);//Allocs on the heap typedef void * gim_realloc_function (void *ptr, size_t oldsize, size_t newsize); typedef void gim_free_function (void *ptr, size_t size); //! @} /*! \defgroup MEMORY_FUNCTION_HANDLERS \brief Memory Function Handlers set new memory management functions. if fn is 0, the default handlers are used. */ //! @{ void gim_set_alloc_handler (gim_alloc_function *fn); // void gim_set_alloca_handler (gim_alloca_function *fn); -- a nonsense void gim_set_realloc_handler (gim_realloc_function *fn); void gim_set_free_handler (gim_free_function *fn); //! @} /*! \defgroup MEMORY_FUNCTION_GET_HANDLERS \brief get current memory management functions. */ //! @{ gim_alloc_function *gim_get_alloc_handler (void); // gim_alloca_function *gim_get_alloca_handler(void); -- a nonsense gim_realloc_function *gim_get_realloc_handler (void); gim_free_function *gim_get_free_handler (void); //! @} /*! \defgroup MEMORY_FUNCTIONS Standar Memory functions */ //! @{ void * gim_alloc(size_t size); // void * gim_alloca(size_t size); -- a nonsense void * gim_realloc(void *ptr, size_t oldsize, size_t newsize); void gim_free(void *ptr, size_t size); //! @} /*! \defgroup DYNAMIC_ARRAYS \brief Dynamic Arrays. Allocated from system memory.
    • For initializes a dynamic array, use GIM_DYNARRAY_CREATE or GIM_DYNARRAY_CREATE_SIZED.
    • When an array is no longer used, must be terminated with the macro GIM_DYNARRAY_DESTROY.
    */ //! @{ #define G_ARRAY_GROW_SIZE 64 #define G_ARRAY_BUFFERMANAGER_INIT_SIZE 2 //! Dynamic array handle. struct GDYNAMIC_ARRAY { char * m_pdata; GUINT32 m_size; GUINT32 m_reserve_size; }; //typedef struct _GDYNAMIC_ARRAY GDYNAMIC_ARRAY; //! Creates a dynamic array zero sized #define GIM_DYNARRAY_CREATE(type, array_data, reserve_size) \ { \ (array_data).m_pdata = (char *)gim_alloc((reserve_size) * sizeof(type)); \ (array_data).m_size = 0; \ (array_data).m_reserve_size = (reserve_size); \ } \ //! Creates a dynamic array with n = size elements #define GIM_DYNARRAY_CREATE_SIZED(type, array_data, size) \ { \ (array_data).m_pdata = (char *)gim_alloc((size) * sizeof(type)); \ (array_data).m_size = (size); \ (array_data).m_reserve_size = (size); \ } \ //! Reserves memory for a dynamic array. #define GIM_DYNARRAY_RESERVE_SIZE(type, array_data, old_size, reserve_size) \ { \ if ((reserve_size) > (array_data).m_reserve_size) \ { \ (array_data).m_pdata = (char *) gim_realloc((array_data).m_pdata, (old_size) * sizeof(type), (reserve_size) * sizeof(type)); \ (array_data).m_reserve_size = (reserve_size); \ } \ } \ //! Set the size of the array #define GIM_DYNARRAY_SET_SIZE(type, array_data, size) \ { \ GIM_DYNARRAY_RESERVE_SIZE(type, array_data, (array_data).m_size, size); \ (array_data).m_size = size; \ } \ //! Gets a pointer from the beginning of the array #define GIM_DYNARRAY_POINTER(type, array_data) ((type *)((array_data).m_pdata)) //! Gets a pointer from the last elemento of the array #define GIM_DYNARRAY_POINTER_LAST(type, array_data) (((type *)(array_data).m_pdata) + ((array_data).m_size - 1)) //! Inserts an element at the last position #define GIM_DYNARRAY_PUSH_ITEM(type, array_data, item)\ { \ if ((array_data).m_reserve_size <= (array_data).m_size)\ {\ GIM_DYNARRAY_RESERVE_SIZE(type, array_data, (array_data).m_size, (array_data).m_size + G_ARRAY_GROW_SIZE); \ }\ type * _pt = GIM_DYNARRAY_POINTER(type, array_data); \ memcpy(&_pt[(array_data).m_size], &(item), sizeof(type)); \ (array_data).m_size++; \ } \ //! Inserts an element at the last position #define GIM_DYNARRAY_PUSH_EMPTY(type, array_data) \ { \ if ((array_data).m_reserve_size <= (array_data).m_size) \ { \ GIM_DYNARRAY_RESERVE_SIZE(type, array_data, (array_data).m_size, (array_data).m_size + G_ARRAY_GROW_SIZE); \ } \ (array_data).m_size++; \ } \ //! Inserts an element #define GIM_DYNARRAY_INSERT_ITEM(type, array_data, item, index) \ { \ if ((array_data).m_reserve_size <= (array_data).m_size) \ { \ GIM_DYNARRAY_RESERVE_SIZE(type, array_data, (array_data).m_size, (array_data).m_size + G_ARRAY_GROW_SIZE); \ } \ type * _pt = GIM_DYNARRAY_POINTER(type, array_data); \ if ((index) < (array_data).m_size - 1) \ { \ memmove(&_pt[(index) + 1], &_pt[(index)], ((array_data).m_size - (index)) * sizeof(type)); \ } \ memcpy(&_pt[(index)], &(item), sizeof(type)); \ array_data.m_size++; \ } \ //! Removes an element #define GIM_DYNARRAY_DELETE_ITEM(type, array_data, index) \ { \ if ((index) < (array_data).m_size - 1) \ { \ type * _pt = GIM_DYNARRAY_POINTER(type, array_data);\ memmove(&_pt[(index)], &_pt[(index) + 1], ((array_data).m_size - (index) - 1) * sizeof(type)); \ } \ (array_data).m_size--; \ } \ //! Removes an element at the last position #define GIM_DYNARRAY_POP_ITEM(array_data) \ { \ if ((array_data).m_size > 0) \ { \ (array_data).m_size--; \ } \ }\ //! Destroys the array void GIM_DYNARRAY_DESTROY(GDYNAMIC_ARRAY & array_data); //! @} /*! \defgroup BITSET \brief Bitsets , based on \ref DYNAMIC_ARRAYS .
    • For initializes a bitset array, use \ref GIM_BITSET_CREATE or \ref GIM_BITSET_CREATE_SIZED.
    • When the bitset is no longer used, must be terminated with the macro \ref GIM_DYNARRAY_DESTROY.
    • For putting a mark on the bitset, call \ref GIM_BITSET_SET
    • For clearing a mark on the bitset, call \ref GIM_BITSET_CLEAR
    • For retrieving a bit value from a bitset, call \ref GIM_BITSET_GET-
    */ //! @{ //! Creates a bitset #define GIM_BITSET_CREATE(array_data) GIM_DYNARRAY_CREATE(GUINT32, array_data, G_ARRAY_GROW_SIZE) //! Creates a bitset, with their bits set to 0. #define GIM_BITSET_CREATE_SIZED(array_data, bits_count) \ { \ GUINT32 array_size = (bits_count) / GUINT32_BIT_COUNT + 1; \ GIM_DYNARRAY_CREATE(GUINT32, array_data, array_size); \ GUINT32 * _pt = GIM_DYNARRAY_POINTER(GUINT32, array_data); \ memset(_pt, 0, sizeof(GUINT32) * ((array_data).m_size)); \ } \ //! Gets the bitset bit count. #define GIM_BITSET_SIZE(array_data) ((array_data).m_size * GUINT32_BIT_COUNT) //! Resizes a bitset, with their bits set to 0. #define GIM_BITSET_RESIZE(array_data, new_bits_count) \ { \ GUINT32 _oldsize = (array_data).m_size; \ (array_data).m_size = (new_bits_count) / GUINT32_BIT_COUNT + 1; \ if (_oldsize < (array_data).m_size) \ { \ if ((array_data).m_size > (array_data).m_reserve_size) \ { \ GIM_DYNARRAY_RESERVE_SIZE(GUINT32, array_data, _oldsize, (array_data).m_size + G_ARRAY_GROW_SIZE); \ } \ GUINT32 * _pt = GIM_DYNARRAY_POINTER(GUINT32, array_data); \ memset(&_pt[_oldsize], 0, sizeof(GUINT32) * ((array_data).m_size - _oldsize)); \ } \ } \ //! Sets all bitset bit to 0. #define GIM_BITSET_CLEAR_ALL(array_data) \ { \ memset((array_data).m_pdata, 0, sizeof(GUINT32) * (array_data).m_size); \ } \ //! Sets all bitset bit to 1. #define GIM_BITSET_SET_ALL(array_data) \ { \ memset((array_data).m_pdata, 0xFF, sizeof(GUINT32) * (array_data).m_size); \ } \ ///Sets the desired bit to 1 #define GIM_BITSET_SET(array_data, bit_index) \ { \ if ((bit_index) >= GIM_BITSET_SIZE(array_data)) \ { \ GIM_BITSET_RESIZE(array_data, bit_index); \ } \ GUINT32 * _pt = GIM_DYNARRAY_POINTER(GUINT32, array_data); \ _pt[(bit_index) >> GUINT32_EXPONENT] |= (1 << ((bit_index) & (GUINT32_BIT_COUNT - 1))); \ } \ ///Return 0 or 1 #define GIM_BITSET_GET(array_data, bit_index, get_value) \ { \ if ((bit_index) >= GIM_BITSET_SIZE(array_data)) \ { \ (get_value) = 0; \ } \ else \ { \ GUINT32 * _pt = GIM_DYNARRAY_POINTER(GUINT32, array_data); \ (get_value) = _pt[(bit_index) >> GUINT32_EXPONENT] & (1 << ((bit_index) & (GUINT32_BIT_COUNT - 1))); \ } \ } \ ///Sets the desired bit to 0 #define GIM_BITSET_CLEAR(array_data, bit_index) \ { \ if ((bit_index) < GIM_BITSET_SIZE(array_data)) \ { \ GUINT32 * _pt = GIM_DYNARRAY_POINTER(GUINT32, array_data); \ _pt[(bit_index) >> GUINT32_EXPONENT] &= ~(1 << ((bit_index) & (GUINT32_BIT_COUNT - 1))); \ } \ } \ //! @} /*! \defgroup MEMORY_ACCESS_CONSTANTS \brief Memory Access constants. \sa BUFFERS */ //! @{ #define G_MA_READ_ONLY 1 #define G_MA_WRITE_ONLY 2 #define G_MA_READ_WRITE 3 //! @} /*! \defgroup MEMORY_USAGE_CONSTANTS \brief Memory usage constants. \sa BUFFERS */ //! @{ /// Don't care how memory is used #define G_MU_EITHER 0 /// specified once, doesn't allow read information #define G_MU_STATIC_WRITE 1 /// specified once, allows to read information from a shadow buffer #define G_MU_STATIC_READ 2 /// write directly on buffer, allows to read information from a shadow buffer #define G_MU_STATIC_READ_DYNAMIC_WRITE 3 /// upload data to buffer from the shadow buffer, allows to read information from a shadow buffer #define G_MU_STATIC_READ_DYNAMIC_WRITE_COPY 4 /// specified once, allows to read information directly from memory #define G_MU_STATIC_WRITE_DYNAMIC_READ 5 /// write directly on buffer, allows to read information directly from memory #define G_MU_DYNAMIC_READ_WRITE 6 //! @} /*! \defgroup BUFFER_ERRORS \brief Buffer operation errors \sa BUFFERS */ //! @{ #define G_BUFFER_OP_SUCCESS 0 #define G_BUFFER_OP_INVALID 1 #define G_BUFFER_OP_STILLREFCOUNTED 2 //! @} /*! \defgroup BUFFER_MANAGER_IDS \brief Buffer manager identifiers \sa BUFFERS, BUFFER_MANAGERS */ //! @{ enum { G_BUFFER_MANAGER_SYSTEM, G_BUFFER_MANAGER_SHARED, G_BUFFER_MANAGER__MAX }; //! @} /*! \defgroup BUFFERS \brief Buffer operations and structs.
    • Before using buffers you must initializes GIMPACT buffer managers by calling \ref gimpact_init.
    • For initializes a buffer, use \ref gim_create_buffer, \ref gim_create_buffer_from_data , \ref gim_create_common_buffer, \ref gim_create_common_buffer_from_data or \ref gim_create_shared_buffer_from_data.
    • For accessing to the buffer memory, you must call \ref gim_lock_buffer, and then \ref gim_unlock_buffer for finish the access.
    • When a buffer is no longer needed, you must free it by calling \ref gim_buffer_free.
    • You must call \ref gimpact_terminate when finish your application.
    • For a safe manipulation of buffers, use \ref BUFFER_ARRAYS
    \sa BUFFER_MANAGERS, BUFFER_ARRAYS */ //! @{ struct GBUFFER_MANAGER_DATA; //! Buffer handle. struct GBUFFER_ID { GBUFFER_MANAGER_DATA * m_bm_data; GUINT32 m_buffer_id; }; //typedef struct _GBUFFER_ID GBUFFER_ID; //! Buffer internal data struct GBUFFER_DATA { GPTR m_buffer_handle;//!< if 0, buffer doesn't exists GUINT32 m_size; GUINT32 m_usage; GINT32 m_access; GUINT32 m_lock_count; char * m_mapped_pointer; GBUFFER_ID m_shadow_buffer; GUINT32 m_refcount;//! Reference counting for safe garbage collection }; //typedef struct _GBUFFER_DATA GBUFFER_DATA; //! @} /*! \defgroup BUFFERS_MANAGER_PROTOTYPES \brief Function prototypes to allocate and free memory for buffers \sa BUFFER_MANAGERS, BUFFERS */ //! @{ //! Returns a Buffer handle typedef GPTR gim_buffer_alloc_function(GUINT32 size,int usage); //! Returns a Buffer handle, and copies the pdata to the buffer typedef GPTR gim_buffer_alloc_data_function(const void * pdata,GUINT32 size,int usage); //! Changes the size of the buffer preserving the content, and returns the new buffer id typedef GPTR gim_buffer_realloc_function(GPTR buffer_handle,GUINT32 oldsize,int old_usage,GUINT32 newsize,int new_usage); //! It changes the m_buffer_handle member to 0/0 typedef void gim_buffer_free_function(GPTR buffer_handle,GUINT32 size); //! It maps the m_mapped_pointer. Returns a pointer typedef char * gim_lock_buffer_function(GPTR buffer_handle,int access); //! It sets the m_mapped_pointer to 0 typedef void gim_unlock_buffer_function(GPTR buffer_handle); typedef void gim_download_from_buffer_function( GPTR source_buffer_handle, GUINT32 source_pos, void * destdata, GUINT32 copysize); typedef void gim_upload_to_buffer_function( GPTR dest_buffer_handle, GUINT32 dest_pos, void * sourcedata, GUINT32 copysize); typedef void gim_copy_buffers_function( GPTR source_buffer_handle, GUINT32 source_pos, GPTR dest_buffer_handle, GUINT32 dest_pos, GUINT32 copysize); //! @} /*! \defgroup BUFFER_MANAGERS \brief Buffer Manager operations */ //! @{ //! Buffer manager prototype struct GBUFFER_MANAGER_PROTOTYPE { gim_buffer_alloc_function * alloc_fn; gim_buffer_alloc_data_function *alloc_data_fn; gim_buffer_realloc_function * realloc_fn; gim_buffer_free_function * free_fn; gim_lock_buffer_function * lock_buffer_fn; gim_unlock_buffer_function * unlock_buffer_fn; gim_download_from_buffer_function * download_from_buffer_fn; gim_upload_to_buffer_function * upload_to_buffer_fn; gim_copy_buffers_function * copy_buffers_fn; }; //typedef struct _GBUFFER_MANAGER_PROTOTYPE GBUFFER_MANAGER_PROTOTYPE; //! Buffer manager struct GBUFFER_MANAGER_DATA { GDYNAMIC_ARRAY m_buffer_array;//!< Array of GBUFFER_DATA objects GDYNAMIC_ARRAY m_free_positions;//!< Array of GUINT elements. Free positions const GBUFFER_MANAGER_PROTOTYPE *m_prototype;//!< Prototype of functions GUINT32 m_buffer_manager_id;//!< Buffer manager id }; //typedef struct _GBUFFER_MANAGER_DATA GBUFFER_MANAGER_DATA; //! Checks if buffer manager is used int gim_is_buffer_manager_active(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id); //! Adds a buffer Manager to the Memory Singleton void gim_create_buffer_manager(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id); //! Destroys a buffer manager void gim_destroy_buffer_manager(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id); void gim_get_buffer_manager_data(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id,GBUFFER_MANAGER_DATA ** pbm_data); void gim_init_buffer_managers(GBUFFER_MANAGER_DATA buffer_managers[]); void gim_terminate_buffer_managers(GBUFFER_MANAGER_DATA buffer_managers[]); //! @} /*! \addtogroup BUFFERS */ //! @{ //!Creates a buffer on the buffer manager specified by buffer_manager_id /*! \param buffer_manager_id \param buffer_size \param usage An usage constant. Use G_MU_DYNAMIC_READ_WRITE as default. \param buffer_id a pointer for receive the new buffer id \return An error code. 0 if success. \post m_refcount = 0 */ GUINT32 gim_create_buffer( GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id, GUINT32 buffer_size, int usage, GBUFFER_ID * buffer_id); //!Creates a buffer on the buffer manager specified by buffer_manager_id /*! \param buffer_manager_id \param pdata Data for allocating \param buffer_size Size of the data buffer \param usage An usage constant. Use G_MU_DYNAMIC_READ_WRITE as default. \param buffer_id a pointer for receive the new buffer id \return An error code. 0 if success. \post m_refcount = 0 */ GUINT32 gim_create_buffer_from_data( GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id, const void * pdata, GUINT32 buffer_size, int usage, GBUFFER_ID * buffer_id); //!Allocates on the G_BUFFER_MANAGER_SYSTEM GUINT32 gim_create_common_buffer(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_size, GBUFFER_ID * buffer_id); //!Allocates on the G_BUFFER_MANAGER_SYSTEM, and copies the data GUINT32 gim_create_common_buffer_from_data(GBUFFER_MANAGER_DATA buffer_managers[], const void * pdata, GUINT32 buffer_size, GBUFFER_ID * buffer_id); //!Creates a buffer with shared data GUINT32 gim_create_shared_buffer_from_data(GBUFFER_MANAGER_DATA buffer_managers[], const void * pdata, GUINT32 buffer_size, GBUFFER_ID * buffer_id); //! Add reference counting to buffer. GINT32 gim_buffer_add_ref(GBUFFER_ID * buffer_id); //! Function for resize buffer, preserving the content /*! \param buffer_id \param newsize \return An error code. 0 if success. \post If m_refcount>0 then it decrements it. */ GINT32 gim_buffer_realloc(GBUFFER_ID * buffer_id,GUINT32 newsize); //! Eliminates the buffer. /*! If the buffer reference counting is <= 1 and is unlocked, then it eliminates the buffer. */ GINT32 gim_buffer_free(GBUFFER_ID * buffer_id); //! Locks the buffer for memory access. /*! \param buffer_id Id from buffer. \param access Must have the following values: G_MA_READ_ONLY,G_MA_WRITE_ONLY or G_MA_READ_WRITE. \param map_pointer Dest Pointer of the memory address from buffer. \post m_lock_count increases. */ GINT32 gim_lock_buffer(GBUFFER_ID * buffer_id,int access,char ** map_pointer); //! Unlocks the buffer for memory access. GINT32 gim_unlock_buffer(GBUFFER_ID * buffer_id); //! Gets the buffer size in bytes GINT32 gim_get_buffer_size(GBUFFER_ID * buffer_id,GUINT32 * buffer_size); //! Determines if the buffer is locked GINT32 gim_get_buffer_is_locked(GBUFFER_ID * buffer_id,GUINT32 * lock_count); //! Copies the content of the buffer to a dest pointer GINT32 gim_download_from_buffer( GBUFFER_ID * buffer_id, GUINT32 source_pos, void * destdata, GUINT32 copysize); //! Copies the content of a memory pointer to the buffer GINT32 gim_upload_to_buffer( GBUFFER_ID * buffer_id, GUINT32 dest_pos, void * sourcedata, GUINT32 copysize); //! Copies two buffers. GINT32 gim_copy_buffers( GBUFFER_ID * source_buffer_id, GUINT32 source_pos, GBUFFER_ID * dest_buffer_id, GUINT32 dest_pos, GUINT32 copysize); //! @} /*! \defgroup BUFFER_ARRAYS \brief Buffered Arrays, for manip elements on a buffer and treat it as an array.
    • Before using buffer arrays you must initializes GIMPACT buffer managers by calling gimpact_init.
    • Before creating buffer arrays, you must create a buffer. see \ref BUFFERS.
    • Create a buffer narray by calling \ref GIM_BUFFER_ARRAY_INIT_TYPE, \ref GIM_BUFFER_ARRAY_INIT_TYPE_OFFSET or \ref GIM_BUFFER_ARRAY_INIT_OFFSET_STRIDE.
    • For accessing to the array elements, you must call \ref gim_buffer_array_lock, and then \ref gim_buffer_array_unlock for finish the access.
    • When a buffer array is no longer needed, you must free it by calling \ref GIM_BUFFER_ARRAY_DESTROY.
    The following example shows how Buffer arrays can be used: \code int main() { //init gimpact gimpact_init(); //Buffer handle to use GBUFFER_ID bufferhandle; //Create a memory buffer of 100 float numbers gim_create_common_buffer(100*sizeof(float), &bufferhandle); //Create a buffer array from the bufferhandle GBUFFER_ARRAY buffer_float_array; GIM_BUFFER_ARRAY_INIT_TYPE(float,buffer_float_array,bufferhandle,100); ////Access to the buffer data, set all elements of the array int i, count; count = buffer_float_array.m_element_count; //Locks the array gim_buffer_array_lock(&buffer_float_array,G_MA_READ_WRITE); float * pelements = GIM_BUFFER_ARRAY_POINTER(float, buffer_float_array, 0); // A pointer to the buffer memory //fill the array with random numbers for (i = 0;i < count;i++ ) { pelements[i] = gim_unit_random(); } //unlock buffer gim_buffer_array_unlock(&buffer_float_array); //Program code .... .... //Destroy array GIM_BUFFER_ARRAY_DESTROY(buffer_float_array); //terminate gimpact gimpact_terminate(); } \endcode \sa BUFFERS */ //! @{ //! Buffer managed array struct. struct GBUFFER_ARRAY { GBUFFER_ID m_buffer_id; char * m_buffer_data; char m_byte_stride; GUINT32 m_byte_offset; GUINT32 m_element_count; }; //typedef struct _GBUFFER_ARRAY GBUFFER_ARRAY; //! Sets offset for a buffered array. #define GIM_BUFFER_ARRAY_SET_OFFSET(_array_data,_offset) (_array_data).m_byte_offset = (_offset)*(_array_data).m_byte_stride; //! Sets offset for a buffered array. #define GIM_BUFFER_ARRAY_GET_OFFSET(_array_data,_offset) (_offset) = (_array_data).m_byte_offset/(_array_data).m_byte_stride; //!Return a pointer of the element at the _index #define GIM_BUFFER_ARRAY_POINTER(_type,_array_data,_index) (_type *)((_array_data).m_buffer_data + (_index)*(_array_data).m_byte_stride) //! Sets stride for a buffered array. #define GIM_BUFFER_ARRAY_SET_STRIDE(_type,_array_data) (_array_data).m_byte_stride = sizeof(_type); //! Is array stride equal to the size of the type ? #define GIM_BUFFER_ARRAY_IS_ALIGNED(_type,_array_data) ((_array_data).m_byte_stride == sizeof(_type)) ///Verify if two arrays have the same data #define GIM_BUFFER_ARRAY_ARE_SAME(_array_data1,_array_data2,aresame) \ { \ (aresame) = 1; \ if ((_array_data1).m_buffer_id.m_buffer_id != (_array_data2).m_buffer_id.m_buffer_id || (_array_data1).m_buffer_id.m_buffer_manager_id != (_array_data2).m_buffer_id.m_buffer_manager_id || (_array_data1).m_byte_offset != (_array_data2).m_byte_offset) \ { \ (aresame) = 0; \ } \ } \ //! Reserve size for a buffered array. /*! \pre array_data must be unlocked, and must be the aligned (GIM_BUFFER_ARRAY_IS_ALIGNED ) */ #define GIM_BUFFER_ARRAY_RESERVE_SIZE(type, array_data, reserve_size) \ { \ if ((reserve_size) > (array_data).m_element_count) \ { \ GUINT32 _buffer_size, _newarray_size; \ gim_get_buffer_size(&(array_data).m_buffer_id, _buffer_size); \ _newarray_size = (reserve_size) * (array_data).m_byte_stride; \ if(_newarray_size > _buffer_size) \ { \ _newarray_size += G_ARRAY_GROW_SIZE * (array_data).m_byte_stride; \ gim_buffer_realloc(&(array_data).m_buffer_id, _newarray_size); \ } \ } \ } \ //! Pushes an element at last position /*! \pre array_data must be unlocked, and must be the aligned (GIM_BUFFER_ARRAY_IS_ALIGNED ) */ #define GIM_BUFFER_ARRAY_PUSH_ITEM(type, array_data, item) \ { \ GIM_BUFFER_ARRAY_RESERVE_SIZE(type, array_data, (array_data).m_element_count + 1); \ gim_buffer_array_lock(&(array_data), G_MA_WRITE_ONLY); \ type * _pt = GIM_BUFFER_ARRAY_POINTER(type, array_data, (array_data).m_element_count); \ memcpy(_pt, &(item), sizeof(type)); \ gim_buffer_array_unlock(&(array_data)); \ (array_data)->m_element_count++; \ } \ //! Pushes a new element at last position /*! \pre array_data must be unlocked, and must be the aligned (GIM_BUFFER_ARRAY_IS_ALIGNED ) */ #define GIM_BUFFER_ARRAY_PUSH_EMPTY(type, array_data) \ {\ GIM_BUFFER_ARRAY_RESERVE_SIZE(type, array_data, (array_data).m_element_count + 1); \ (array_data)->m_element_count++; \ }\ //! Inserts an element /*! \pre array_data must be unlocked, and must be the aligned (GIM_BUFFER_ARRAY_IS_ALIGNED ) */ #define GIM_BUFFER_ARRAY_INSERT_ITEM(type, array_data, item, index) \ { \ GIM_BUFFER_ARRAY_RESERVE_SIZE(type, array_data, (array_data).m_element_count + 1); \ gim_buffer_array_lock(&(array_data), G_MA_WRITE_ONLY); \ type * _pt = GIM_BUFFER_ARRAY_POINTER(type, array_data, 0); \ if ((index) < (array_data)->m_element_count - 1) \ { \ memmove(&_pt[(index) + 1], &_pt[(index)], ((array_data).m_element_count - (index)) * sizeof(type)); \ } \ memcpy(&_pt[(index)], &(item), sizeof(type)); \ gim_buffer_array_unlock(&(array_data)); \ (array_data).m_element_count++; \ } \ //! Deletes an element /*! \pre array_data must be unlocked, and must be the aligned (GIM_BUFFER_ARRAY_IS_ALIGNED ) */ #define GIM_BUFFER_ARRAY_DELETE_ITEM(type, array_data, index) \ { \ if ((index) < (array_data).m_element_count - 1) \ { \ gim_buffer_array_lock(&(array_data), G_MA_WRITE_ONLY); \ type * _pt = GIM_BUFFER_ARRAY_POINTER(type, array_data, 0); \ memmove(&_pt[(index)], &_pt[(index) + 1],((array_data).m_element_count - (index) - 1) * sizeof(type)); \ gim_buffer_array_unlock(&(array_data)); \ } \ (array_data).m_element_count--; \ } \ //! Deletes an element at last position /*! \pre array_data must be unlocked, and must be the aligned (GIM_BUFFER_ARRAY_IS_ALIGNED ) */ #define GIM_BUFFER_ARRAY_POP_ITEM(array_data) \ { \ if ((array_data).m_element_count > 0) \ { \ (array_data).m_element_count--; \ } \ } \ //! Initializes an GBUFFER_ARRAY object from a buffer ID /*! m_buffer_data will be 0, for acces to the elements, you'd need to call lock_array \param array_data Array structure to be filled \param buffer_id A GBUFFER_ID structure which this array_daya will refer to \param element_count Number of elements \param offset element offset, it isn't byte offset. 0 is recomended \param byte_stride size of each element. 0 is recomended. \post Adds reference to the buffer \sa gim_buffer_add_ref */ #define GIM_BUFFER_ARRAY_INIT_OFFSET_STRIDE(array_data, buffer_id, element_count, offset, byte_stride) \ { \ (array_data).m_buffer_id.m_buffer_id = (buffer_id).m_buffer_id; \ (array_data).m_buffer_id.m_buffer_manager_id = (buffer_id).m_buffer_manager_id; \ (array_data).m_buffer_data = 0; \ (array_data).m_element_count = (element_count); \ (array_data).m_byte_stride = (byte_stride); \ GIM_BUFFER_ARRAY_SET_OFFSET(array_data, offset); \ gim_buffer_add_ref(&(buffer_id)); \ } \ //! Initializes an GBUFFER_ARRAY object from a buffer ID and a Given type /*! m_buffer_data will be 0, for acces to the elements, you'd need to call lock_array \param type Type of the Array. It determines the stride. \param array_data Array structure to be filled \param buffer_id A GBUFFER_ID structure which this array_daya will refer to \param element_count Number of elements \param offset element offset, it isn't byte offset. 0 is recomended \post Adds reference to the buffer \sa gim_buffer_add_ref */ #define GIM_BUFFER_ARRAY_INIT_TYPE_OFFSET(type, array_data, buffer_id, element_count, offset) \ { \ (array_data).m_buffer_id.m_buffer_id = (buffer_id).m_buffer_id; \ (array_data).m_buffer_id.m_bm_data = (buffer_id).m_bm_data; \ (array_data).m_buffer_data = 0; \ (array_data).m_element_count = (element_count);\ GIM_BUFFER_ARRAY_SET_STRIDE(type, array_data); \ GIM_BUFFER_ARRAY_SET_OFFSET(array_data, offset); \ gim_buffer_add_ref(&(buffer_id)); \ }\ //! Initializes a buffer array giving a data type and a buffer id /*! m_buffer_data will be 0, for acces to the elements, you'd need to call lock_array. \param type Type of the Array. It determines the stride. \param array_data Array structure to be filled \param buffer_id A GBUFFER_ID structure which this array_daya will refer to \param element_count Number of elements \post Adds reference to the buffer \sa gim_buffer_add_ref */ #define GIM_BUFFER_ARRAY_INIT_TYPE(type, array_data, buffer_id, element_count) GIM_BUFFER_ARRAY_INIT_TYPE_OFFSET(type, array_data, buffer_id, element_count, 0) //! Gain access to the array buffer through the m_buffer_data element /*! m_buffer_data pointer will be located at the m_byte_offset position of the buffer m_buffer Then, You'd need to call unlock_array when finish to using the array access. \pre if m_buffer_data != 0, the function returns \param array_data Array structure to be locked \param access A constant for access to the buffer. can be G_MA_READ_ONLY,G_MA_WRITE_ONLY or G_MA_READ_WRITE \return an Buffer error code */ GINT32 gim_buffer_array_lock(GBUFFER_ARRAY * array_data, int access); //! close the access to the array buffer through the m_buffer_data element /*! \param array_data Array structure to be locked \return an Buffer error code */ GINT32 gim_buffer_array_unlock(GBUFFER_ARRAY * array_data); //! Copy an array by reference /*! \post A reference to the m_buffer_id is increased. */ void gim_buffer_array_copy_ref(GBUFFER_ARRAY * source_data,GBUFFER_ARRAY * dest_data); //! Copy an array by value /*! \post A new buffer is created */ void gim_buffer_array_copy_value(GBUFFER_ARRAY * source_data, GBUFFER_MANAGER_DATA dest_buffer_managers[],GBUFFER_ARRAY * dest_data, GUINT32 buffer_manager_id,int usage); //! Destroys an GBUFFER_ARRAY object /*! \post Attemps to destroy the buffer, decreases reference counting */ void GIM_BUFFER_ARRAY_DESTROY(GBUFFER_ARRAY & array_data); //! Copy the content of the array to a pointer /*! \pre dest_data must have the same size as the array_data \param type \param array_data A GBUFFERED_ARRAY structure \param dest_data A type pointer */ #define GIM_BUFFER_ARRAY_DOWNLOAD(type,array_data,dest_data) \ { \ if (GIM_BUFFER_ARRAY_IS_ALIGNED(type, array_data)) \ { \ gim_download_from_buffer(&(array_data).m_buffer_id, (array_data).m_byte_offset, (void *)(dest_data), (array_data).m_element_count * (array_data).m_byte_stride); \ } \ else \ { \ GUINT32 _k_, _ecount_= (array_data).m_element_count; \ type * _source_vert_; \ type * _dest_vert_ = (dest_data); \ gim_buffer_array_lock(&(array_data), G_MA_READ_ONLY); \ for (_k_ = 0; _k_ < _ecount_; _k_++) \ { \ _source_vert_ = GIM_BUFFER_ARRAY_POINTER(type, array_data, _k_); \ memcpy(_dest_vert_, _source_vert_, sizeof(type)); \ _dest_vert_++; \ } \ gim_buffer_array_unlock(&(array_data)); \ } \ } \ //! Upload the content of a a pointer to a buffered array /*! \pre source_data must have the same size as the array_data \param type \param array_data A GBUFFERED_ARRAY structure \param source_data A void pointer */ #define GIM_BUFFER_ARRAY_UPLOAD(type, array_data, source_data) \ { \ if (GIM_BUFFER_ARRAY_IS_ALIGNED(type, array_data)) \ { \ gim_upload_to_buffer(&(array_data).m_buffer_id, (array_data).m_byte_offset, (void *)(source_data), (array_data).m_element_count * (array_data).m_byte_stride); \ } \ else \ { \ GUINT32 _k_, _ecount_= (array_data).m_element_count; \ type * _source_vert_ = (source_data); \ type * _dest_vert_; \ gim_buffer_array_lock(&(array_data), G_MA_WRITE_ONLY); \ for (_k_ = 0; _k_ < _ecount_; _k_++) \ { \ _dest_vert_ = GIM_BUFFER_ARRAY_POINTER(type, array_data, _k_); \ memcpy(_dest_vert_, _source_vert_, sizeof(type)); \ _source_vert_++; \ } \ gim_buffer_array_unlock(&(array_data)); \ } \ } \ //!Kernel function prototype for process streams, given a buffered array as source and /*! \param 1 the uniform arguments \param 2 the source stream \param 3 the destination stream */ typedef void (* gim_kernel_func)(void *,GBUFFER_ARRAY *,GBUFFER_ARRAY *); //! Generic Stream Processingp loop /*! This macro executes a kernel macro or function for each element of the streams \pre _src_array->m_count <= _dst_array->m_count \param _uniform_data An argument to be passed to the Kernel function \param _src_array An GBUFFER_ARRAY structure passed as the source stream \param _dst_array An GBUFFER_ARRAY structure passed as the source stream \param _kernel Macro or function of the kernel \param _src_type Required. Type of all elements of the source stream \param _dst_type Required. Type of all elements of the dest stream */ #define GIM_PROCESS_BUFFER_ARRAY(_uniform_data, _src_array, _dst_array, _kernel, _src_type, _dst_type) \ { \ \ gim_buffer_array_lock(&(_src_array), G_MA_READ_ONLY); \ gim_buffer_array_lock(&(_dst_array), G_MA_WRITE_ONLY); \ \ GUINT32 _i_, _count_=(_src_array).m_element_count; \ \ _src_type * _source_vert_; \ _dst_type * _dest_vert_; \ if (GIM_BUFFER_ARRAY_IS_ALIGNED(_src_type, _src_array) && GIM_BUFFER_ARRAY_IS_ALIGNED(_dst_type, _dst_array)) \ { \ \ _source_vert_ = GIM_BUFFER_ARRAY_POINTER(_src_type, _src_array, 0); \ _dest_vert_ = GIM_BUFFER_ARRAY_POINTER(_dst_type, _dst_array, 0); \ for (_i_ = 0;_i_< _count_; _i_++) \ { \ _kernel(_uniform_data, *_source_vert_, *_dest_vert_); \ _source_vert_++; \ _dest_vert_++; \ } \ } \ else \ { \ for (_i_ = 0; _i_ < _count_; _i_++) \ { \ _source_vert_ = GIM_BUFFER_ARRAY_POINTER(_src_type, _src_array, _i_); \ _dest_vert_ = GIM_BUFFER_ARRAY_POINTER(_dst_type, _dst_array, _i_); \ _kernel(_uniform_data, *_source_vert_, *_dest_vert_); \ } \ } \ gim_buffer_array_unlock(&(_src_array)); \ gim_buffer_array_unlock(&(_dst_array)); \ } \ //! @} #endif // GIM_MEMORY_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_radixsort.h0000644000000000000000000001662212635011627017534 0ustar rootroot#ifndef GIM_RADIXSORT_H_INCLUDED #define GIM_RADIXSORT_H_INCLUDED /*! \file gim_radixsort.h \author Francisco Len. Based on the work of Michael Herf : "fast floating-point radix sort" Avaliable on http://www.stereopsis.com/radix.html */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_memory.h" /*! \defgroup SORTING \brief Macros for sorting. */ //! @{ struct GIM_RSORT_TOKEN { GUINT32 m_key; GUINT32 m_value; }; //typedef struct _GIM_RSORT_TOKEN GIM_RSORT_TOKEN; //comparator for sorting #define RSORT_TOKEN_COMPARATOR(x, y) ((int)((x.m_key) - (y.m_key))) // ---- utils for accessing 11-bit quantities #define D11_0(x) (x & 0x7FF) #define D11_1(x) (x >> 11 & 0x7FF) #define D11_2(x) (x >> 22 ) //COMMON FUNCTIONS FOR ACCESSING THE KEY OF AN ELEMENT //For the type of your array, you need to declare a macro for obtaining the key, like these: #define SIMPLE_GET_FLOAT32KEY(e,key) {key =(GREAL)(e);} #define SIMPLE_GET_INTKEY(e,key) {key =(GINT32)(e);} #define SIMPLE_GET_UINTKEY(e,key) {key =(GUINT32)(e);} //For the type of your array, you need to declare a macro for copy elements, like this: #define SIMPLE_COPY_ELEMENTS(dest,src) {dest = src;} #define kHist 2048 ///Radix sort for unsigned integer keys #define GIM_RADIX_SORT_RTOKENS(array,sorted,element_count)\ {\ GUINT32 i;\ GUINT32 b0[kHist * 3];\ GUINT32 *b1 = b0 + kHist;\ GUINT32 *b2 = b1 + kHist;\ for (i = 0; i < kHist * 3; i++)\ {\ b0[i] = 0;\ }\ GUINT32 fi;\ GUINT32 pos;\ for (i = 0; i < element_count; i++)\ {\ fi = array[i].m_key;\ b0[D11_0(fi)] ++;\ b1[D11_1(fi)] ++;\ b2[D11_2(fi)] ++;\ }\ {\ GUINT32 sum0 = 0, sum1 = 0, sum2 = 0;\ GUINT32 tsum;\ for (i = 0; i < kHist; i++)\ {\ tsum = b0[i] + sum0;\ b0[i] = sum0 - 1;\ sum0 = tsum;\ tsum = b1[i] + sum1;\ b1[i] = sum1 - 1;\ sum1 = tsum;\ tsum = b2[i] + sum2;\ b2[i] = sum2 - 1;\ sum2 = tsum;\ }\ }\ for (i = 0; i < element_count; i++)\ {\ fi = array[i].m_key;\ pos = D11_0(fi);\ pos = ++b0[pos];\ sorted[pos].m_key = array[i].m_key;\ sorted[pos].m_value = array[i].m_value;\ }\ for (i = 0; i < element_count; i++)\ {\ fi = sorted[i].m_key;\ pos = D11_1(fi);\ pos = ++b1[pos];\ array[pos].m_key = sorted[i].m_key;\ array[pos].m_value = sorted[i].m_value;\ }\ for (i = 0; i < element_count; i++)\ {\ fi = array[i].m_key;\ pos = D11_2(fi);\ pos = ++b2[pos];\ sorted[pos].m_key = array[i].m_key;\ sorted[pos].m_value = array[i].m_value;\ }\ }\ /// Get the sorted tokens from an array. For generic use. Tokens are GIM_RSORT_TOKEN #define GIM_RADIX_SORT_ARRAY_TOKENS(array, sorted_tokens, element_count, get_uintkey_macro)\ {\ GIM_RSORT_TOKEN * _unsorted = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN )*element_count);\ GUINT32 _i;\ for (_i=0;_i 0)\ {\ _stack_index_ --;\ _start_ = _start_stack_[_stack_index_];\ _end_ = _end_stack_[_stack_index_];\ while (_end_ - _start_ > 2)\ {\ _p_ = _start_;\ _i_ = _start_ + 1;\ _j_ = _end_ - 1;\ while (_i_<_j_) \ {\ for(; _i_<=_j_ && comp_macro(((array)[_i_]),((array)[_p_]))<=0; _i_++) ;\ if (_i_ > _j_) \ {\ exchange_macro(type, array, _j_, _p_);\ _i_ = _j_;\ }\ else\ {\ for(; _i_<=_j_ && comp_macro(((array)[_j_]),((array)[_p_]))>=0; _j_--) ;\ if (_i_ > _j_) \ {\ exchange_macro(type, array, _j_, _p_);\ _i_ = _j_;\ }\ else if (_i_ < _j_)\ {\ exchange_macro(type, array, _i_, _j_);\ if (_i_+2 < _j_) {_i_++; _j_--;}\ else if (_i_+1 < _j_) _i_++;\ }\ }\ }\ if (_i_-_start_ > 1 && _end_-_j_ > 1) \ {\ if (_i_-_start_ < _end_-_j_-1) \ {\ _start_stack_[_stack_index_] = _j_+1;\ _end_stack_[_stack_index_] = _end_;\ _stack_index_ ++;\ _end_ = _i_;\ }\ else\ {\ _start_stack_[_stack_index_] = _start_;\ _end_stack_[_stack_index_] = _i_;\ _stack_index_ ++;\ _start_ = _j_+1;\ }\ }\ else\ {\ if (_i_-_start_ > 1)\ {\ _end_ = _i_;\ }\ else \ {\ _start_ = _j_+1;\ }\ }\ }\ if (_end_ - _start_ == 2) \ {\ if (comp_macro(((array)[_start_]),((array)[_end_-1])) > 0) \ {\ exchange_macro(type, array, _start_, _end_-1);\ }\ }\ }\ }\ #define GIM_DEF_EXCHANGE_MACRO(type, _array, _i, _j)\ {\ type _e_tmp_ =(_array)[(_i)];\ (_array)[(_i)]=(_array)[(_j)];\ (_array)[(_j)]= _e_tmp_;\ }\ #define GIM_COMP_MACRO(x, y) ((GINT32)((x) - (y))) //! @} #endif // GIM_RADIXSORT_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_tri_capsule_collision.h0000644000000000000000000000707712635011627022106 0ustar rootroot#ifndef GIM_TRI_CAPSULE_COLLISION_H_INCLUDED #define GIM_TRI_CAPSULE_COLLISION_H_INCLUDED /*! \file gim_tri_capsule_collision.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_memory.h" /*! \addtogroup GEOMETRIC_OPERATIONS */ //! @{ //! Capsule struct struct GIM_CAPSULE_DATA { GREAL m_radius; vec3f m_point1; vec3f m_point2; }; //typedef struct _GIM_CAPSULE_DATA GIM_CAPSULE_DATA; #define CALC_CAPSULE_AABB(capsule,aabb)\ {\ if(capsule.m_point1[0]G_EPSILON ?1:0; \ if(_classif == 0) \ { \ if(_prevclassif==1) \ {\ if(clipped_count u*axe1[i1] + ((vecproj[i2] - u*axe1[i2])/axe2[i2])*axe2[i1] = vecproj[i1] --> u*axe1[i1] + vecproj[i2]*axe2[i1]/axe2[i2] - u*axe1[i2]*axe2[i1]/axe2[i2] = vecproj[i1] --> u*(axe1[i1] - axe1[i2]*axe2[i1]/axe2[i2]) = vecproj[i1] - vecproj[i2]*axe2[i1]/axe2[i2] --> u*((axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1])/axe2[i2]) = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1])/axe2[i2] --> u*(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1]) = vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1] --> u = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]) /(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1]) if 0.0<= u+v <=1.0 then they are inside of triangle */ #define TRIANGLE_GET_UVPARAMETERS(point,vec1,vec2,vec3,tri_plane,u,v,outside)\ {\ vec3f _axe1, _axe2, _vecproj;\ VEC_DIFF(_axe1,vec2,vec1);\ VEC_DIFF(_axe2,vec3,vec1);\ VEC_DIFF(_vecproj,point,vec1);\ GUINT32 _i1,_i2;\ PLANE_MINOR_AXES(tri_plane, _i1, _i2);\ if(fabsf(_axe2[_i2])G_EPSILON)\ {\ outside = 1;\ }\ else\ {\ outside = 0;\ }\ }\ }\ //! Finds the collision of a ray and a triangle. #define RAY_TRIANGLE_INTERSECTION(vOrigin,vDir,vec1,vec2,vec3,tri_plane,pout,u,v,tparam,tmax,does_intersect)\ {\ RAY_PLANE_COLLISION(tri_plane,vDir,vOrigin,pout,tparam,does_intersect);\ if(does_intersect != 0)\ {\ if(tparam<-G_EPSILON||tparam>tmax+G_EPSILON)\ {\ does_intersect = 0;\ }\ else\ {\ TRIANGLE_GET_UVPARAMETERS(pout,vec1,vec2,vec3,tri_plane,u,v,does_intersect);\ does_intersect = !does_intersect;\ }\ }\ }\ //! @} #endif // GIM_TRI_COLLISION_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_tri_sphere_collision.h0000644000000000000000000000343112635011627021726 0ustar rootroot#ifndef GIM_TRI_SPHERE_COLLISION_H_INCLUDED #define GIM_TRI_SPHERE_COLLISION_H_INCLUDED /*! \file gim_tri_sphere_collision.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ /*! \addtogroup GEOMETRIC_OPERATIONS */ //! @{ //! Finds the contact points from a collision of a triangle and a sphere /*! \param tri \param center \param radius \param contact_data Contains the closest points on the Sphere, and the normal is pointing to triangle */ int gim_triangle_sphere_collision( GIM_TRIANGLE_DATA *tri, vec3f center, GREAL radius, GIM_TRIANGLE_CONTACT_DATA * contact_data); //! @} #endif // GIM_TRI_SPHERE_COLLISION_H_INCLUDED ode-0.14/GIMPACT/include/GIMPACT/gim_trimesh.h0000644000000000000000000004331212635011627017164 0ustar rootroot#ifndef GIM_TRIMESH_H_INCLUDED #define GIM_TRIMESH_H_INCLUDED /*! \file gim_trimesh.h \author Francisco Len */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_boxpruning.h" #include "GIMPACT/gim_contact.h" ///MAsk defines #define GIM_TRIMESH_TRANSFORMED_REPLY 1 #define GIM_TRIMESH_NEED_UPDATE 2 /*! \addtogroup TRIMESH \brief A Trimesh is the basic geometric structure for representing solid objects.

    CREATING TRIMESHES

    • For creating trimeshes, you must initialize Buffer managers by calling \ref gimpact_init
    • Then you must define the vertex and index sources by creating them with \ref BUFFER_ARRAYS routines, and then call \ref gim_trimesh_create_from_arrays.
    • An alternative way for creaing trimesh objects is calling \ref gim_trimesh_create_from_data.
    • For access to the trimesh data (vertices, triangle indices), you must call \ref gim_trimesh_locks_work_data , and \ref gim_trimesh_unlocks_work_data for finish the access.
    • Each time when the trimesh data is modified, you must call \ref gim_trimesh_update after.
    • When a trimesh is no longer needed, you must call \ref gim_trimesh_destroy.

    This is an example of how to create a deformable trimesh that shares vertices with the user application:

    \code //Declaration of vertices vec3f trimeshvertices[200]; //Declaration of indices GUINT trimeshindices[100]; ... Initializing vertices and triangle indices at beginning //Then create trimesh GIM_TRIMESH mytrimesh; //Calling trimesh create function gim_trimesh_create_from_data( &mytrimesh, trimeshvertices,200, 0 ,//copy_vertices is 0 trimeshindices, 100, 0, //copy_indices is 0 0 //transformed_reply is 0 ); \endcode

    Note that parameter transformed_reply is 0, that means that m_transformed_vertex_buffer is a reference to m_source_vertex on the trimesh, and transformations are not avaliable. Use that configuration if you have to simulate a deformable trimesh like cloth or elastic bodies.

    When the trimesh is no longer needed, destroy it safely with gim_trimesh_destroy()

    UPDATING TRIMESHES

    On simulation loops, is needed to update trimeshes every time for update vertices althought updating triangle boxes and planes cache. There is two ways for update trimeshes:

    • Updating vertices directly. You need to access to the \ref GIM_TRIMESH.m_source_vertex_buffer member; a vertex buffer which has access to the source vertices. \code // Access to the source vertices gim_buffer_array_lock(&mytrimesh.m_source_vertex_buffer, G_MA_READ_WRITE); //Get a pointer to the vertex buffer vec3f * vertexpointer = GIM_BUFFER_ARRAY_POINTER(vec3f,mytrimesh.m_source_vertex_buffer,0); //Get the amount of vertices int veccount = mytrimesh.m_source_vertex_buffer.m_element_count; //Modify vertices for (int i=0;itransformed_reply = 0.
    • Aplying a transformation. Simply use \ref gim_trimesh_set_tranform . Remember that with this method trimeshes must be created with \ref gim_trimesh_create_from_data with parameter transformed_reply = 1.

    After updating vertices, you must call \ref gim_trimesh_update()

    TRIMESHES COLLISION

    Before collide trimeshes, you need to update them first.

    Then you must use \ref gim_trimesh_trimesh_collision().

    */ //! @{ //! Prototype for updating vertices typedef void * gim_update_trimesh_function(struct _GIM_TRIMESH *); //! Trimesh struct GIM_TRIMESH { ///Original //@{ GBUFFER_ARRAY m_source_vertex_buffer;//!< Buffer of vec3f coordinates //! (GUINT) Indices of triangles,groups of three elements. /*! Array of GUINT. Triangle indices. Each triple contains indices of the vertices for each triangle. \invariant must be aligned */ GBUFFER_ARRAY m_tri_index_buffer; //@} ///Allocated //@{ char m_mask;//!< Don't use directly //! Allocated transformed vertices vec3f /*! Array of vec3f.If gim_trimesh_has_tranformed_reply(this) == 1 then it refers to the m_source_vertex_buffer \invariant must be aligned */ GBUFFER_ARRAY m_transformed_vertex_buffer; //@} ///Auxiliary data //@{ GIM_AABB_SET m_aabbset; GDYNAMIC_ARRAY m_planes_cache_buffer;//! Allocated GIM_TRIPLANES_CACHE GDYNAMIC_ARRAY m_planes_cache_bitset; gim_update_trimesh_function * m_update_callback;//! If null, then m_transform is applied. mat4f m_transform; //@} }; //typedef struct _GIM_TRIMESH GIM_TRIMESH; /// Info about mesh //! Return the trimesh triangle count GUINT32 gim_trimesh_get_triangle_count(GIM_TRIMESH * trimesh); //! Returns 1 if the m_transformed_vertex_buffer is a reply of m_source_vertex_buffer char gim_trimesh_has_tranformed_reply(GIM_TRIMESH * trimesh); //! Returns 1 if the trimesh needs to update their aabbset and the planes cache. char gim_trimesh_needs_update(GIM_TRIMESH * trimesh); //! Change the state of the trimesh for force it to update /*! Call it after made changes to the trimesh. \post gim_trimesh_need_update(trimesh) will return 1 \sa gim_trimesh_needs_update,gim_trimesh_has_tranformed_reply */ void gim_trimesh_post_update(GIM_TRIMESH * trimesh); //! Creates the aabb set and the triangles cache /*! \param trimesh \param vertex_array \param triindex_array \param transformed_reply If 1, then the m_transformed_vertices is a reply of the source vertices. Else it just be a reference to the original array. \post it copies the arrays by reference, and creates the auxiliary data (m_aabbset,m_planes_cache_buffer) */ void gim_trimesh_create_from_arrays(GBUFFER_MANAGER_DATA buffer_managers[], GIM_TRIMESH * trimesh, GBUFFER_ARRAY * vertex_array, GBUFFER_ARRAY * triindex_array,char transformed_reply); //! Create a trimesh from vertex array and an index array /*! \param trimesh An uninitialized GIM_TRIMESH structure \param vertex_array A buffer to a vec3f array \param vertex_count \param triindex_array \param index_count \param copy_vertices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data. \param copy_indices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data. \param transformed_reply If 1, then the m_transformed_vertices is a reply of the source vertices. Else it just be a reference to the original array. Use 1 if you will apply transformations to the trimesh. See \ref gim_trimesh_set_tranform(). */ void gim_trimesh_create_from_data(GBUFFER_MANAGER_DATA buffer_managers[], GIM_TRIMESH * trimesh, vec3f * vertex_array, GUINT32 vertex_count,char copy_vertices, GUINT32 * triindex_array, GUINT32 index_count,char copy_indices,char transformed_reply); //! Clears auxiliary data and releases buffer arrays void gim_trimesh_destroy(GIM_TRIMESH * trimesh); //! Copies two meshes /*! \param source_trimesh \param dest_trimesh \param copy_by_reference If 1, it attach a reference to the source vertices, else it copies the vertices \param transformed_reply If 1, transformed vertices are reply of source vertives. 1 Is recommended */ void gim_trimesh_copy(GIM_TRIMESH * source_trimesh, GBUFFER_MANAGER_DATA dest_buffer_managers[], GIM_TRIMESH * dest_trimesh, char copy_by_reference, char transformed_reply); //! Locks the trimesh for working with it /*! \post locks m_tri_index_buffer and m_transformed_vertex_buffer. \param trimesh */ void gim_trimesh_locks_work_data(GIM_TRIMESH * trimesh); //! unlocks the trimesh /*! \post unlocks m_tri_index_buffer and m_transformed_vertex_buffer. \param trimesh */ void gim_trimesh_unlocks_work_data(GIM_TRIMESH * trimesh); //! Updates m_transformed_vertex_buffer /*! \pre m_transformed_vertex_buffer must be unlocked */ void gim_trimesh_update_vertices(GIM_TRIMESH * trimesh); //! Updates m_aabbset and m_planes_cache_bitset /*! \pre gim_trimesh_locks_work_data must be called before */ void gim_trimesh_update_aabbset(GIM_TRIMESH * trimesh); //! Calls before perfom collisions. Updates the trimesh if needed /*! \post If gim_trimesh_needs_update returns 1, then it calls gim_trimesh_update_vertices and gim_trimesh_update_aabbset */ void gim_trimesh_update(GIM_TRIMESH * trimesh); //! Set the transform of a trimesh /*! \post This function calls to gim_trimesh_post_update */ void gim_trimesh_set_tranform(GIM_TRIMESH * trimesh, mat4f transform); //! Fetch triangle data /*! \pre gim_trimesh_locks_work_data must be called before */ void gim_trimesh_get_triangle_data(GIM_TRIMESH * trimesh, GUINT32 triangle_index, GIM_TRIANGLE_DATA * tri_data); //! Fetch triangle vertices /*! \pre gim_trimesh_locks_work_data must be called before */ void gim_trimesh_get_triangle_vertices(GIM_TRIMESH * trimesh, GUINT32 triangle_index, vec3f v1,vec3f v2,vec3f v3); //! Trimesh Trimesh Collisions /*! Before use this function you must update each trimesh: \code gim_trimesh_update(TriMesh1); gim_trimesh_update(TriMesh2); \endcode Then you must use the trimesh collision in this way: \code int collide_trimeshes(GIM_TRIMESH * TriMesh1, GIM_TRIMESH * TriMesh2) { //Create contact list GDYNAMIC_ARRAY trimeshcontacts; GIM_CREATE_CONTACT_LIST(trimeshcontacts); //Collide trimeshes gim_trimesh_trimesh_collision(TriMesh1,TriMesh2,&trimeshcontacts); if(trimeshcontacts.m_size == 0) //do nothing { GIM_DYNARRAY_DESTROY(trimeshcontacts);//clean contact array return 0; } //Getting a pointer to the contact array GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); int contactcount = trimeshcontacts.m_size; int i; //Process contacts for (i=0;i
  • m_handle1 points to trimesh1.
  • m_handle2 points to trimesh2.
  • m_feature1 Is a triangle index of trimesh1.
  • m_feature2 Is a triangle index of trimesh2. \param trimesh1 Collider \param trimesh2 Collidee \param contacts A GIM_CONTACT array. Must be initialized */ void gim_trimesh_trimesh_collision(GIM_TRIMESH * trimesh1, GIM_TRIMESH * trimesh2, GDYNAMIC_ARRAY * contacts); //! Trimesh Sphere Collisions /*! Before use this function you must update the trimesh: \code gim_trimesh_update(trimesh); \endcode Then you must use this function in this way: \code int collide_trimesh_sphere(GIM_TRIMESH * trimesh, vec3f center,GREAL radius) { //Create contact list GDYNAMIC_ARRAY trimeshcontacts; GIM_CREATE_CONTACT_LIST(trimeshcontacts); //Collide trimeshes gim_trimesh_sphere_collision(trimesh,center,radius,&trimeshcontacts); if(trimeshcontacts.m_size == 0) //do nothing { GIM_DYNARRAY_DESTROY(trimeshcontacts);//clean contact array return 0; } //Getting a pointer to the contact array GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); int contactcount = trimeshcontacts.m_size; int i; //Process contacts for (i=0;i
  • m_handle1 points to trimesh.
  • m_handle2 points to NULL.
  • m_feature1 Is a triangle index of trimesh. \param trimesh \param center \param radius \param contacts A GIM_CONTACT array. Must be initialized */ void gim_trimesh_sphere_collision(GIM_TRIMESH * trimesh,vec3f center,GREAL radius, GDYNAMIC_ARRAY * contacts); //! Trimesh Capsule collision /*! Find the closest primitive collided by the ray. Before use this function you must update the trimesh: \code gim_trimesh_update(trimesh); \endcode Then you must use this function in this way: \code int collide_trimesh_capsule(GIM_TRIMESH * trimesh, GIM_CAPSULE_DATA * capsule) { //Create contact list GDYNAMIC_ARRAY trimeshcontacts; GIM_CREATE_CONTACT_LIST(trimeshcontacts); //Collide trimeshes gim_trimesh_capsule_collision(trimesh,capsule,&trimeshcontacts); if(trimeshcontacts.m_size == 0) //do nothing { GIM_DYNARRAY_DESTROY(trimeshcontacts);//clean contact array return 0; } //Getting a pointer to the contact array GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); int contactcount = trimeshcontacts.m_size; int i; //Process contacts for (i=0;i
  • m_handle1 points to trimesh.
  • m_handle2 points to NULL.
  • m_feature1 Is a triangle index of trimesh. \param trimesh \param capsule \param contacts A GIM_CONTACT array. Must be initialized */ void gim_trimesh_capsule_collision(GIM_TRIMESH * trimesh, GIM_CAPSULE_DATA * capsule, GDYNAMIC_ARRAY * contacts); ///Function for create Trimesh Plane collision result #define GIM_CREATE_TRIMESHPLANE_CONTACTS(dynarray) GIM_DYNARRAY_CREATE(vec4f,dynarray,G_ARRAY_GROW_SIZE) //! Trimesh Plane Collisions /*! Before use this function you must update the trimesh: \code gim_trimesh_update(trimesh); \endcode Then you must use this function in this way: \code int collide_trimesh_plane(GIM_TRIMESH * trimesh, vec4f plane) { //Create contact list GDYNAMIC_ARRAY tri_plane_contacts; GIM_CREATE_TRIMESHPLANE_CONTACTS(tri_plane_contacts); //Collide trimeshes gim_trimesh_plane_collision(trimesh,plane,&tri_plane_contacts); if(tri_plane_contacts.m_size == 0) //do nothing { GIM_DYNARRAY_DESTROY(tri_plane_contacts);//clean contact array return 0; } //Getting a pointer to the contact array vec4f * planecontacts = GIM_DYNARRAY_POINTER(vec4f,tri_plane_contacts); int contactcount = tri_plane_contacts.m_size; int i; //Process contacts for (i=0;im_count = count; aabbset->m_boxes = (aabb3f *)gim_alloc(sizeof(aabb3f)*count); if(countm_maxcoords = 0; aabbset->m_sorted_mincoords = 0; } else { aabbset->m_maxcoords = (GUINT32 *)gim_alloc(sizeof(GUINT32)*aabbset->m_count ); aabbset->m_sorted_mincoords = (GIM_RSORT_TOKEN *)gim_alloc(sizeof(GIM_RSORT_TOKEN)*aabbset->m_count); } aabbset->m_shared = 0; INVALIDATE_AABB(aabbset->m_global_bound); } //! Destroys the aabb set. void gim_aabbset_destroy(GIM_AABB_SET * aabbset) { aabbset->m_count = 0; if(aabbset->m_shared==0) { gim_free(aabbset->m_boxes,0); gim_free(aabbset->m_maxcoords,0); gim_free(aabbset->m_sorted_mincoords,0); } aabbset->m_boxes = 0; aabbset->m_sorted_mincoords = 0; aabbset->m_maxcoords = 0; } void gim_aabbset_calc_global_bound(GIM_AABB_SET * aabbset) { aabb3f * paabb = aabbset->m_boxes; aabb3f * globalbox = &aabbset->m_global_bound; AABB_COPY((*globalbox),(*paabb)); GUINT32 count = aabbset->m_count-1; paabb++; while(count) { MERGEBOXES(*globalbox,*paabb) paabb++; count--; } } //! Sorts the boxes for box prunning. /*! 1) find the integer representation of the aabb coords 2) Sorts the min coords 3) Calcs the global bound \pre aabbset must be allocated. And the boxes must be already set. \param aabbset \param calc_global_bound If 1 , calcs the global bound \post If aabbset->m_sorted_mincoords == 0, then it allocs the sorted coordinates */ void gim_aabbset_sort(GIM_AABB_SET * aabbset, char calc_global_bound) { if(aabbset->m_sorted_mincoords == 0) {//allocate aabbset->m_maxcoords = (GUINT32 *)gim_alloc(sizeof(GUINT32)*aabbset->m_count ); aabbset->m_sorted_mincoords = (GIM_RSORT_TOKEN *)gim_alloc(sizeof(GIM_RSORT_TOKEN)*aabbset->m_count); } GUINT32 i, count = aabbset->m_count; aabb3f * paabb = aabbset->m_boxes; GUINT32 * maxcoords = aabbset->m_maxcoords; GIM_RSORT_TOKEN * sorted_tokens = aabbset->m_sorted_mincoords; if(count<860)//Calibrated on a Pentium IV { //Sort by quick sort //Calculate keys for(i=0;im_index1 = i;\ _pair->m_index2 = j;\ } #define PUSH_PAIR_INV(i,j,pairset)\ {\ GIM_DYNARRAY_PUSH_EMPTY(GIM_PAIR,pairset);\ GIM_PAIR * _pair = GIM_DYNARRAY_POINTER(GIM_PAIR,pairset) + (pairset).m_size - 1;\ _pair->m_index1 = j;\ _pair->m_index2 = i;\ } #define FIND_OVERLAPPING_FOWARD(\ curr_index,\ test_count,\ test_aabb,\ max_coord_uint,\ sorted_tokens,\ aabbarray,\ pairset,\ push_pair_macro)\ {\ GUINT32 _i = test_count;\ char _intersected;\ GIM_RSORT_TOKEN * _psorted_tokens = sorted_tokens;\ while(_i>0 && max_coord_uint >= _psorted_tokens->m_key)\ {\ AABBCOLLISION(_intersected,test_aabb,aabbarray[_psorted_tokens->m_value]);\ if(_intersected)\ {\ push_pair_macro(curr_index, _psorted_tokens->m_value,pairset);\ }\ _psorted_tokens++;\ _i--;\ }\ } //! log(N) Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. /*! \pre aabbset must be allocated and sorted, the boxes must be already set. \param aabbset Must be sorted. Global bound isn't required \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_self_intersections_sorted(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs) { collision_pairs->m_size = 0; GUINT32 count = aabbset->m_count; aabb3f * paabb = aabbset->m_boxes; GUINT32 * maxcoords = aabbset->m_maxcoords; GIM_RSORT_TOKEN * sorted_tokens = aabbset->m_sorted_mincoords; aabb3f test_aabb; while(count>1) { ///current cache variables GUINT32 curr_index = sorted_tokens->m_value; GUINT32 max_coord_uint = maxcoords[curr_index]; AABB_COPY(test_aabb,paabb[curr_index]); ///next pairs sorted_tokens++; count--; FIND_OVERLAPPING_FOWARD( curr_index, count, test_aabb, max_coord_uint, sorted_tokens , paabb, (*collision_pairs),PUSH_PAIR); } } //! NxN Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. /*! \pre aabbset must be allocated, the boxes must be already set. \param aabbset Global bound isn't required. Doen't need to be sorted. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_self_intersections_brute_force(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs) { collision_pairs->m_size = 0; GUINT32 i,j; GUINT32 count = aabbset->m_count; aabb3f * paabb = aabbset->m_boxes; char intersected; for (i=0;i< count-1 ;i++ ) { for (j=i+1;jm_size = 0; AABBCOLLISION(intersected,aabbset1->m_global_bound,aabbset2->m_global_bound); if(intersected == 0) return; GUINT32 count1 = aabbset1->m_count; aabb3f * paabb1 = aabbset1->m_boxes; GUINT32 * maxcoords1 = aabbset1->m_maxcoords; GIM_RSORT_TOKEN * sorted_tokens1 = aabbset1->m_sorted_mincoords; GUINT32 count2 = aabbset2->m_count; aabb3f * paabb2 = aabbset2->m_boxes; GUINT32 * maxcoords2 = aabbset2->m_maxcoords; GIM_RSORT_TOKEN * sorted_tokens2 = aabbset2->m_sorted_mincoords; GUINT32 curr_index; GUINT32 max_coord_uint; aabb3f test_aabb; //Classify boxes //Find Set intersection aabb3f int_abbb; BOXINTERSECTION(aabbset1->m_global_bound,aabbset2->m_global_bound, int_abbb); //Clasify set 1 GIM_RSORT_TOKEN * classified_tokens1 = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*count1); GUINT32 i,classified_count1 = 0,classified_count2 = 0; for (i=0;i0&&classified_count2>0) { if(sorted_tokens1->m_key <= sorted_tokens2->m_key) { ///current cache variables curr_index = sorted_tokens1->m_value; max_coord_uint = maxcoords1[curr_index]; AABB_COPY(test_aabb,paabb1[curr_index]); ///next pairs sorted_tokens1++; classified_count1--; FIND_OVERLAPPING_FOWARD( curr_index, classified_count2, test_aabb, max_coord_uint, sorted_tokens2 , paabb2, (*collision_pairs), PUSH_PAIR); } else ///Switch test { ///current cache variables curr_index = sorted_tokens2->m_value; max_coord_uint = maxcoords2[curr_index]; AABB_COPY(test_aabb,paabb2[curr_index]); ///next pairs sorted_tokens2++; classified_count2--; FIND_OVERLAPPING_FOWARD( curr_index, classified_count1, test_aabb, max_coord_uint, sorted_tokens1 , paabb1, (*collision_pairs), PUSH_PAIR_INV ); } } gim_free(classified_tokens1 ,0); gim_free(classified_tokens2 ,0); } //! NxM Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. /*! \pre aabbset1 and aabbset2 must be allocated and sorted, the boxes must be already set. \param aabbset1 Must be sorted, Global bound is required. \param aabbset2 Must be sorted, Global bound is required. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_bipartite_intersections_brute_force(GIM_AABB_SET * aabbset1,GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs) { char intersected; collision_pairs->m_size = 0; AABBCOLLISION(intersected,aabbset1->m_global_bound,aabbset2->m_global_bound); if(intersected == 0) return; aabb3f int_abbb; //Find Set intersection BOXINTERSECTION(aabbset1->m_global_bound,aabbset2->m_global_bound, int_abbb); //Clasify set 1 GUINT32 i,j; GUINT32 classified_count = 0; GUINT32 count = aabbset1->m_count; aabb3f * paabb1 = aabbset1->m_boxes; aabb3f * paabb2 = aabbset2->m_boxes; GUINT32 * classified = (GUINT32 *) gim_alloc(sizeof(GUINT32)*count); for (i=0;im_count; for (i=0;im_count < GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES) {//Brute force approach gim_aabbset_calc_global_bound(aabbset); } else {//Sorted force approach gim_aabbset_sort(aabbset,1); } } //! Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. /*! This function sorts the set and then it calls to gim_aabbset_self_intersections_brute_force or gim_aabbset_self_intersections_sorted. \param aabbset Set of boxes. Sorting isn't required. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) \pre aabbset must be allocated and initialized. \post If aabbset->m_count >= GIM_MIN_SORTED_PRUNING_BOXES, then it calls to gim_aabbset_sort and then to gim_aabbset_self_intersections_sorted. */ void gim_aabbset_self_intersections(GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collision_pairs) { if(aabbset->m_count < GIM_MIN_SORTED_PRUNING_BOXES) {//Brute force approach gim_aabbset_self_intersections_brute_force(aabbset,collision_pairs); } else {//Sorted force approach gim_aabbset_sort(aabbset,0); gim_aabbset_self_intersections_sorted(aabbset,collision_pairs); } } //! Collides two sets. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. /*! \pre aabbset1 and aabbset2 must be allocated and updated. See . \param aabbset1 Must be sorted, Global bound is required. \param aabbset2 Must be sorted, Global bound is required. \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100) */ void gim_aabbset_bipartite_intersections(GIM_AABB_SET * aabbset1, GIM_AABB_SET * aabbset2, GDYNAMIC_ARRAY * collision_pairs) { if(aabbset1->m_sorted_mincoords == 0||aabbset2->m_sorted_mincoords == 0) {//Brute force approach gim_aabbset_bipartite_intersections_brute_force(aabbset1,aabbset2,collision_pairs); } else {//Sorted force approach gim_aabbset_bipartite_intersections_sorted(aabbset1,aabbset2,collision_pairs); } } void gim_aabbset_box_collision(aabb3f *test_aabb, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided) { collided->m_size = 0; char intersected; AABBCOLLISION(intersected,aabbset->m_global_bound,(*test_aabb)); if(intersected == 0) return; GUINT32 i; GUINT32 count = aabbset->m_count; aabb3f * paabb = aabbset->m_boxes; aabb3f _testaabb; AABB_COPY(_testaabb,*test_aabb); for (i=0;i< count;i++ ) { AABBCOLLISION(intersected,paabb[i],_testaabb); if(intersected) { GIM_DYNARRAY_PUSH_ITEM(GUINT32,(*collided),i); } } } void gim_aabbset_ray_collision(vec3f vorigin,vec3f vdir, GREAL tmax, GIM_AABB_SET * aabbset, GDYNAMIC_ARRAY * collided) { collided->m_size = 0; char intersected; GREAL tparam = 0; BOX_INTERSECTS_RAY(aabbset->m_global_bound, vorigin, vdir, tparam, tmax,intersected); if(intersected==0) return; GUINT32 i; GUINT32 count = aabbset->m_count; aabb3f * paabb = aabbset->m_boxes; for (i=0;i< count;i++ ) { BOX_INTERSECTS_RAY(paabb[i], vorigin, vdir, tparam, tmax,intersected); if(intersected) { GIM_DYNARRAY_PUSH_ITEM(GUINT32,(*collided),i); } } (void)tparam; } ode-0.14/GIMPACT/src/gim_contact.cpp0000644000000000000000000001025112635011627015553 0ustar rootroot /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_contact.h" void gim_merge_contacts(GDYNAMIC_ARRAY * source_contacts, GDYNAMIC_ARRAY * dest_contacts) { dest_contacts->m_size = 0; GUINT32 source_count = source_contacts->m_size; GIM_CONTACT * psource_contacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,(*source_contacts)); //create keys GIM_RSORT_TOKEN * keycontacts = (GIM_RSORT_TOKEN * )gim_alloc(sizeof(GIM_RSORT_TOKEN)*source_count); GUINT32 i; for(i=0;im_size;i++) { key = keycontacts[i].m_key; scontact = &psource_contacts[keycontacts[i].m_value]; if(i>0 && last_key == key) { //merge contact if(pcontact->m_depth > scontact->m_depth + CONTACT_DIFF_EPSILON) { GIM_COPY_CONTACTS(pcontact, scontact); } } else {//add new contact GIM_DYNARRAY_PUSH_EMPTY(GIM_CONTACT,(*dest_contacts)); pcontact = GIM_DYNARRAY_POINTER_LAST(GIM_CONTACT,(*dest_contacts)); GIM_COPY_CONTACTS(pcontact, scontact); } last_key = key; } gim_free(keycontacts,0); } void gim_merge_contacts_unique(GDYNAMIC_ARRAY * source_contacts, GDYNAMIC_ARRAY * dest_contacts) { dest_contacts->m_size = 0; //Traverse the source contacts GUINT32 source_count = source_contacts->m_size; if(source_count==0) return; GIM_CONTACT * psource_contacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,(*source_contacts)); //add the unique contact GIM_CONTACT * pcontact = 0; GIM_DYNARRAY_PUSH_EMPTY(GIM_CONTACT,(*dest_contacts)); pcontact = GIM_DYNARRAY_POINTER_LAST(GIM_CONTACT,(*dest_contacts)); //set the first contact GIM_COPY_CONTACTS(pcontact, psource_contacts); if(source_count==1) return; //scale the first contact VEC_SCALE(pcontact->m_normal,pcontact->m_depth,pcontact->m_normal); psource_contacts++; //Average the contacts GUINT32 i; for(i=1;im_point,pcontact->m_point,psource_contacts->m_point); VEC_ACCUM(pcontact->m_normal,psource_contacts->m_depth,psource_contacts->m_normal); psource_contacts++; } GREAL divide_average = 1.0f/((GREAL)source_count); VEC_SCALE(pcontact->m_point,divide_average,pcontact->m_point); pcontact->m_depth = VEC_DOT(pcontact->m_normal,pcontact->m_normal)*divide_average; GIM_SQRT(pcontact->m_depth,pcontact->m_depth); VEC_NORMALIZE(pcontact->m_normal); /*GREAL normal_len; VEC_INV_LENGTH(pcontact->m_normal,normal_len); VEC_SCALE(pcontact->m_normal,normal_len,pcontact->m_normal); //Deep = LEN(normal)/SQRT(source_count) GIM_SQRT(divide_average,divide_average); pcontact->m_depth = divide_average/normal_len; */ } ode-0.14/GIMPACT/src/gim_math.cpp0000644000000000000000000000323412635011627015054 0ustar rootroot/* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_math.h" #include "stdlib.h" #include "time.h" GREAL gim_inv_sqrt(GREAL f) { GREAL r; GIM_INV_SQRT(f,r); return r; } GREAL gim_sqrt(GREAL f) { GREAL r; GIM_SQRT(f,r); return r; } //!Initializes mathematical functions void gim_init_math() { srand( static_cast< unsigned int >( time( 0 ) ) ); } //! Generates an unit random GREAL gim_unit_random() { GREAL rn = static_cast< GREAL >( rand() ); rn/=(GREAL)RAND_MAX; return rn; } ode-0.14/GIMPACT/src/gim_memory.cpp0000644000000000000000000006464112635011627015444 0ustar rootroot /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include #include #include "GIMPACT/gim_memory.h" #include #include "config.h" //#include "malloc.h" //#include "mm_malloc.h" static gim_alloc_function *g_allocfn = 0; // static gim_alloca_function *g_allocafn = 0; -- a nonsense static gim_realloc_function *g_reallocfn = 0; static gim_free_function *g_freefn = 0; #define VALIDATE_BUFFER_MANAGER(buffer_managers,buffer_manager_id)\ if(buffer_manager_id>=G_BUFFER_MANAGER__MAX) return G_BUFFER_OP_INVALID;\ GBUFFER_MANAGER_DATA * bm_data;\ gim_get_buffer_manager_data(buffer_managers,buffer_manager_id,&bm_data);\ if(bm_data == 0) return G_BUFFER_OP_INVALID;\ #define VALIDATE_BUFFER_ID_PT(buffer_id)\ GBUFFER_MANAGER_DATA * bm_data = buffer_id->m_bm_data;\ if(bm_data == 0) return G_BUFFER_OP_INVALID;\ if(buffer_id->m_buffer_id>=bm_data->m_buffer_array.m_size) return G_BUFFER_OP_INVALID;\ GBUFFER_DATA * pbuffer = GIM_DYNARRAY_POINTER(GBUFFER_DATA,bm_data->m_buffer_array);\ pbuffer += buffer_id->m_buffer_id;\ if(pbuffer->m_buffer_handle==0) return G_BUFFER_OP_INVALID;\ void GIM_BUFFER_ARRAY_DESTROY(GBUFFER_ARRAY & array_data) { gim_buffer_array_unlock(&array_data); gim_buffer_free(&(array_data).m_buffer_id); } void GIM_DYNARRAY_DESTROY(GDYNAMIC_ARRAY & array_data) { if(array_data.m_pdata != 0) { gim_free(array_data.m_pdata,0); array_data.m_reserve_size = 0; array_data.m_size = 0; array_data.m_pdata = 0; } } void gim_set_alloc_handler (gim_alloc_function *fn) { g_allocfn = fn; } /* -- a nonsense void gim_set_alloca_handler (gim_alloca_function *fn) { g_allocafn = fn; } */ void gim_set_realloc_handler (gim_realloc_function *fn) { g_reallocfn = fn; } void gim_set_free_handler (gim_free_function *fn) { g_freefn = fn; } gim_alloc_function *gim_get_alloc_handler() { return g_allocfn; } /* -- a nonsense gim_alloca_function *gim_get_alloca_handler() { return g_allocafn; } */ gim_realloc_function *gim_get_realloc_handler () { return g_reallocfn; } gim_free_function *gim_get_free_handler () { return g_freefn; } void * gim_alloc(size_t size) { void * ptr; /* if (g_allocfn) { ptr = g_allocfn(size); } else */ { ptr = malloc(size);//_mm_malloc(size,0);*/ } assert(ptr); return ptr; } /* -- a nonsense void * gim_alloca(size_t size) { if (g_allocafn) return g_allocafn(size); else return alloca(size); } */ void * gim_realloc(void *ptr, size_t oldsize, size_t newsize) { /*if (g_reallocfn) return g_reallocfn(ptr,oldsize,newsize); else return realloc(ptr,newsize);*/ //return realloc(ptr,newsize); void * newptr = gim_alloc(newsize); size_t copysize = newsize> oldsize? oldsize: newsize; memcpy(newptr,ptr,copysize); gim_free(ptr,oldsize); return newptr; } void gim_free(void *ptr, size_t size) { if (!ptr) return; /* -- if custom allocation function is not used, custom free must not be used too if (g_freefn) { g_freefn(ptr,size); } else */ { free(ptr);//_mm_free(ptr); } } ///******************************* BUFFER MANAGERS ******************************/// //!** Basic buffer prototype functions static GPTR _system_buffer_alloc_function(GUINT32 size,int usage) { void * newdata = gim_alloc(size); memset(newdata,0,size); return (GPTR)newdata; } static GPTR _system_buffer_alloc_data_function(const void * pdata,GUINT32 size,int usage) { void * newdata = gim_alloc(size); memcpy(newdata,pdata,size); return (GPTR)(newdata); } static GPTR _system_buffer_realloc_function(GPTR buffer_handle,GUINT32 oldsize,int old_usage,GUINT32 newsize,int new_usage) { void * newdata = gim_realloc(buffer_handle,oldsize,newsize); return (GPTR)(newdata); } static void _system_buffer_free_function(GPTR buffer_handle,GUINT32 size) { gim_free(buffer_handle,size); } static char * _system_lock_buffer_function(GPTR buffer_handle,int access) { return (char * )(buffer_handle); } static void _system_unlock_buffer_function(GPTR buffer_handle) { } static void _system_download_from_buffer_function( GPTR source_buffer_handle, GUINT32 source_pos, void * destdata, GUINT32 copysize) { char * pdata; pdata = (char *)source_buffer_handle; memcpy(destdata,pdata+source_pos,copysize); } static void _system_upload_to_buffer_function( GPTR dest_buffer_handle, GUINT32 dest_pos, void * sourcedata, GUINT32 copysize) { char * pdata; pdata = (char * )dest_buffer_handle; memcpy(pdata+dest_pos,sourcedata,copysize); } static void _system_copy_buffers_function( GPTR source_buffer_handle, GUINT32 source_pos, GPTR dest_buffer_handle, GUINT32 dest_pos, GUINT32 copysize) { char * pdata1,*pdata2; pdata1 = (char *)source_buffer_handle; pdata2 = (char *)dest_buffer_handle; memcpy(pdata2+dest_pos,pdata1+source_pos,copysize); } static GPTR _shared_buffer_alloc_function(GUINT32 size,int usage) { return 0; } static GPTR _shared_buffer_alloc_data_function(const void * pdata,GUINT32 size,int usage) { return (GPTR)pdata; } #if 0 static GPTR _shared_buffer_realloc_function(GPTR buffer_handle,GUINT32 oldsize,int old_usage,GUINT32 newsize,int new_usage) { return 0; } #endif static void _shared_buffer_free_function(GPTR buffer_handle,GUINT32 size) { } static inline int _is_buffer_manager_data_active(GBUFFER_MANAGER_DATA * bm_data) { return bm_data->m_buffer_array.m_pdata != 0; } static inline void _init_buffer_manager_data(GBUFFER_MANAGER_DATA * bm_data) { bm_data->m_buffer_array.m_pdata = 0; } static const GBUFFER_MANAGER_PROTOTYPE g_bm_prototypes[G_BUFFER_MANAGER__MAX] = { { &_system_buffer_alloc_function, // alloc_fn; &_system_buffer_alloc_data_function, // alloc_data_fn; &_system_buffer_realloc_function, // realloc_fn; &_system_buffer_free_function, // free_fn; &_system_lock_buffer_function, // lock_buffer_fn; &_system_unlock_buffer_function, // unlock_buffer_fn; &_system_download_from_buffer_function, // download_from_buffer_fn; &_system_upload_to_buffer_function, // upload_to_buffer_fn; &_system_copy_buffers_function, // copy_buffers_fn; }, // G_BUFFER_MANAGER_SYSTEM { &_shared_buffer_alloc_function, // alloc_fn; &_shared_buffer_alloc_data_function, // alloc_data_fn; &_system_buffer_realloc_function, // realloc_fn; &_shared_buffer_free_function, // free_fn; &_system_lock_buffer_function, // lock_buffer_fn; &_system_unlock_buffer_function, // unlock_buffer_fn; &_system_download_from_buffer_function, // download_from_buffer_fn; &_system_upload_to_buffer_function, // upload_to_buffer_fn; &_system_copy_buffers_function, // copy_buffers_fn; }, // G_BUFFER_MANAGER_SHARED }; int gim_is_buffer_manager_active(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id) { GBUFFER_MANAGER_DATA * bm_data; bm_data = &buffer_managers[buffer_manager_id]; return _is_buffer_manager_data_active(bm_data); } //!** Buffer manager operations void gim_create_buffer_manager(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id) { GBUFFER_MANAGER_DATA * bm_data; bm_data = &buffer_managers[buffer_manager_id]; if (_is_buffer_manager_data_active(bm_data)) { gim_destroy_buffer_manager(buffer_managers, buffer_manager_id); } //CREATE ARRAYS GIM_DYNARRAY_CREATE(GBUFFER_DATA,bm_data->m_buffer_array,G_ARRAY_BUFFERMANAGER_INIT_SIZE); GIM_DYNARRAY_CREATE(GUINT32,bm_data->m_free_positions,G_ARRAY_BUFFERMANAGER_INIT_SIZE); bm_data->m_prototype = g_bm_prototypes + buffer_manager_id; bm_data->m_buffer_manager_id = buffer_manager_id; } void gim_destroy_buffer_manager(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id) { GBUFFER_MANAGER_DATA * bm_data; gim_get_buffer_manager_data(buffer_managers,buffer_manager_id,&bm_data); if(bm_data == 0) return; //Destroy all buffers GBUFFER_DATA * buffers = GIM_DYNARRAY_POINTER(GBUFFER_DATA,bm_data->m_buffer_array); GUINT32 i, buffer_count = bm_data->m_buffer_array.m_size; for (i=0;im_buffer_handle!=0) //Is active { // free handle bm_data->m_prototype->free_fn(current_buffer->m_buffer_handle,current_buffer->m_size); } } //destroy buffer array GIM_DYNARRAY_DESTROY(bm_data->m_buffer_array); //destroy free positions GIM_DYNARRAY_DESTROY(bm_data->m_free_positions); } void gim_get_buffer_manager_data(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id,GBUFFER_MANAGER_DATA ** pbm_data) { GBUFFER_MANAGER_DATA * bm_data; bm_data = &buffer_managers[buffer_manager_id]; if (_is_buffer_manager_data_active(bm_data)) { *pbm_data = bm_data; } else { *pbm_data = 0; } } void gim_init_buffer_managers(GBUFFER_MANAGER_DATA buffer_managers[]) { GUINT32 i; for (i=0;im_free_positions.m_size>0)\ { GUINT32 * _pointer = GIM_DYNARRAY_POINTER(GUINT32,buffer_manager->m_free_positions); buffer_id = _pointer[buffer_manager->m_free_positions.m_size-1]; GIM_DYNARRAY_POP_ITEM(buffer_manager->m_free_positions); } else { buffer_id = buffer_manager->m_buffer_array.m_size; GIM_DYNARRAY_PUSH_EMPTY(GBUFFER_DATA,buffer_manager->m_buffer_array); } } GINT32 _validate_buffer_id(GBUFFER_ID * buffer_id,GBUFFER_DATA ** ppbuffer,GBUFFER_MANAGER_DATA ** pbm_data) { VALIDATE_BUFFER_ID_PT(buffer_id) *ppbuffer = pbuffer; *pbm_data = bm_data; return G_BUFFER_OP_SUCCESS; } GUINT32 gim_create_buffer( GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id, GUINT32 buffer_size, int usage, GBUFFER_ID * buffer_id) { VALIDATE_BUFFER_MANAGER(buffer_managers,buffer_manager_id) GPTR newbufferhandle = bm_data->m_prototype->alloc_fn(buffer_size,usage); if(newbufferhandle==0) return G_BUFFER_OP_INVALID; GET_AVALIABLE_BUFFER_ID(bm_data,buffer_id->m_buffer_id); buffer_id->m_bm_data = bm_data; GBUFFER_DATA * pbuffer = GIM_DYNARRAY_POINTER(GBUFFER_DATA,bm_data->m_buffer_array); pbuffer += buffer_id->m_buffer_id ; pbuffer->m_buffer_handle = newbufferhandle; pbuffer->m_size = buffer_size; pbuffer->m_usage = usage; pbuffer->m_lock_count = 0; pbuffer->m_refcount = 0; pbuffer->m_mapped_pointer = 0; //set shadow buffer if needed if(usage == G_MU_STATIC_READ || usage == G_MU_STATIC_READ_DYNAMIC_WRITE|| usage == G_MU_STATIC_READ_DYNAMIC_WRITE_COPY) { gim_create_common_buffer(buffer_managers,buffer_size,&pbuffer->m_shadow_buffer); } else { pbuffer->m_shadow_buffer.m_bm_data = 0; pbuffer->m_shadow_buffer.m_buffer_id = G_UINT_INFINITY; } return G_BUFFER_OP_SUCCESS; } GUINT32 gim_create_buffer_from_data( GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_manager_id, const void * pdata, GUINT32 buffer_size, int usage, GBUFFER_ID * buffer_id) { VALIDATE_BUFFER_MANAGER(buffer_managers,buffer_manager_id) GPTR newbufferhandle = bm_data->m_prototype->alloc_data_fn(pdata,buffer_size,usage); if(newbufferhandle==0) return G_BUFFER_OP_INVALID; GET_AVALIABLE_BUFFER_ID(bm_data,buffer_id->m_buffer_id); buffer_id->m_bm_data = bm_data; GBUFFER_DATA * pbuffer = GIM_DYNARRAY_POINTER(GBUFFER_DATA,bm_data->m_buffer_array); pbuffer += buffer_id->m_buffer_id ; pbuffer->m_buffer_handle = newbufferhandle; pbuffer->m_size = buffer_size; pbuffer->m_usage = usage; pbuffer->m_lock_count = 0; pbuffer->m_mapped_pointer = 0; pbuffer->m_refcount = 0; //set shadow buffer if needed if(usage == G_MU_STATIC_READ || usage == G_MU_STATIC_READ_DYNAMIC_WRITE|| usage == G_MU_STATIC_READ_DYNAMIC_WRITE_COPY) { gim_create_common_buffer_from_data(buffer_managers,pdata,buffer_size,&pbuffer->m_shadow_buffer); } else { pbuffer->m_shadow_buffer.m_bm_data = 0; pbuffer->m_shadow_buffer.m_buffer_id = G_UINT_INFINITY; } return G_BUFFER_OP_SUCCESS; } GUINT32 gim_create_common_buffer(GBUFFER_MANAGER_DATA buffer_managers[], GUINT32 buffer_size, GBUFFER_ID * buffer_id) { return gim_create_buffer(buffer_managers,G_BUFFER_MANAGER_SYSTEM,buffer_size,G_MU_DYNAMIC_READ_WRITE,buffer_id); } GUINT32 gim_create_common_buffer_from_data(GBUFFER_MANAGER_DATA buffer_managers[], const void * pdata, GUINT32 buffer_size, GBUFFER_ID * buffer_id) { return gim_create_buffer_from_data(buffer_managers,G_BUFFER_MANAGER_SYSTEM,pdata,buffer_size,G_MU_DYNAMIC_READ_WRITE,buffer_id); } GUINT32 gim_create_shared_buffer_from_data(GBUFFER_MANAGER_DATA buffer_managers[], const void * pdata, GUINT32 buffer_size, GBUFFER_ID * buffer_id) { return gim_create_buffer_from_data(buffer_managers,G_BUFFER_MANAGER_SHARED,pdata,buffer_size,G_MU_DYNAMIC_READ_WRITE,buffer_id); } GINT32 gim_buffer_realloc(GBUFFER_ID * buffer_id,GUINT32 newsize) { VALIDATE_BUFFER_ID_PT(buffer_id) if(pbuffer->m_lock_count>0) return G_BUFFER_OP_INVALID; GPTR newhandle = buffer_id->m_bm_data->m_prototype->realloc_fn( pbuffer->m_buffer_handle,pbuffer->m_size,pbuffer->m_usage,newsize,pbuffer->m_usage); if(newhandle==0) return G_BUFFER_OP_INVALID; pbuffer->m_buffer_handle = newhandle; //realloc shadow buffer if any gim_buffer_realloc(&pbuffer->m_shadow_buffer,newsize); return G_BUFFER_OP_SUCCESS; } GINT32 gim_buffer_add_ref(GBUFFER_ID * buffer_id) { VALIDATE_BUFFER_ID_PT(buffer_id) pbuffer->m_refcount++; return G_BUFFER_OP_SUCCESS; } GINT32 gim_buffer_free(GBUFFER_ID * buffer_id) { VALIDATE_BUFFER_ID_PT(buffer_id) if(pbuffer->m_lock_count>0) return G_BUFFER_OP_INVALID; if(pbuffer->m_refcount>0) pbuffer->m_refcount--; if(pbuffer->m_refcount>0) return G_BUFFER_OP_STILLREFCOUNTED; buffer_id->m_bm_data->m_prototype->free_fn( pbuffer->m_buffer_handle,pbuffer->m_size); //destroy shadow buffer if needed gim_buffer_free(&pbuffer->m_shadow_buffer); // Obtain a free slot index for a new buffer GIM_DYNARRAY_PUSH_ITEM(GUINT32,bm_data->m_free_positions,buffer_id->m_buffer_id); pbuffer->m_buffer_handle = 0; pbuffer->m_size = 0; pbuffer->m_shadow_buffer.m_bm_data = 0; pbuffer->m_shadow_buffer.m_buffer_id = G_UINT_INFINITY; return G_BUFFER_OP_SUCCESS; } GINT32 gim_lock_buffer(GBUFFER_ID * buffer_id,int access,char ** map_pointer) { VALIDATE_BUFFER_ID_PT(buffer_id) if(pbuffer->m_lock_count>0) { if(pbuffer->m_access!=access) return G_BUFFER_OP_INVALID; pbuffer->m_lock_count++; *map_pointer = pbuffer->m_mapped_pointer; return G_BUFFER_OP_SUCCESS; } pbuffer->m_access = access; GUINT32 result; if(pbuffer->m_usage==G_MU_STATIC_WRITE) { *map_pointer = 0;///no access return G_BUFFER_OP_INVALID; } else if(pbuffer->m_usage==G_MU_STATIC_READ) { if(pbuffer->m_access == G_MA_READ_ONLY) { result = gim_lock_buffer(&pbuffer->m_shadow_buffer,access,map_pointer); if(result!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; pbuffer->m_mapped_pointer = *map_pointer; pbuffer->m_lock_count++; } else { *map_pointer = 0; return G_BUFFER_OP_INVALID; } } else if(pbuffer->m_usage==G_MU_STATIC_READ_DYNAMIC_WRITE) { if(pbuffer->m_access == G_MA_READ_ONLY) { result = gim_lock_buffer(&pbuffer->m_shadow_buffer,access,map_pointer); if(result!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; pbuffer->m_mapped_pointer = *map_pointer; pbuffer->m_lock_count++; } else if(pbuffer->m_access == G_MA_WRITE_ONLY) { pbuffer->m_mapped_pointer = buffer_id->m_bm_data->m_prototype->lock_buffer_fn( pbuffer->m_buffer_handle,access); *map_pointer = pbuffer->m_mapped_pointer; pbuffer->m_lock_count++; } else if(pbuffer->m_access == G_MA_READ_WRITE) { *map_pointer = 0; return G_BUFFER_OP_INVALID; } } else if(pbuffer->m_usage==G_MU_STATIC_READ_DYNAMIC_WRITE_COPY) { result = gim_lock_buffer(&pbuffer->m_shadow_buffer,access,map_pointer); if(result!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; pbuffer->m_mapped_pointer = *map_pointer; pbuffer->m_lock_count++; } else if(pbuffer->m_usage==G_MU_STATIC_WRITE_DYNAMIC_READ) { if(pbuffer->m_access == G_MA_READ_ONLY) { pbuffer->m_mapped_pointer = buffer_id->m_bm_data->m_prototype->lock_buffer_fn( pbuffer->m_buffer_handle,access); *map_pointer = pbuffer->m_mapped_pointer; pbuffer->m_lock_count++; } else { *map_pointer = 0; return G_BUFFER_OP_INVALID; } } else if(pbuffer->m_usage==G_MU_DYNAMIC_READ_WRITE) { pbuffer->m_mapped_pointer = buffer_id->m_bm_data->m_prototype->lock_buffer_fn( pbuffer->m_buffer_handle,access); *map_pointer = pbuffer->m_mapped_pointer; pbuffer->m_lock_count++; } return G_BUFFER_OP_SUCCESS; } GINT32 gim_unlock_buffer(GBUFFER_ID * buffer_id) { VALIDATE_BUFFER_ID_PT(buffer_id) if(pbuffer->m_lock_count==0) return G_BUFFER_OP_INVALID; if(pbuffer->m_lock_count>1) { pbuffer->m_lock_count--; return G_BUFFER_OP_SUCCESS; } GUINT32 result; if(pbuffer->m_usage==G_MU_STATIC_WRITE) { pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; return G_BUFFER_OP_INVALID; } else if(pbuffer->m_usage==G_MU_STATIC_READ) { if(pbuffer->m_access == G_MA_READ_ONLY) { result = gim_unlock_buffer(&pbuffer->m_shadow_buffer); if(result!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; } else { pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; return G_BUFFER_OP_INVALID; } } else if(pbuffer->m_usage==G_MU_STATIC_READ_DYNAMIC_WRITE) { if(pbuffer->m_access == G_MA_READ_ONLY) { result = gim_unlock_buffer(&pbuffer->m_shadow_buffer); if(result!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; } else if(pbuffer->m_access == G_MA_WRITE_ONLY) { buffer_id->m_bm_data->m_prototype->unlock_buffer_fn( pbuffer->m_buffer_handle); pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; } else if(pbuffer->m_access == G_MA_READ_WRITE) { pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; return G_BUFFER_OP_INVALID; } } else if(pbuffer->m_usage==G_MU_STATIC_READ_DYNAMIC_WRITE_COPY) { result = gim_unlock_buffer(&pbuffer->m_shadow_buffer); if(result!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; if(pbuffer->m_access == G_MA_WRITE_ONLY||pbuffer->m_access == G_MA_READ_WRITE) { gim_copy_buffers(&pbuffer->m_shadow_buffer,0,buffer_id,0,pbuffer->m_size); } } else if(pbuffer->m_usage==G_MU_STATIC_WRITE_DYNAMIC_READ) { if(pbuffer->m_access == G_MA_READ_ONLY) { buffer_id->m_bm_data->m_prototype->unlock_buffer_fn( pbuffer->m_buffer_handle); pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; } else { pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; return G_BUFFER_OP_INVALID; } } else if(pbuffer->m_usage==G_MU_DYNAMIC_READ_WRITE) { buffer_id->m_bm_data->m_prototype->unlock_buffer_fn( pbuffer->m_buffer_handle); pbuffer->m_mapped_pointer = 0; pbuffer->m_lock_count=0; } return G_BUFFER_OP_SUCCESS; } GINT32 gim_get_buffer_size(GBUFFER_ID * buffer_id,GUINT32 * buffer_size) { VALIDATE_BUFFER_ID_PT(buffer_id) *buffer_size = pbuffer->m_size; return G_BUFFER_OP_SUCCESS; } GINT32 gim_get_buffer_is_locked(GBUFFER_ID * buffer_id,GUINT32 * lock_count) { VALIDATE_BUFFER_ID_PT(buffer_id) *lock_count = pbuffer->m_lock_count; return G_BUFFER_OP_SUCCESS; } GINT32 gim_download_from_buffer( GBUFFER_ID * buffer_id, GUINT32 source_pos, void * destdata, GUINT32 copysize) { VALIDATE_BUFFER_ID_PT(buffer_id) buffer_id->m_bm_data->m_prototype->download_from_buffer_fn( pbuffer->m_buffer_handle,source_pos,destdata,copysize); return G_BUFFER_OP_SUCCESS; } GINT32 gim_upload_to_buffer( GBUFFER_ID * buffer_id, GUINT32 dest_pos, void * sourcedata, GUINT32 copysize) { VALIDATE_BUFFER_ID_PT(buffer_id) buffer_id->m_bm_data->m_prototype->upload_to_buffer_fn( pbuffer->m_buffer_handle,dest_pos,sourcedata,copysize); return G_BUFFER_OP_SUCCESS; } GINT32 gim_copy_buffers( GBUFFER_ID * source_buffer_id, GUINT32 source_pos, GBUFFER_ID * dest_buffer_id, GUINT32 dest_pos, GUINT32 copysize) { GBUFFER_MANAGER_DATA * bm_data1,* bm_data2; GBUFFER_DATA * pbuffer1, * pbuffer2; void * tempdata; if(_validate_buffer_id(source_buffer_id,&pbuffer1,&bm_data1)!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; if(_validate_buffer_id(dest_buffer_id,&pbuffer2,&bm_data2)!= G_BUFFER_OP_SUCCESS) return G_BUFFER_OP_INVALID; if((bm_data1->m_buffer_manager_id == bm_data2->m_buffer_manager_id)|| (bm_data1->m_buffer_manager_id == G_BUFFER_MANAGER_SYSTEM && bm_data2->m_buffer_manager_id == G_BUFFER_MANAGER_SHARED)|| (bm_data1->m_buffer_manager_id == G_BUFFER_MANAGER_SHARED && bm_data2->m_buffer_manager_id == G_BUFFER_MANAGER_SYSTEM) ) {//smooth copy bm_data1->m_prototype->copy_buffers_fn( pbuffer1->m_buffer_handle,source_pos,pbuffer2->m_buffer_handle,dest_pos,copysize); } else if(bm_data1->m_buffer_manager_id == G_BUFFER_MANAGER_SYSTEM || bm_data1->m_buffer_manager_id == G_BUFFER_MANAGER_SHARED) { //hard copy tempdata = (void *)pbuffer1->m_buffer_handle; //upload data bm_data2->m_prototype->upload_to_buffer_fn( pbuffer2->m_buffer_handle,dest_pos,tempdata,copysize); } else { //very hard copy void * tempdata = gim_alloc(copysize); //download data bm_data1->m_prototype->download_from_buffer_fn( pbuffer1->m_buffer_handle,source_pos,tempdata,copysize); //upload data bm_data2->m_prototype->upload_to_buffer_fn( pbuffer2->m_buffer_handle,dest_pos,tempdata,copysize); //delete temp buffer gim_free(tempdata,copysize); } return G_BUFFER_OP_SUCCESS; } GINT32 gim_buffer_array_lock(GBUFFER_ARRAY * array_data, int access) { if(array_data->m_buffer_data != 0) return G_BUFFER_OP_SUCCESS; GINT32 result = gim_lock_buffer(&array_data->m_buffer_id,access,&array_data->m_buffer_data); if(result!= G_BUFFER_OP_SUCCESS) return result; array_data->m_buffer_data += array_data->m_byte_offset; return result; } GINT32 gim_buffer_array_unlock(GBUFFER_ARRAY * array_data) { if(array_data->m_buffer_data == 0) return G_BUFFER_OP_SUCCESS; GINT32 result = gim_unlock_buffer(&array_data->m_buffer_id); if(result!= G_BUFFER_OP_SUCCESS) return result; array_data->m_buffer_data = 0; return result; } void gim_buffer_array_copy_ref(GBUFFER_ARRAY * source_data,GBUFFER_ARRAY * dest_data) { dest_data->m_buffer_id.m_buffer_id = source_data->m_buffer_id.m_buffer_id; dest_data->m_buffer_id.m_bm_data = source_data->m_buffer_id.m_bm_data; dest_data->m_buffer_data = 0; dest_data->m_byte_stride = source_data->m_byte_stride; dest_data->m_byte_offset = source_data->m_byte_offset; dest_data->m_element_count = source_data->m_element_count; gim_buffer_add_ref(&dest_data->m_buffer_id); } void gim_buffer_array_copy_value(GBUFFER_ARRAY * source_data, GBUFFER_MANAGER_DATA dest_buffer_managers[],GBUFFER_ARRAY * dest_data, GUINT32 buffer_manager_id,int usage) { //Create new buffer GUINT32 buffsize = source_data->m_element_count*source_data->m_byte_stride; gim_create_buffer(dest_buffer_managers,buffer_manager_id,buffsize,usage,&dest_data->m_buffer_id); //copy ref data dest_data->m_buffer_data = 0; dest_data->m_byte_stride = source_data->m_byte_stride; dest_data->m_byte_offset = 0; dest_data->m_element_count = source_data->m_element_count; gim_buffer_add_ref(&dest_data->m_buffer_id); //copy buffers gim_copy_buffers(&source_data->m_buffer_id,source_data->m_byte_offset,&dest_data->m_buffer_id,0,buffsize); } ode-0.14/GIMPACT/src/gim_tri_tri_overlap.cpp0000644000000000000000000002153712635011627017335 0ustar rootroot /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_trimesh.h" #define FABS(x) (float(fabs(x))) /* implement as is fastest on your machine */ /* some macros */ #define CLASSIFY_TRIPOINTS_BY_FACE(v1,v2,v3,faceplane,out_of_face)\ { \ _distances[0] = DISTANCE_PLANE_POINT(faceplane,v1);\ _distances[1] = _distances[0] * DISTANCE_PLANE_POINT(faceplane,v2);\ _distances[2] = _distances[0] * DISTANCE_PLANE_POINT(faceplane,v3); \ if(_distances[1]>0.0f && _distances[2]>0.0f)\ {\ out_of_face = 1;\ }\ else\ {\ out_of_face = 0;\ }\ }\ /* sort so that a<=b */ #define SORT(a,b) \ if(a>b) \ { \ float c; \ c=a; \ a=b; \ b=c; \ } /* this edge to edge test is based on Franlin Antonio's gem: "Faster Line Segment Intersection", in Graphics Gems III, pp. 199-202 */ #define EDGE_EDGE_TEST(V0,U0,U1) \ Bx=U0[i0]-U1[i0]; \ By=U0[i1]-U1[i1]; \ Cx=V0[i0]-U0[i0]; \ Cy=V0[i1]-U0[i1]; \ f=Ay*Bx-Ax*By; \ d=By*Cx-Bx*Cy; \ if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) \ { \ e=Ax*Cy-Ay*Cx; \ if(f>0) \ { \ if(e>=0 && e<=f) return 1; \ } \ else \ { \ if(e<=0 && e>=f) return 1; \ } \ } #define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \ { \ float Ax,Ay,Bx,By,Cx,Cy,e,d,f; \ Ax=V1[i0]-V0[i0]; \ Ay=V1[i1]-V0[i1]; \ /* test edge U0,U1 against V0,V1 */ \ EDGE_EDGE_TEST(V0,U0,U1); \ /* test edge U1,U2 against V0,V1 */ \ EDGE_EDGE_TEST(V0,U1,U2); \ /* test edge U2,U1 against V0,V1 */ \ EDGE_EDGE_TEST(V0,U2,U0); \ } #define POINT_IN_TRI(V0,U0,U1,U2) \ { \ float a,b,c,d0,d1,d2; \ /* is T1 completly inside T2? */ \ /* check if V0 is inside tri(U0,U1,U2) */ \ a=U1[i1]-U0[i1]; \ b=-(U1[i0]-U0[i0]); \ c=-a*U0[i0]-b*U0[i1]; \ d0=a*V0[i0]+b*V0[i1]+c; \ \ a=U2[i1]-U1[i1]; \ b=-(U2[i0]-U1[i0]); \ c=-a*U1[i0]-b*U1[i1]; \ d1=a*V0[i0]+b*V0[i1]+c; \ \ a=U0[i1]-U2[i1]; \ b=-(U0[i0]-U2[i0]); \ c=-a*U2[i0]-b*U2[i1]; \ d2=a*V0[i0]+b*V0[i1]+c; \ if(d0*d1>0.0) \ { \ if(d0*d2>0.0) return 1; \ } \ } int coplanar_tri_tri(GIM_TRIANGLE_DATA *tri1, GIM_TRIANGLE_DATA *tri2) { short i0,i1; /* first project onto an axis-aligned plane, that maximizes the area */ /* of the triangles, compute indices: i0,i1. */ PLANE_MINOR_AXES(tri1->m_planes.m_planes[0], i0, i1); /* test all edges of triangle 1 against the edges of triangle 2 */ EDGE_AGAINST_TRI_EDGES(tri1->m_vertices[0],tri1->m_vertices[1],tri2->m_vertices[0],tri2->m_vertices[1],tri2->m_vertices[2]); EDGE_AGAINST_TRI_EDGES(tri1->m_vertices[1],tri1->m_vertices[2],tri2->m_vertices[0],tri2->m_vertices[1],tri2->m_vertices[2]); EDGE_AGAINST_TRI_EDGES(tri1->m_vertices[2],tri1->m_vertices[0],tri2->m_vertices[0],tri2->m_vertices[1],tri2->m_vertices[2]); /* finally, test if tri1 is totally contained in tri2 or vice versa */ POINT_IN_HULL(tri1->m_vertices[0],(&tri2->m_planes.m_planes[1]),3,i0); if(i0==0) return 1; POINT_IN_HULL(tri2->m_vertices[0],(&tri1->m_planes.m_planes[1]),3,i0); if(i0==0) return 1; return 0; } #define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \ { \ if(D0D1>0.0f) \ { \ /* here we know that D0D2<=0.0 */ \ /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ } \ else if(D0D2>0.0f)\ { \ /* here we know that d0d1<=0.0 */ \ A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ } \ else if(D1*D2>0.0f || D0!=0.0f) \ { \ /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ A=VV0; B=(VV1-VV0)*D0; C=(VV2-VV0)*D0; X0=D0-D1; X1=D0-D2; \ } \ else if(D1!=0.0f) \ { \ A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ } \ else if(D2!=0.0f) \ { \ A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ } \ else \ { \ /* triangles are coplanar */ \ return coplanar_tri_tri(tri1,tri2); \ } \ }\ int gim_triangle_triangle_overlap( GIM_TRIANGLE_DATA *tri1, GIM_TRIANGLE_DATA *tri2) { vec3f _distances; char out_of_face; CLASSIFY_TRIPOINTS_BY_FACE(tri1->m_vertices[0],tri1->m_vertices[1],tri1->m_vertices[2],tri2->m_planes.m_planes[0],out_of_face); if(out_of_face==1) return 0; CLASSIFY_TRIPOINTS_BY_FACE(tri2->m_vertices[0],tri2->m_vertices[1],tri2->m_vertices[2],tri1->m_planes.m_planes[0],out_of_face); if(out_of_face==1) return 0; float du0=0,du1=0,du2=0,dv0=0,dv1=0,dv2=0; float D[3]; float isect1[2], isect2[2]; float du0du1=0,du0du2=0,dv0dv1=0,dv0dv2=0; short index; float vp0,vp1,vp2; float up0,up1,up2; float bb,cc,max; /* compute direction of intersection line */ VEC_CROSS(D,tri1->m_planes.m_planes[0],tri2->m_planes.m_planes[0]); /* compute and index to the largest component of D */ max=(float)FABS(D[0]); index=0; bb=(float)FABS(D[1]); cc=(float)FABS(D[2]); if(bb>max) max=bb,index=1; if(cc>max) max=cc,index=2; /* this is the simplified projection onto L*/ vp0= tri1->m_vertices[0][index]; vp1= tri1->m_vertices[1][index]; vp2= tri1->m_vertices[2][index]; up0= tri2->m_vertices[0][index]; up1= tri2->m_vertices[1][index]; up2= tri2->m_vertices[2][index]; /* compute interval for triangle 1 */ float a,b,c,x0,x1; NEWCOMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,a,b,c,x0,x1); /* compute interval for triangle 2 */ float d,e,f,y0,y1; NEWCOMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,d,e,f,y0,y1); float xx,yy,xxyy,tmp; xx=x0*x1; yy=y0*y1; xxyy=xx*yy; tmp=a*xxyy; isect1[0]=tmp+b*x1*yy; isect1[1]=tmp+c*x0*yy; tmp=d*xxyy; isect2[0]=tmp+e*xx*y1; isect2[1]=tmp+f*xx*y0; SORT(isect1[0],isect1[1]); SORT(isect2[0],isect2[1]); if(isect1[1] #include "GIMPACT/gim_trimesh.h" GUINT32 gim_trimesh_get_triangle_count(GIM_TRIMESH * trimesh) { return trimesh->m_tri_index_buffer.m_element_count/3; } //! Creates the aabb set and the triangles cache /*! \param trimesh \param vertex_array \param triindex_array \param transformed_reply If 1, then the m_transformed_vertices is a reply of the source vertices. Else it just be a reference to the original array. \post it copies the arrays by reference, and creates the auxiliary data (m_aabbset,m_planes_cache_buffer) */ void gim_trimesh_create_from_arrays(GBUFFER_MANAGER_DATA buffer_managers[], GIM_TRIMESH * trimesh, GBUFFER_ARRAY * vertex_array, GBUFFER_ARRAY * triindex_array,char transformed_reply) { assert(trimesh); assert(vertex_array); assert(triindex_array); gim_buffer_array_copy_ref(vertex_array,&trimesh->m_source_vertex_buffer); gim_buffer_array_copy_ref(triindex_array,&trimesh->m_tri_index_buffer); trimesh->m_mask = GIM_TRIMESH_NEED_UPDATE;//needs update //Create the transformed vertices if(transformed_reply==1) { trimesh->m_mask |= GIM_TRIMESH_TRANSFORMED_REPLY; gim_buffer_array_copy_value(vertex_array, buffer_managers,&trimesh->m_transformed_vertex_buffer,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE); } else { gim_buffer_array_copy_ref(vertex_array,&trimesh->m_transformed_vertex_buffer); } //create the box set GUINT32 facecount = gim_trimesh_get_triangle_count(trimesh); gim_aabbset_alloc(&trimesh->m_aabbset,facecount); //create the planes cache GIM_DYNARRAY_CREATE_SIZED(GIM_TRIPLANES_CACHE,trimesh->m_planes_cache_buffer,facecount); //Create the bitset GIM_BITSET_CREATE_SIZED(trimesh->m_planes_cache_bitset,facecount); //Callback is 0 trimesh->m_update_callback = 0; //set to identity IDENTIFY_MATRIX_4X4(trimesh->m_transform); } //! Create a trimesh from vertex array and an index array /*! \param trimesh An uninitialized GIM_TRIMESH structure \param vertex_array A buffer to a vec3f array \param vertex_count \param triindex_array \param index_count \param copy_vertices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data. \param copy_indices If 1, it copies the source vertices in another buffer. Else (0) it constructs a reference to the data. \param transformed_reply If , then the m_transformed_vertices is a reply of the source vertices. Else it just be a reference to the original array. */ void gim_trimesh_create_from_data(GBUFFER_MANAGER_DATA buffer_managers[], GIM_TRIMESH * trimesh, vec3f * vertex_array, GUINT32 vertex_count,char copy_vertices, GUINT32 * triindex_array, GUINT32 index_count,char copy_indices,char transformed_reply) { GBUFFER_ARRAY buffer_vertex_array; GBUFFER_ARRAY buffer_triindex_array; //Create vertices if(copy_vertices == 1) { gim_create_common_buffer_from_data(buffer_managers, vertex_array, vertex_count*sizeof(vec3f), &buffer_vertex_array.m_buffer_id); } else//Create a shared buffer { gim_create_shared_buffer_from_data(buffer_managers, vertex_array, vertex_count*sizeof(vec3f), &buffer_vertex_array.m_buffer_id); } GIM_BUFFER_ARRAY_INIT_TYPE(vec3f,buffer_vertex_array,buffer_vertex_array.m_buffer_id,vertex_count); //Create vertices if(copy_indices == 1) { gim_create_common_buffer_from_data(buffer_managers, triindex_array, index_count*sizeof(GUINT32), &buffer_triindex_array.m_buffer_id); } else//Create a shared buffer { gim_create_shared_buffer_from_data(buffer_managers, triindex_array, index_count*sizeof(GUINT32), &buffer_triindex_array.m_buffer_id); } GIM_BUFFER_ARRAY_INIT_TYPE(GUINT32,buffer_triindex_array,buffer_triindex_array.m_buffer_id,index_count); gim_trimesh_create_from_arrays(buffer_managers, trimesh, &buffer_vertex_array, &buffer_triindex_array,transformed_reply); ///always call this after create a buffer_array GIM_BUFFER_ARRAY_DESTROY(buffer_vertex_array); GIM_BUFFER_ARRAY_DESTROY(buffer_triindex_array); } //! Clears auxiliary data and releases buffer arrays void gim_trimesh_destroy(GIM_TRIMESH * trimesh) { gim_aabbset_destroy(&trimesh->m_aabbset); GIM_DYNARRAY_DESTROY(trimesh->m_planes_cache_buffer); GIM_DYNARRAY_DESTROY(trimesh->m_planes_cache_bitset); GIM_BUFFER_ARRAY_DESTROY(trimesh->m_transformed_vertex_buffer); GIM_BUFFER_ARRAY_DESTROY(trimesh->m_source_vertex_buffer); GIM_BUFFER_ARRAY_DESTROY(trimesh->m_tri_index_buffer); } //! Copies two meshes /*! \pre dest_trimesh shouldn't be created \post dest_trimesh will be created \param source_trimesh \param dest_trimesh \param copy_by_reference If 1, it attach a reference to the source vertices, else it copies the vertices \param transformed_reply IF 1, then it forces the m_trasnformed_vertices to be a reply of the source vertices */ void gim_trimesh_copy(GIM_TRIMESH * source_trimesh, GBUFFER_MANAGER_DATA dest_buffer_managers[], GIM_TRIMESH * dest_trimesh, char copy_by_reference, char transformed_reply) { /* -- trimesh can not be copied by reference until GBUFFER_MANAGER_DATA is rewritten to be thread safe and until it is moved back to global variables. if(copy_by_reference==1) { gim_trimesh_create_from_arrays(dest_trimesh, &source_trimesh->m_source_vertex_buffer, &source_trimesh->m_tri_index_buffer,transformed_reply); } else */ { GBUFFER_ARRAY buffer_vertex_array; GBUFFER_ARRAY buffer_triindex_array; gim_buffer_array_copy_value(&source_trimesh->m_source_vertex_buffer, dest_buffer_managers,&buffer_vertex_array,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE); gim_buffer_array_copy_value(&source_trimesh->m_tri_index_buffer, dest_buffer_managers,&buffer_triindex_array,G_BUFFER_MANAGER_SYSTEM,G_MU_DYNAMIC_READ_WRITE); gim_trimesh_create_from_arrays(dest_buffer_managers, dest_trimesh, &buffer_vertex_array, &buffer_triindex_array,transformed_reply); ///always call this after create a buffer_array GIM_BUFFER_ARRAY_DESTROY(buffer_vertex_array); GIM_BUFFER_ARRAY_DESTROY(buffer_triindex_array); } } //! Locks the trimesh for working with it /*! \post locks m_tri_index_buffer and m_transformed_vertex_buffer. \param trimesh */ void gim_trimesh_locks_work_data(GIM_TRIMESH * trimesh) { GINT32 res; res=gim_buffer_array_lock(&trimesh->m_tri_index_buffer,G_MA_READ_ONLY); assert(res==G_BUFFER_OP_SUCCESS); res=gim_buffer_array_lock(&trimesh->m_transformed_vertex_buffer,G_MA_READ_ONLY); assert(res==G_BUFFER_OP_SUCCESS); } //! unlocks the trimesh /*! \post unlocks m_tri_index_buffer and m_transformed_vertex_buffer. \param trimesh */ void gim_trimesh_unlocks_work_data(GIM_TRIMESH * trimesh) { gim_buffer_array_unlock(&trimesh->m_tri_index_buffer); gim_buffer_array_unlock(&trimesh->m_transformed_vertex_buffer); } //! Returns 1 if the m_transformed_vertex_buffer is a reply of m_source_vertex_buffer char gim_trimesh_has_tranformed_reply(GIM_TRIMESH * trimesh) { if(trimesh->m_mask&GIM_TRIMESH_TRANSFORMED_REPLY) return 1; return 0; } //! Returns 1 if the trimesh needs to update their aabbset and the planes cache. char gim_trimesh_needs_update(GIM_TRIMESH * trimesh) { if(trimesh->m_mask&GIM_TRIMESH_NEED_UPDATE) return 1; return 0; } //! Change the state of the trimesh for force it to update /*! Call it after made changes to the trimesh. \post gim_trimesh_need_update(trimesh) will return 1 */ void gim_trimesh_post_update(GIM_TRIMESH * trimesh) { trimesh->m_mask |= GIM_TRIMESH_NEED_UPDATE; } //kernel #define MULT_MAT_VEC4_KERNEL(_mat,_src,_dst) MAT_DOT_VEC_3X4((_dst),(_mat),(_src)) //! Updates m_transformed_vertex_buffer /*! \pre m_transformed_vertex_buffer must be unlocked */ void gim_trimesh_update_vertices(GIM_TRIMESH * trimesh) { if(gim_trimesh_has_tranformed_reply(trimesh) == 0) return; //Don't perform transformation //Vertices GBUFFER_ARRAY * psource_vertex_buffer = &trimesh->m_source_vertex_buffer; GBUFFER_ARRAY * ptransformed_vertex_buffer = &trimesh->m_transformed_vertex_buffer; //Temp transform mat4f transform; COPY_MATRIX_4X4(transform,trimesh->m_transform); GIM_PROCESS_BUFFER_ARRAY(transform,(*psource_vertex_buffer),(*ptransformed_vertex_buffer),MULT_MAT_VEC4_KERNEL,vec3f,vec3f); } //! Updates m_aabbset and m_planes_cache_bitset /*! \pre gim_trimesh_locks_work_data must be called before */ void gim_trimesh_update_aabbset(GIM_TRIMESH * trimesh) { vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0); assert(transformed_vertices); GUINT32 * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT32,trimesh->m_tri_index_buffer,0); assert(triangle_indices); // box set aabb3f * paabb = trimesh->m_aabbset.m_boxes; GUINT32 triangle_count = gim_trimesh_get_triangle_count(trimesh); float * v1,*v2,*v3; GUINT32 i; for (i=0; im_planes_cache_bitset); //Sorts set gim_aabbset_update(&trimesh->m_aabbset); } //! Updates the trimesh if needed /*! \post If gim_trimesh_needs_update returns 1, then it calls gim_trimesh_update_vertices and gim_trimesh_update_aabbset */ void gim_trimesh_update(GIM_TRIMESH * trimesh) { if(gim_trimesh_needs_update(trimesh)==0) return; gim_trimesh_update_vertices(trimesh); gim_trimesh_locks_work_data(trimesh); gim_trimesh_update_aabbset(trimesh); gim_trimesh_unlocks_work_data(trimesh); //Clear update flag trimesh->m_mask &= ~GIM_TRIMESH_NEED_UPDATE; } void gim_trimesh_set_tranform(GIM_TRIMESH * trimesh, mat4f transform) { GREAL diff = 0.0f; float * originaltrans = &trimesh->m_transform[0][0]; float * newtrans = &transform[0][0]; GUINT32 i; for (i=0;i<16;i++) { diff += fabs(originaltrans[i]-newtrans[i]); } // if(IS_ZERO(diff)) return ;///don't need to update if(diff< 0.00001f) return ;///don't need to update COPY_MATRIX_4X4(trimesh->m_transform,transform); gim_trimesh_post_update(trimesh); } void gim_trimesh_get_triangle_data(GIM_TRIMESH * trimesh, GUINT32 triangle_index, GIM_TRIANGLE_DATA * tri_data) { vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0); GUINT32 * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT32,trimesh->m_tri_index_buffer,triangle_index*3); //Copy the vertices VEC_COPY(tri_data->m_vertices[0],transformed_vertices[triangle_indices[0]]); VEC_COPY(tri_data->m_vertices[1],transformed_vertices[triangle_indices[1]]); VEC_COPY(tri_data->m_vertices[2],transformed_vertices[triangle_indices[2]]); //Get the planes GIM_TRIPLANES_CACHE * planes = GIM_DYNARRAY_POINTER(GIM_TRIPLANES_CACHE,trimesh->m_planes_cache_buffer); planes += triangle_index; //verify planes cache GUINT32 bit_eval; GIM_BITSET_GET(trimesh->m_planes_cache_bitset,triangle_index,bit_eval); if(bit_eval == 0)// Needs to calc the planes { //Calc the face plane TRIANGLE_PLANE(tri_data->m_vertices[0],tri_data->m_vertices[1],tri_data->m_vertices[2],planes->m_planes[0]); //Calc the edge 1 EDGE_PLANE(tri_data->m_vertices[0],tri_data->m_vertices[1],(planes->m_planes[0]),(planes->m_planes[1])); //Calc the edge 2 EDGE_PLANE(tri_data->m_vertices[1],tri_data->m_vertices[2],(planes->m_planes[0]),(planes->m_planes[2])); //Calc the edge 3 EDGE_PLANE(tri_data->m_vertices[2],tri_data->m_vertices[0],(planes->m_planes[0]), (planes->m_planes[3])); //mark GIM_BITSET_SET(trimesh->m_planes_cache_bitset,triangle_index); } VEC_COPY_4((tri_data->m_planes.m_planes[0]),(planes->m_planes[0]));//face plane VEC_COPY_4((tri_data->m_planes.m_planes[1]),(planes->m_planes[1]));//edge1 VEC_COPY_4((tri_data->m_planes.m_planes[2]),(planes->m_planes[2]));//edge2 VEC_COPY_4((tri_data->m_planes.m_planes[3]),(planes->m_planes[3]));//edge3 } void gim_trimesh_get_triangle_vertices(GIM_TRIMESH * trimesh, GUINT32 triangle_index, vec3f v1,vec3f v2,vec3f v3) { vec3f * transformed_vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0); GUINT32 * triangle_indices = GIM_BUFFER_ARRAY_POINTER(GUINT32,trimesh->m_tri_index_buffer,triangle_index*3); //Copy the vertices VEC_COPY(v1,transformed_vertices[triangle_indices[0]]); VEC_COPY(v2,transformed_vertices[triangle_indices[1]]); VEC_COPY(v3,transformed_vertices[triangle_indices[2]]); } ode-0.14/GIMPACT/src/gim_trimesh_capsule_collision.cpp0000644000000000000000000002162012635011627021364 0ustar rootroot /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_trimesh.h" //! Utility function for find the closest point between a segment and a triangle /*! \param triangle \param s1 \param s2 \param contacts Contains the closest points on the segment (1,2), and the normal points to segment, and m_depth contains the distance \post The contacts array is not set to 0. It adds aditional contacts */ void gim_closest_point_triangle_segment(GIM_TRIANGLE_DATA * triangle, vec3f s1,vec3f s2, GDYNAMIC_ARRAY * contacts) { vec3f segment_points[4] = {{0}}; vec3f closest_points[2] = {{0}}; GUINT32 intersection_type, out_edge= 10; GREAL dis, dis_temp,perpend; vec4f sdiff; dis = DISTANCE_PLANE_POINT(triangle->m_planes.m_planes[0],s1); dis_temp = DISTANCE_PLANE_POINT(triangle->m_planes.m_planes[0],s2); if(dis<=0.0f && dis_temp<=0.0f) return; VEC_DIFF(sdiff,s2,s1); perpend = VEC_DOT(sdiff,triangle->m_planes.m_planes[0]); if(!IS_ZERO(perpend)) // Not perpendicular { if(dis=0.0f && dis_temp>=0.0f) { POINT_IN_HULL(closest_points[0],(&triangle->m_planes.m_planes[1]),3,out_edge); if(out_edge==0)//Point over face { GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); return; } } else { PLANE_CLIP_SEGMENT(s1,s2,triangle->m_planes.m_planes[0],closest_points[1]); POINT_IN_HULL(closest_points[1],(&triangle->m_planes.m_planes[1]),3,out_edge); if(out_edge==0)//Point over face { GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); return; } } } else // Perpendicular Face { //out_edge=10 //Clip segment by triangle // Edge1 PLANE_CLIP_SEGMENT_CLOSEST(s1,s2,triangle->m_planes.m_planes[1],segment_points[0],segment_points[1],intersection_type); if(intersection_type==0||intersection_type==1) { out_edge = 0; VEC_COPY(closest_points[0],segment_points[0]); } else { //Edge2 PLANE_CLIP_SEGMENT_CLOSEST(segment_points[0],segment_points[1],triangle->m_planes.m_planes[2],segment_points[2],segment_points[3],intersection_type); if(intersection_type==0||intersection_type==1) { out_edge = 1; VEC_COPY(closest_points[0],segment_points[3]); } else { //Edge3 PLANE_CLIP_SEGMENT_CLOSEST(segment_points[2],segment_points[3],triangle->m_planes.m_planes[3],closest_points[0],closest_points[1],intersection_type); if(intersection_type==0||intersection_type==1) { out_edge = 2; } } } //POST closest_points[0] and closest_points[1] are inside the triangle, if out_edge>2 if(out_edge>2) // Over triangle { dis = VEC_DOT(closest_points[0],triangle->m_planes.m_planes[0]); GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); GIM_PUSH_CONTACT((*contacts),closest_points[1] ,triangle->m_planes.m_planes[0] ,dis,0, 0, 0,0); return; } } //Find closest edges out_edge = 10; dis = G_REAL_INFINITY; GUINT32 i; for(i=0;i<3;i++) { SEGMENT_COLLISION(s1,s2,triangle->m_vertices[i],triangle->m_vertices[(i+1)%3],segment_points[0],segment_points[1]); VEC_DIFF(sdiff,segment_points[0],segment_points[1]); dis_temp = VEC_DOT(sdiff,sdiff); if(dis_temp< dis) { dis = dis_temp; out_edge = i; VEC_COPY(closest_points[0],segment_points[0]); VEC_COPY(closest_points[1],sdiff);//normal } } if(out_edge>2) return ;// ???? ASSERT this please if(IS_ZERO(dis)) { //Set face plane GIM_PUSH_CONTACT((*contacts),closest_points[0] ,triangle->m_planes.m_planes[0] ,0.0f,0, 0, 0,0); } else { GIM_SQRT(dis,dis); VEC_SCALE(closest_points[1],(1.0f/dis),closest_points[1]);//normal GIM_PUSH_CONTACT((*contacts),closest_points[0] ,closest_points[1],dis,0, 0, 0,0); } } //! Utility function for find the closest point between a capsule and a triangle /*! \param triangle \param capsule \param contacts Contains the closest points on the capsule, and the normal points to triangle \post The contacts array is not set to 0. It adds aditional contacts */ int gim_triangle_capsule_collision(GIM_TRIANGLE_DATA * triangle, GIM_CAPSULE_DATA * capsule, GDYNAMIC_ARRAY * contacts) { GUINT32 old_contact_size = contacts->m_size; gim_closest_point_triangle_segment(triangle,capsule->m_point1,capsule->m_point2,contacts); if (contacts->m_size == old_contact_size) { return 0; } GIM_CONTACT * pcontact = GIM_DYNARRAY_POINTER(GIM_CONTACT ,(*contacts)); pcontact+= old_contact_size; if(pcontact->m_depth > capsule->m_radius) { contacts->m_size = old_contact_size; return 0; } vec3f vec; while(old_contact_sizem_size) { //Scale the normal for pointing to triangle VEC_SCALE(pcontact->m_normal,-1.0f,pcontact->m_normal); //Fix the contact point VEC_SCALE(vec,capsule->m_radius,pcontact->m_normal); VEC_SUM(pcontact->m_point,vec,pcontact->m_point); //Fix the depth pcontact->m_depth = capsule->m_radius - pcontact->m_depth; pcontact++; old_contact_size++; } return 1; } //! Trimesh Capsule collision /*! Find the closest primitive collided by the ray \param trimesh \param capsule \param contact \param contacts A GIM_CONTACT array. Must be initialized */ void gim_trimesh_capsule_collision(GIM_TRIMESH * trimesh, GIM_CAPSULE_DATA * capsule, GDYNAMIC_ARRAY * contacts) { contacts->m_size = 0; aabb3f test_aabb; CALC_CAPSULE_AABB((*capsule),test_aabb); GDYNAMIC_ARRAY collision_result; GIM_CREATE_BOXQUERY_LIST(collision_result); gim_aabbset_box_collision(&test_aabb, &trimesh->m_aabbset , &collision_result); if(collision_result.m_size==0) { GIM_DYNARRAY_DESTROY(collision_result); } //collide triangles //Locks trimesh gim_trimesh_locks_work_data(trimesh); //dummy contacts GDYNAMIC_ARRAY dummycontacts; GIM_CREATE_CONTACT_LIST(dummycontacts); int cresult; unsigned int i; GUINT32 * boxesresult = GIM_DYNARRAY_POINTER(GUINT32,collision_result); GIM_TRIANGLE_DATA tri_data; GUINT32 old_contact_size; GIM_CONTACT * pcontact; for(i=0;im_handle1 = trimesh; pcontact->m_handle2 = capsule; pcontact->m_feature1 = boxesresult[i]; pcontact->m_feature2 = 0; pcontact++; old_contact_size++; } } } ///unlocks gim_trimesh_unlocks_work_data(trimesh); ///Destroy box result GIM_DYNARRAY_DESTROY(collision_result); //merge contacts gim_merge_contacts(&dummycontacts,contacts); //Destroy dummy GIM_DYNARRAY_DESTROY(dummycontacts); } ode-0.14/GIMPACT/src/gim_trimesh_ray_collision.cpp0000644000000000000000000001105512635011627020524 0ustar rootroot /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_trimesh.h" //! Trimesh Ray Collisions /*! \param trimesh \param contact \return 1 if the ray collides, else 0 */ int gim_trimesh_ray_collision(GIM_TRIMESH * trimesh,vec3f origin,vec3f dir, GREAL tmax, GIM_TRIANGLE_RAY_CONTACT_DATA * contact) { GDYNAMIC_ARRAY collision_result; GIM_CREATE_BOXQUERY_LIST(collision_result); gim_aabbset_ray_collision(origin,dir,tmax,&trimesh->m_aabbset,&collision_result); if(collision_result.m_size==0) { GIM_DYNARRAY_DESTROY(collision_result); return 0; } //collide triangles GUINT32 * boxesresult = GIM_DYNARRAY_POINTER(GUINT32,collision_result); GIM_TRIANGLE_DATA tridata; vec3f pout; GREAL tparam,u,v; char does_intersect; gim_trimesh_locks_work_data(trimesh); for(unsigned int i=0;itparam = tparam; contact->u = u; contact->v = v; contact->m_face_id = boxesresult[i]; VEC_COPY(contact->m_point,pout); VEC_COPY(contact->m_normal,flippedPlane); gim_trimesh_unlocks_work_data(trimesh); GIM_DYNARRAY_DESTROY(collision_result); return 1; } } gim_trimesh_unlocks_work_data(trimesh); GIM_DYNARRAY_DESTROY(collision_result); return 0;//no collisiion } //! Trimesh Ray Collisions closest /*! Find the closest primitive collided by the ray \param trimesh \param contact \return 1 if the ray collides, else 0 */ int gim_trimesh_ray_closest_collision(GIM_TRIMESH * trimesh,vec3f origin,vec3f dir, GREAL tmax, GIM_TRIANGLE_RAY_CONTACT_DATA * contact) { GDYNAMIC_ARRAY collision_result; GIM_CREATE_BOXQUERY_LIST(collision_result); gim_aabbset_ray_collision(origin,dir,tmax,&trimesh->m_aabbset,&collision_result); if(collision_result.m_size==0) { GIM_DYNARRAY_DESTROY(collision_result); return 0; } //collide triangles GUINT32 * boxesresult = GIM_DYNARRAY_POINTER(GUINT32,collision_result); GIM_TRIANGLE_DATA tridata; vec3f pout; GREAL tparam,u,v; char does_intersect; contact->tparam = tmax + 0.1f; gim_trimesh_locks_work_data(trimesh); for(unsigned int i=0;itparam)) { contact->tparam = tparam; contact->u = u; contact->v = v; contact->m_face_id = boxesresult[i]; VEC_COPY(contact->m_point,pout); VEC_COPY(contact->m_normal,flippedPlane); } } gim_trimesh_unlocks_work_data(trimesh); GIM_DYNARRAY_DESTROY(collision_result); if(contact->tparam > tmax) return 0; return 1; } ode-0.14/GIMPACT/src/gim_trimesh_sphere_collision.cpp0000644000000000000000000001443212635011627021221 0ustar rootroot /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "GIMPACT/gim_trimesh.h" int gim_triangle_sphere_collision( GIM_TRIANGLE_DATA *tri, vec3f center, GREAL radius, GIM_TRIANGLE_CONTACT_DATA * contact_data) { contact_data->m_point_count = 0; //Find Face plane distance GREAL dis = DISTANCE_PLANE_POINT(tri->m_planes.m_planes[0],center); if(dis>radius) return 0; //out if(dis<-radius) return 0;//Out of triangle contact_data->m_penetration_depth = dis; //Find the most edge GUINT32 most_edge = 4;//no edge GREAL max_dis = 0.0f; dis = DISTANCE_PLANE_POINT(tri->m_planes.m_planes[1],center); if(dis>radius) return 0;//Out of triangle if(dis>0.0f) { max_dis = dis; most_edge = 0; } dis = DISTANCE_PLANE_POINT(tri->m_planes.m_planes[2],center); if(dis>radius) return 0;//Out of triangle if(dis>max_dis)// && dis>0.0f) { max_dis = dis; most_edge = 1; } dis = DISTANCE_PLANE_POINT(tri->m_planes.m_planes[3],center); if(dis>radius) return 0;//Out of triangle if(dis>max_dis)// && dis>0.0f) { max_dis = dis; most_edge = 2; } if(most_edge == 4) //Box is into triangle { //contact_data->m_penetration_depth = dis is set above //Find Face plane point VEC_COPY(contact_data->m_separating_normal,tri->m_planes.m_planes[0]); //Find point projection on plane if(contact_data->m_penetration_depth>=0.0f) { VEC_SCALE(contact_data->m_points[0],-radius,contact_data->m_separating_normal); } else { VEC_SCALE(contact_data->m_points[0],radius,contact_data->m_separating_normal); } contact_data->m_penetration_depth = radius - contact_data->m_penetration_depth; VEC_SUM(contact_data->m_points[0],contact_data->m_points[0],center); //Scale normal for pointing to triangle VEC_SCALE(contact_data->m_separating_normal,-1.0f,contact_data->m_separating_normal); contact_data->m_point_count = 1; return 1; } //find the edge vec3f e1,e2; VEC_COPY(e1,tri->m_vertices[most_edge]); VEC_COPY(e2,tri->m_vertices[(most_edge+1)%3]); CLOSEST_POINT_ON_SEGMENT(contact_data->m_points[0],center,e1,e2); //find distance VEC_DIFF(e1,center,contact_data->m_points[0]); VEC_LENGTH(e1,dis); if(dis>radius) return 0; contact_data->m_penetration_depth = radius - dis; if(IS_ZERO(dis)) { VEC_COPY(contact_data->m_separating_normal,tri->m_planes.m_planes[most_edge+1]); VEC_SCALE(contact_data->m_points[0],-radius,contact_data->m_separating_normal); VEC_SUM(contact_data->m_points[0],contact_data->m_points[0],center); } else { VEC_SCALE(contact_data->m_separating_normal,1.0f/dis,e1); VEC_SCALE(contact_data->m_points[0],-radius,contact_data->m_separating_normal); VEC_SUM(contact_data->m_points[0],contact_data->m_points[0],center); } //Scale normal for pointing to triangle VEC_SCALE(contact_data->m_separating_normal,-1.0f,contact_data->m_separating_normal); contact_data->m_point_count = 1; return 1; } //! Trimesh Sphere Collisions /*! In each contact
    • m_handle1 points to trimesh.
    • m_handle2 points to NULL.
    • m_feature1 Is a triangle index of trimesh.
    \param trimesh \param center \param radius \param contacts A GIM_CONTACT array. Must be initialized */ void gim_trimesh_sphere_collision(GIM_TRIMESH * trimesh,vec3f center,GREAL radius, GDYNAMIC_ARRAY * contacts) { contacts->m_size = 0; aabb3f test_aabb; test_aabb.minX = center[0]-radius; test_aabb.maxX = center[0]+radius; test_aabb.minY = center[1]-radius; test_aabb.maxY = center[1]+radius; test_aabb.minZ = center[2]-radius; test_aabb.maxZ = center[2]+radius; GDYNAMIC_ARRAY collision_result; GIM_CREATE_BOXQUERY_LIST(collision_result); gim_aabbset_box_collision(&test_aabb, &trimesh->m_aabbset , &collision_result); if(collision_result.m_size==0) { GIM_DYNARRAY_DESTROY(collision_result); } //collide triangles //Locks trimesh gim_trimesh_locks_work_data(trimesh); //dummy contacts GDYNAMIC_ARRAY dummycontacts; GIM_CREATE_CONTACT_LIST(dummycontacts); int cresult; unsigned int i; GUINT32 * boxesresult = GIM_DYNARRAY_POINTER(GUINT32,collision_result); GIM_TRIANGLE_CONTACT_DATA tri_contact_data; GIM_TRIANGLE_DATA tri_data; for(i=0;i0.0f && _distances[2]>0.0f)\ {\ out_of_face = 1;\ }\ else\ {\ out_of_face = 0;\ }\ }\ //! Receives the 3 edge planes #define MOST_DEEP_POINTS(plane,points,point_count,deep_points,deep_points_count,maxdeep)\ {\ maxdeep=-1000.0f;\ GUINT32 _k;\ GREAL _dist;\ deep_points_count = 0;\ for(_k=0;_kmaxdeep)\ {\ maxdeep = _dist;\ _max_candidates[0] = _k;\ deep_points_count=1;\ }\ else if((_dist+G_EPSILON)>=maxdeep)\ {\ _max_candidates[deep_points_count] = _k;\ deep_points_count++;\ }\ }\ if(maxdeep<0.0f)\ {\ deep_points_count = 0;\ }\ else\ {\ for(_k=0;_k0)\ {\ _temp_clip_count2 = 0;\ PLANE_CLIP_POLYGON(tri_edge_planes[1],_temp_clip,_temp_clip_count,_temp_clip2,_temp_clip_count2,MAX_TRI_CLIPPING);\ if(_temp_clip_count2>0)\ {\ PLANE_CLIP_POLYGON(tri_edge_planes[2],_temp_clip2,_temp_clip_count2,clipped_points,clipped_point_count,MAX_TRI_CLIPPING);\ }\ }\ }\ int _gim_triangle_triangle_collision( GIM_TRIANGLE_DATA *tri1, GIM_TRIANGLE_DATA *tri2, GIM_TRIANGLE_CONTACT_DATA * contact_data) { //Cache variables for triangle intersection GUINT32 _max_candidates[MAX_TRI_CLIPPING]; vec3f _temp_clip[MAX_TRI_CLIPPING]; GUINT32 _temp_clip_count = 0; vec3f _temp_clip2[MAX_TRI_CLIPPING]; GUINT32 _temp_clip_count2 = 0; vec3f clipped_points2[MAX_TRI_CLIPPING]; vec3f deep_points2[MAX_TRI_CLIPPING]; vec3f clipped_points1[MAX_TRI_CLIPPING]; vec3f deep_points1[MAX_TRI_CLIPPING]; //State variabnles GUINT32 mostdir=0; GUINT32 clipped2_count=0; //Clip tri2 by tri1 edges CLIP_TRI_POINTS_BY_TRI_EDGE_PLANES(tri2->m_vertices,(&tri1->m_planes.m_planes[1]), clipped_points2, clipped2_count); if(clipped2_count == 0 ) { return 0;//Reject } //find most deep interval face1 GUINT32 deep2_count=0; GREAL maxdeep; MOST_DEEP_POINTS((tri1->m_planes.m_planes[0]), clipped_points2, clipped2_count, deep_points2, deep2_count, maxdeep); if(deep2_count==0) { // *perror = 0.0f; return 0;//Reject } //Normal pointing to triangle1 VEC_SCALE(contact_data->m_separating_normal,-1.0f,(tri1->m_planes.m_planes[0])); //Clip tri1 by tri2 edges GUINT32 clipped1_count=0; CLIP_TRI_POINTS_BY_TRI_EDGE_PLANES(tri1->m_vertices,(&tri2->m_planes.m_planes[1]), clipped_points1, clipped1_count); if(clipped2_count == 0 ) { // *perror = 0.0f; return 0;//Reject } //find interval face2 GUINT32 deep1_count=0; GREAL dist; MOST_DEEP_POINTS((tri2->m_planes.m_planes[0]), clipped_points1, clipped1_count, deep_points1, deep1_count, dist); if(deep1_count==0) { // *perror = 0.0f; return 0; } if(distm_separating_normal,(tri2->m_planes.m_planes[0])); } //set deep contact_data->m_penetration_depth = maxdeep; ////check most dir for contacts if(mostdir==0) { contact_data->m_point_count = deep2_count; for(mostdir=0;mostdirm_points[mostdir] ,deep_points2[mostdir]); } } else { contact_data->m_point_count = deep1_count; for(mostdir=0;mostdirm_points[mostdir] ,deep_points1[mostdir]); } } return 1; } //! Finds the contact points from a collision of two triangles /*! Returns the contact points, the penetration depth and the separating normal of the collision between two triangles. The normal is pointing toward triangle 1 from triangle 2 */ int gim_triangle_triangle_collision( GIM_TRIANGLE_DATA *tri1, GIM_TRIANGLE_DATA *tri2, GIM_TRIANGLE_CONTACT_DATA * contact_data) { vec3f _distances; char out_of_face=0; CLASSIFY_TRI_BY_FACE(tri1->m_vertices[0],tri1->m_vertices[1],tri1->m_vertices[2],tri2->m_planes.m_planes[0],out_of_face); if(out_of_face==1) return 0; CLASSIFY_TRI_BY_FACE(tri2->m_vertices[0],tri2->m_vertices[1],tri2->m_vertices[2],tri1->m_planes.m_planes[0],out_of_face); if(out_of_face==1) return 0; return _gim_triangle_triangle_collision(tri1,tri2,contact_data); } //! Trimesh Trimesh Collisions /*! In each contact
    • m_handle1 points to trimesh1.
    • m_handle2 points to trimesh2.
    • m_feature1 Is a triangle index of trimesh1.
    • m_feature2 Is a triangle index of trimesh2.
    \param trimesh1 Collider \param trimesh2 Collidee \param contacts A GIM_CONTACT array. Must be initialized */ void gim_trimesh_trimesh_collision(GIM_TRIMESH * trimesh1, GIM_TRIMESH * trimesh2, GDYNAMIC_ARRAY * contacts) { contacts->m_size = 0; GDYNAMIC_ARRAY collision_pairs; GIM_CREATE_PAIR_SET(collision_pairs) gim_aabbset_bipartite_intersections(&trimesh1->m_aabbset,&trimesh2->m_aabbset,&collision_pairs); if(collision_pairs.m_size==0) { GIM_DYNARRAY_DESTROY(collision_pairs); return; //no collisioin } //Locks meshes gim_trimesh_locks_work_data(trimesh1); gim_trimesh_locks_work_data(trimesh2); //pair pointer GIM_PAIR *pairs = GIM_DYNARRAY_POINTER(GIM_PAIR,collision_pairs); //dummy contacts GDYNAMIC_ARRAY dummycontacts; GIM_CREATE_CONTACT_LIST(dummycontacts); //Auxiliary triangle data GIM_TRIANGLE_CONTACT_DATA tri_contact_data; GIM_TRIANGLE_DATA tri1data,tri2data; GUINT32 i, ti1,ti2,ci; int colresult; for (i=0;im_size = 0; char classify; PLANE_CLASSIFY_BOX(plane,trimesh->m_aabbset.m_global_bound,classify); if(classify>1) return; // in front of plane //Locks mesh gim_trimesh_locks_work_data(trimesh); //Get vertices GUINT32 i, vertcount = trimesh->m_transformed_vertex_buffer.m_element_count; vec3f * vertices = GIM_BUFFER_ARRAY_POINTER(vec3f,trimesh->m_transformed_vertex_buffer,0); GREAL dist; vec4f * result_contact; for (i=0;i premake4.exe --with-tests --with-demos vs2008 To see a complete list of options use: > premake4.exe --help Note that Visual Studio 6 is not supported and users are advised to upgrade to at least Visual Studio 2005 Express (it's free!) 2. BUILDING WITH AUTOTOOLS (Linux, OS X, MSYS, etc.) ==================================================== 2.1 FROM SUBVERSION REPOSITORY ------------------------------ If you downloaded the source code from Subversion you must bootstrap the process by running the command: $ ./bootstrap For this command to work you need a set of tools typically available on BSD and Linux distributions with development packages installed. OS X users may need to manually install libtool, autoconf, automake, pkg-config, and maybe some more. If you downloaded a source code package from SourceForge this has already been done for you. You may see some "underquoted definition" warnings depending on your platform, these are (for now) harmless warnings regarding scripts from other m4 installed packages. 2.2 FROM A RELEASED TARBALL --------------------------- First extract the archive (e.g. tar xvfz ) and enter the created directory (ode-x.y). Run the configure script to autodetect your build environment: $ ./configure By default this will build ODE as a static library with single-precision math, trimesh support with OPCODE, and debug symbols enabled. You can modify these defaults by passing additional parameters to configure. For a full list of available options, type: $ ./configure --help Some of the more popular options are --enable-double-precision enable double-precision math --with-trimesh=none disables the trimesh support --with-trimesh=opcode use OPCODE for trimesh code --with-trimesh=gimpact use GIMPACT for trimesh code --enabled-shared builds a shared library To pass specific flags for an optimized build, you must do so in the CFLAGS and CXXFLAGS enviroment variables, or as arguments to ./configure. For example if you are building for an athlon xp processor and you want the compiler to use SSE instructions you can run configure as follows: $ ./configure CFLAGS="-msse -march=atlon-xp" CXXFLAGS="-msse -march=atlon-xp" Note that you must set both CFLAGS and CXXFLAGS as ODE contains a mixture of C and C++ files. Once configure has run successfully, build and install ODE: $ make $ make install The latter command will also create a pkg-config script that provides compilation and linking flags for programs. The old stand-alone "ode-config" script is also installed for compatibility. 3. BUILDING WITH Code::Blocks ============================= Because Code::Blocks supports so many different platforms, we do not provide workspaces. Instead, use Premake to create a workspace tailored for your platform and project. Like so: $ cd build $ premake4 --with-tests --with-demos codeblocks To see a complete list of options: $ cd build $ premake4 --help 4. BUILDING WITH SOMETHING ELSE =============================== ODE uses the Premake tool to provide support for several different toolsets. Premake adds support for new toolsets on a regular basis, so yours might be supported. Check the Premake website at http://premake.sourceforge.net/, and then follow the directions for Code::Blocks above, substituting your toolset target in place of `codeblocks`. ode-0.14/LICENSE-BSD.TXT0000644000000000000000000000313212635011627012776 0ustar rootroot This is the BSD-style license for the Open Dynamics Engine ---------------------------------------------------------- Open Dynamics Engine Copyright (c) 2001-2007, Russell L. Smith. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the names of ODE's copyright owner nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ode-0.14/LICENSE.TXT0000644000000000000000000006347412635011627012407 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ode-0.14/Makefile.am0000644000000000000000000000143512635011627012745 0ustar rootrootAUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 --install if ENABLE_OU OU_DIR = ou endif if LIBCCD if LIBCCD_INTERNAL LIBCCD_DIR = libccd endif endif if ENABLE_DEMOS DRAWSTUFF_DIR = drawstuff endif if GIMPACT GIMPACT_DIR = GIMPACT endif if OPCODE OPCODE_DIR = OPCODE endif SUBDIRS = include \ $(DRAWSTUFF_DIR) \ $(GIMPACT_DIR) \ $(OPCODE_DIR) \ $(OU_DIR) \ $(LIBCCD_DIR) \ ode \ tests bin_SCRIPTS = ode-config # Utility rule for making a release release: dist-gzip dist-bzip2 @echo Created release packages for ${PACKAGE}-${VERSION}. EXTRA_DIST = bootstrap build tools \ CHANGELOG.txt COPYING INSTALL.txt README.md LICENSE.TXT \ bindings pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = ode.pc ode-0.14/OPCODE/0000775000000000000000000000000012635012023011650 5ustar rootrootode-0.14/OPCODE/COPYING0000644000000000000000000000166512635011627012722 0ustar rootrootThe OPCODE library distributed as part of ODE is licensed under the same terms as ODE (LGPLv2.1+ and BSD). Quoting a public e-mail from the author: Re: TriMesh support and OPCODE added to ODE core Pierre Terdiman wanadoo.fr> 2003-07-01 21:18:44 GMT > If he wants > to explicitly make it clear that OpCode is good under ODE's > license, that would be A-1 Super... "Opcode is good under ODE's license" I didn't put a license to prevent boring questions about licenses, but it seems it's not enough - I still get as many questions, regarding missing license. The only thing that would NOT be good would be renaming it "TopCode", changing the author's name, selling it at a very expensive price, and still managing to make money out of it :) ...I should add a license explicitely against this :) Pierre Source: http://permalink.gmane.org/gmane.comp.lib.ode/3237 ode-0.14/OPCODE/Ice/0000775000000000000000000000000012635012022012347 5ustar rootrootode-0.14/OPCODE/Ice/IceAABB.cpp0000644000000000000000000003760412635011627014203 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains AABB-related code. * \file IceAABB.cpp * \author Pierre Terdiman * \date January, 29, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * AABB class. * \class AABB * \author Pierre Terdiman * \version 1.0 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the sum of two AABBs. * \param aabb [in] the other AABB * \return Self-Reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABB& AABB::Add(const AABB& aabb) { // Compute new min & max values Point Min; GetMin(Min); Point Tmp; aabb.GetMin(Tmp); Min.Min(Tmp); Point Max; GetMax(Max); aabb.GetMax(Tmp); Max.Max(Tmp); // Update this SetMinMax(Min, Max); return *this; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Makes a cube from the AABB. * \param cube [out] the cube AABB * \return cube edge length */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AABB::MakeCube(AABB& cube) const { Point Ext; GetExtents(Ext); float Max = Ext.Max(); Point Cnt; GetCenter(Cnt); cube.SetCenterExtents(Cnt, Point(Max, Max, Max)); return Max; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Makes a sphere from the AABB. * \param sphere [out] sphere containing the AABB */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABB::MakeSphere(Sphere& sphere) const { GetExtents(sphere.mCenter); sphere.mRadius = sphere.mCenter.Magnitude() * 1.00001f; // To make sure sphere::Contains(*this) succeeds GetCenter(sphere.mCenter); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks a box is inside another box. * \param box [in] the other AABB * \return true if current box is inside input box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABB::IsInside(const AABB& box) const { if(box.GetMin(0)>GetMin(0)) return false; if(box.GetMin(1)>GetMin(1)) return false; if(box.GetMin(2)>GetMin(2)) return false; if(box.GetMax(0) max.x) ? 2 : 0) // 2 = right + ((local_eye.y < min.y) ? 4 : 0) // 4 = bottom + ((local_eye.y > max.y) ? 8 : 0) // 8 = top + ((local_eye.z < min.z) ? 16 : 0) // 16 = front + ((local_eye.z > max.z) ? 32 : 0); // 32 = back // Look up number of vertices in outline num = (sdword)gIndexList[pos][7]; // Zero indicates invalid case if(!num) return null; return &gIndexList[pos][0]; } // calculateBoxArea: computes the screen-projected 2D area of an oriented 3D bounding box //const Point& eye, //eye point (in bbox object coordinates) //const AABB& box, //3d bbox //const Matrix4x4& mat, //free transformation for bbox //float width, float height, int& num) float AABB::ComputeBoxArea(const Point& eye, const Matrix4x4& mat, float width, float height, sdword& num) const { const sbyte* Outline = ComputeOutline(eye, num); if(!Outline) return -1.0f; // Compute box vertices Point vertexBox[8], dst[8]; ComputePoints(vertexBox); // Transform all outline corners into 2D screen space for(sdword i=0;i GetMax(0) || p.x < GetMin(0)) return FALSE; \ if(p.y > GetMax(1) || p.y < GetMin(1)) return FALSE; \ if(p.z > GetMax(2) || p.z < GetMin(2)) return FALSE; \ return TRUE; \ } enum AABBType { AABB_RENDER = 0, //!< AABB used for rendering. Not visible == not rendered. AABB_UPDATE = 1, //!< AABB used for dynamic updates. Not visible == not updated. AABB_FORCE_DWORD = 0x7fffffff, }; #ifdef USE_MINMAX struct ICEMATHS_API ShadowAABB { Point mMin; Point mMax; }; class ICEMATHS_API AABB { public: //! Constructor inline_ AABB() {} //! Destructor inline_ ~AABB() {} //! Type-independent methods AABB_COMMON_METHODS; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an AABB from min & max vectors. * \param min [in] the min point * \param max [in] the max point */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetMinMax(const Point& min, const Point& max) { mMin = min; mMax = max; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an AABB from center & extents vectors. * \param c [in] the center point * \param e [in] the extents vector */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetCenterExtents(const Point& c, const Point& e) { mMin = c - e; mMax = c + e; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an empty AABB. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetEmpty() { Point p(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); mMin = -p; mMax = p;} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups a point AABB. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetPoint(const Point& pt) { mMin = mMax = pt; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the size of the AABB. The size is defined as the longest extent. * \return the size of the AABB */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float GetSize() const { Point e; GetExtents(e); return e.Max(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Extends the AABB. * \param p [in] the next point */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Extend(const Point& p) { if(p.x > mMax.x) mMax.x = p.x; if(p.x < mMin.x) mMin.x = p.x; if(p.y > mMax.y) mMax.y = p.y; if(p.y < mMin.y) mMin.y = p.y; if(p.z > mMax.z) mMax.z = p.z; if(p.z < mMin.z) mMin.z = p.z; } // Data access //! Get min point of the box inline_ void GetMin(Point& min) const { min = mMin; } //! Get max point of the box inline_ void GetMax(Point& max) const { max = mMax; } //! Get component of the box's min point along a given axis inline_ float GetMin(udword axis) const { return mMin[axis]; } //! Get component of the box's max point along a given axis inline_ float GetMax(udword axis) const { return mMax[axis]; } //! Get box center inline_ void GetCenter(Point& center) const { center = (mMax + mMin)*0.5f; } //! Get box extents inline_ void GetExtents(Point& extents) const { extents = (mMax - mMin)*0.5f; } //! Get component of the box's center along a given axis inline_ float GetCenter(udword axis) const { return (mMax[axis] + mMin[axis])*0.5f; } //! Get component of the box's extents along a given axis inline_ float GetExtents(udword axis) const { return (mMax[axis] - mMin[axis])*0.5f; } //! Get box diagonal inline_ void GetDiagonal(Point& diagonal) const { diagonal = mMax - mMin; } inline_ float GetWidth() const { return mMax.x - mMin.x; } inline_ float GetHeight() const { return mMax.y - mMin.y; } inline_ float GetDepth() const { return mMax.z - mMin.z; } //! Volume inline_ float GetVolume() const { return GetWidth() * GetHeight() * GetDepth(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the intersection between two AABBs. * \param a [in] the other AABB * \return true on intersection */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL Intersect(const AABB& a) const { if(mMax.x < a.mMin.x || a.mMax.x < mMin.x || mMax.y < a.mMin.y || a.mMax.y < mMin.y || mMax.z < a.mMin.z || a.mMax.z < mMin.z) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the 1D-intersection between two AABBs, on a given axis. * \param a [in] the other AABB * \param axis [in] the axis (0, 1, 2) * \return true on intersection */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL Intersect(const AABB& a, udword axis) const { if(mMax[axis] < a.mMin[axis] || a.mMax[axis] < mMin[axis]) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recomputes the AABB after an arbitrary transform by a 4x4 matrix. * Original code by Charles Bloom on the GD-Algorithm list. (I slightly modified it) * \param mtx [in] the transform matrix * \param aabb [out] the transformed AABB [can be *this] */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const { // The three edges transformed: you can efficiently transform an X-only vector // by just getting the "X" column of the matrix Point vx,vy,vz; mtx.GetRow(0, vx); vx *= (mMax.x - mMin.x); mtx.GetRow(1, vy); vy *= (mMax.y - mMin.y); mtx.GetRow(2, vz); vz *= (mMax.z - mMin.z); // Transform the min point aabb.mMin = aabb.mMax = mMin * mtx; // Take the transformed min & axes and find new extents // Using CPU code in the right place is faster... if(IS_NEGATIVE_FLOAT(vx.x)) aabb.mMin.x += vx.x; else aabb.mMax.x += vx.x; if(IS_NEGATIVE_FLOAT(vx.y)) aabb.mMin.y += vx.y; else aabb.mMax.y += vx.y; if(IS_NEGATIVE_FLOAT(vx.z)) aabb.mMin.z += vx.z; else aabb.mMax.z += vx.z; if(IS_NEGATIVE_FLOAT(vy.x)) aabb.mMin.x += vy.x; else aabb.mMax.x += vy.x; if(IS_NEGATIVE_FLOAT(vy.y)) aabb.mMin.y += vy.y; else aabb.mMax.y += vy.y; if(IS_NEGATIVE_FLOAT(vy.z)) aabb.mMin.z += vy.z; else aabb.mMax.z += vy.z; if(IS_NEGATIVE_FLOAT(vz.x)) aabb.mMin.x += vz.x; else aabb.mMax.x += vz.x; if(IS_NEGATIVE_FLOAT(vz.y)) aabb.mMin.y += vz.y; else aabb.mMax.y += vz.y; if(IS_NEGATIVE_FLOAT(vz.z)) aabb.mMin.z += vz.z; else aabb.mMax.z += vz.z; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the AABB is valid. * \return true if the box is valid */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL IsValid() const { // Consistency condition for (Min, Max) boxes: min < max if(mMin.x > mMax.x) return FALSE; if(mMin.y > mMax.y) return FALSE; if(mMin.z > mMax.z) return FALSE; return TRUE; } //! Operator for AABB *= float. Scales the extents, keeps same center. inline_ AABB& operator*=(float s) { Point Center; GetCenter(Center); Point Extents; GetExtents(Extents); SetCenterExtents(Center, Extents * s); return *this; } //! Operator for AABB /= float. Scales the extents, keeps same center. inline_ AABB& operator/=(float s) { Point Center; GetCenter(Center); Point Extents; GetExtents(Extents); SetCenterExtents(Center, Extents / s); return *this; } //! Operator for AABB += Point. Translates the box. inline_ AABB& operator+=(const Point& trans) { mMin+=trans; mMax+=trans; return *this; } private: Point mMin; //!< Min point Point mMax; //!< Max point }; #else class ICEMATHS_API AABB { public: //! Constructor inline_ AABB() {} //! Destructor inline_ ~AABB() {} //! Type-independent methods AABB_COMMON_METHODS; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an AABB from min & max vectors. * \param min [in] the min point * \param max [in] the max point */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an AABB from center & extents vectors. * \param c [in] the center point * \param e [in] the extents vector */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetCenterExtents(const Point& c, const Point& e) { mCenter = c; mExtents = e; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an empty AABB. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetEmpty() { mCenter.Zero(); mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups a point AABB. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetPoint(const Point& pt) { mCenter = pt; mExtents.Zero(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the size of the AABB. The size is defined as the longest extent. * \return the size of the AABB */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float GetSize() const { return mExtents.Max(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Extends the AABB. * \param p [in] the next point */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Extend(const Point& p) { Point Max = mCenter + mExtents; Point Min = mCenter - mExtents; if(p.x > Max.x) Max.x = p.x; if(p.x < Min.x) Min.x = p.x; if(p.y > Max.y) Max.y = p.y; if(p.y < Min.y) Min.y = p.y; if(p.z > Max.z) Max.z = p.z; if(p.z < Min.z) Min.z = p.z; SetMinMax(Min, Max); } // Data access //! Get min point of the box inline_ void GetMin(Point& min) const { min = mCenter - mExtents; } //! Get max point of the box inline_ void GetMax(Point& max) const { max = mCenter + mExtents; } //! Get component of the box's min point along a given axis inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; } //! Get component of the box's max point along a given axis inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; } //! Get box center inline_ void GetCenter(Point& center) const { center = mCenter; } //! Get box extents inline_ void GetExtents(Point& extents) const { extents = mExtents; } //! Get component of the box's center along a given axis inline_ float GetCenter(udword axis) const { return mCenter[axis]; } //! Get component of the box's extents along a given axis inline_ float GetExtents(udword axis) const { return mExtents[axis]; } //! Get box diagonal inline_ void GetDiagonal(Point& diagonal) const { diagonal = mExtents * 2.0f; } inline_ float GetWidth() const { return mExtents.x * 2.0f; } inline_ float GetHeight() const { return mExtents.y * 2.0f; } inline_ float GetDepth() const { return mExtents.z * 2.0f; } //! Volume inline_ float GetVolume() const { return mExtents.x * mExtents.y * mExtents.z * 8.0f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the intersection between two AABBs. * \param a [in] the other AABB * \return true on intersection */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL Intersect(const AABB& a) const { float tx = mCenter.x - a.mCenter.x; float ex = a.mExtents.x + mExtents.x; if(AIR(tx) > IR(ex)) return FALSE; float ty = mCenter.y - a.mCenter.y; float ey = a.mExtents.y + mExtents.y; if(AIR(ty) > IR(ey)) return FALSE; float tz = mCenter.z - a.mCenter.z; float ez = a.mExtents.z + mExtents.z; if(AIR(tz) > IR(ez)) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * The standard intersection method from Gamasutra. Just here to check its speed against the one above. * \param a [in] the other AABB * \return true on intersection */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ bool GomezIntersect(const AABB& a) { Point T = mCenter - a.mCenter; // Vector from A to B return ((fabsf(T.x) <= (a.mExtents.x + mExtents.x)) && (fabsf(T.y) <= (a.mExtents.y + mExtents.y)) && (fabsf(T.z) <= (a.mExtents.z + mExtents.z))); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the 1D-intersection between two AABBs, on a given axis. * \param a [in] the other AABB * \param axis [in] the axis (0, 1, 2) * \return true on intersection */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL Intersect(const AABB& a, udword axis) const { float t = mCenter[axis] - a.mCenter[axis]; float e = a.mExtents[axis] + mExtents[axis]; if(AIR(t) > IR(e)) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recomputes the AABB after an arbitrary transform by a 4x4 matrix. * \param mtx [in] the transform matrix * \param aabb [out] the transformed AABB [can be *this] */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const { // Compute new center aabb.mCenter = mCenter * mtx; // Compute new extents. FPU code & CPU code have been interleaved for improved performance. Point Ex(mtx.m[0][0] * mExtents.x, mtx.m[0][1] * mExtents.x, mtx.m[0][2] * mExtents.x); //IR(Ex.x)&=0x7fffffff; IR(Ex.y)&=0x7fffffff; IR(Ex.z)&=0x7fffffff; Ex.x = FR( AIR(Ex.x) ); Ex.y = FR( AIR(Ex.y) ); Ex.z = FR( AIR(Ex.z) ); Point Ey(mtx.m[1][0] * mExtents.y, mtx.m[1][1] * mExtents.y, mtx.m[1][2] * mExtents.y); //IR(Ey.x)&=0x7fffffff; IR(Ey.y)&=0x7fffffff; IR(Ey.z)&=0x7fffffff; Ey.x = FR( AIR(Ey.x) ); Ey.y = FR( AIR(Ey.y) ); Ey.z = FR( AIR(Ey.z) ); Point Ez(mtx.m[2][0] * mExtents.z, mtx.m[2][1] * mExtents.z, mtx.m[2][2] * mExtents.z); //IR(Ez.x)&=0x7fffffff; IR(Ez.y)&=0x7fffffff; IR(Ez.z)&=0x7fffffff; Ez.x = FR( AIR(Ez.x) ); Ez.y = FR( AIR(Ez.y) ); Ez.z = FR( AIR(Ez.z) ); aabb.mExtents.x = Ex.x + Ey.x + Ez.x; aabb.mExtents.y = Ex.y + Ey.y + Ez.y; aabb.mExtents.z = Ex.z + Ey.z + Ez.z; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the AABB is valid. * \return true if the box is valid */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL IsValid() const { // Consistency condition for (Center, Extents) boxes: Extents >= 0 if(IS_NEGATIVE_FLOAT(mExtents.x)) return FALSE; if(IS_NEGATIVE_FLOAT(mExtents.y)) return FALSE; if(IS_NEGATIVE_FLOAT(mExtents.z)) return FALSE; return TRUE; } //! Operator for AABB *= float. Scales the extents, keeps same center. inline_ AABB& operator*=(float s) { mExtents*=s; return *this; } //! Operator for AABB /= float. Scales the extents, keeps same center. inline_ AABB& operator/=(float s) { mExtents/=s; return *this; } //! Operator for AABB += Point. Translates the box. inline_ AABB& operator+=(const Point& trans) { mCenter+=trans; return *this; } private: Point mCenter; //!< AABB Center Point mExtents; //!< x, y and z extents }; #endif inline_ void ComputeMinMax(const Point& p, Point& min, Point& max) { if(p.x > max.x) max.x = p.x; if(p.x < min.x) min.x = p.x; if(p.y > max.y) max.y = p.y; if(p.y < min.y) min.y = p.y; if(p.z > max.z) max.z = p.z; if(p.z < min.z) min.z = p.z; } inline_ void ComputeAABB(AABB& aabb, const Point* list, udword nb_pts) { if(list) { Point Maxi(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); Point Mini(MAX_FLOAT, MAX_FLOAT, MAX_FLOAT); while(nb_pts--) { // _prefetch(list+1); // off by one ? ComputeMinMax(*list++, Mini, Maxi); } aabb.SetMinMax(Mini, Maxi); } } #endif // __ICEAABB_H__ ode-0.14/OPCODE/Ice/IceAxes.h0000644000000000000000000000264312635011627014056 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains axes definition. * \file IceAxes.h * \author Pierre Terdiman * \date January, 29, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEAXES_H__ #define __ICEAXES_H__ enum PointComponent { X = 0, Y = 1, Z = 2, W = 3, FORCE_DWORD = 0x7fffffff }; enum AxisOrder { AXES_XYZ = (X)|(Y<<2)|(Z<<4), AXES_XZY = (X)|(Z<<2)|(Y<<4), AXES_YXZ = (Y)|(X<<2)|(Z<<4), AXES_YZX = (Y)|(Z<<2)|(X<<4), AXES_ZXY = (Z)|(X<<2)|(Y<<4), AXES_ZYX = (Z)|(Y<<2)|(X<<4), AXES_FORCE_DWORD = 0x7fffffff }; class ICEMATHS_API Axes { public: inline_ Axes(AxisOrder order) { mAxis0 = (order ) & 3; mAxis1 = (order>>2) & 3; mAxis2 = (order>>4) & 3; } inline_ ~Axes() {} udword mAxis0; udword mAxis1; udword mAxis2; }; #endif // __ICEAXES_H__ ode-0.14/OPCODE/Ice/IceBoundingSphere.h0000644000000000000000000001540612635011627016073 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code to compute the minimal bounding sphere. * \file IceBoundingSphere.h * \author Pierre Terdiman * \date January, 29, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEBOUNDINGSPHERE_H__ #define __ICEBOUNDINGSPHERE_H__ enum BSphereMethod { BS_NONE, BS_GEMS, BS_MINIBALL, BS_FORCE_DWORD = 0x7fffffff }; class ICEMATHS_API Sphere { public: //! Constructor inline_ Sphere() {} //! Constructor inline_ Sphere(const Point& center, float radius) : mCenter(center), mRadius(radius) {} //! Constructor Sphere(udword nb_verts, const Point* verts); //! Copy constructor inline_ Sphere(const Sphere& sphere) : mCenter(sphere.mCenter), mRadius(sphere.mRadius) {} //! Destructor inline_ ~Sphere() {} BSphereMethod Compute(udword nb_verts, const Point* verts); bool FastCompute(udword nb_verts, const Point* verts); // Access methods inline_ const Point& GetCenter() const { return mCenter; } inline_ float GetRadius() const { return mRadius; } inline_ const Point& Center() const { return mCenter; } inline_ float Radius() const { return mRadius; } inline_ Sphere& Set(const Point& center, float radius) { mCenter = center; mRadius = radius; return *this; } inline_ Sphere& SetCenter(const Point& center) { mCenter = center; return *this; } inline_ Sphere& SetRadius(float radius) { mRadius = radius; return *this; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if a point is contained within the sphere. * \param p [in] the point to test * \return true if inside the sphere */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ bool Contains(const Point& p) const { return mCenter.SquareDistance(p) <= mRadius*mRadius; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if a sphere is contained within the sphere. * \param sphere [in] the sphere to test * \return true if inside the sphere */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ bool Contains(const Sphere& sphere) const { // If our radius is the smallest, we can't possibly contain the other sphere if(mRadius < sphere.mRadius) return false; // So r is always positive or null now float r = mRadius - sphere.mRadius; return mCenter.SquareDistance(sphere.mCenter) <= r*r; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if a box is contained within the sphere. * \param aabb [in] the box to test * \return true if inside the sphere */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL Contains(const AABB& aabb) const { // I assume if all 8 box vertices are inside the sphere, so does the whole box. // Sounds ok but maybe there's a better way? float R2 = mRadius * mRadius; #ifdef USE_MIN_MAX const Point& Max = ((ShadowAABB&)&aabb).mMax; const Point& Min = ((ShadowAABB&)&aabb).mMin; #else Point Max; aabb.GetMax(Max); Point Min; aabb.GetMin(Min); #endif Point p; p.x=Max.x; p.y=Max.y; p.z=Max.z; if(mCenter.SquareDistance(p)>=R2) return FALSE; p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE; p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; p.x=Max.x; p.y=Max.y; p.z=Min.z; if(mCenter.SquareDistance(p)>=R2) return FALSE; p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE; p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if the sphere intersects another sphere * \param sphere [in] the other sphere * \return true if spheres overlap */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ bool Intersect(const Sphere& sphere) const { float r = mRadius + sphere.mRadius; return mCenter.SquareDistance(sphere.mCenter) <= r*r; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the sphere is valid. * \return true if the box is valid */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL IsValid() const { // Consistency condition for spheres: Radius >= 0.0f if(mRadius < 0.0f) return FALSE; return TRUE; } public: Point mCenter; //!< Sphere center float mRadius; //!< Sphere radius }; #endif // __ICEBOUNDINGSPHERE_H__ ode-0.14/OPCODE/Ice/IceContainer.cpp0000644000000000000000000003323212635011627015431 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a simple container class. * \file IceContainer.cpp * \author Pierre Terdiman * \date February, 5, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a list of 32-bits values. * Use this class when you need to store an unknown number of values. The list is automatically * resized and can contains 32-bits entities (dwords or floats) * * \class Container * \author Pierre Terdiman * \version 1.0 * \date 08.15.98 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceCore; // Static members #ifdef CONTAINER_STATS udword Container::mNbContainers = 0; udword Container::mUsedRam = 0; #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. No entries allocated there. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f) { #ifdef CONTAINER_STATS mNbContainers++; mUsedRam+=sizeof(Container); #endif } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. Also allocates a given number of entries. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor) { #ifdef CONTAINER_STATS mNbContainers++; mUsedRam+=sizeof(Container); #endif SetSize(size); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Copy constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f) { #ifdef CONTAINER_STATS mNbContainers++; mUsedRam+=sizeof(Container); #endif *this = object; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. Frees everything and leaves. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Container::~Container() { Empty(); #ifdef CONTAINER_STATS mNbContainers--; mUsedRam-=GetUsedRam(); #endif } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Clears the container. All stored values are deleted, and it frees used ram. * \see Reset() * \return Self-Reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Container& Container::Empty() { #ifdef CONTAINER_STATS mUsedRam-=mMaxNbEntries*sizeof(udword); #endif DELETEARRAY(mEntries); mCurNbEntries = mMaxNbEntries = 0; return *this; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Resizes the container. * \param needed [in] assume the container can be added at least "needed" values * \return true if success. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Container::Resize(udword needed) { #ifdef CONTAINER_STATS // Subtract previous amount of bytes mUsedRam-=mMaxNbEntries*sizeof(udword); #endif // Get more entries mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2 if(mMaxNbEntriesmMaxNbEntries) Resize(nb); // Add new entry CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(uword)); mCurNbEntries+=nb; return *this; } inline_ Container& Add(const udword* entries, udword nb) { // Resize if needed if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb); // Add new entry CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword)); mCurNbEntries+=nb; return *this; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A O(1) method to add a value in the container. The container is automatically resized if needed. * The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation * costs a lot more than the call overhead... * * \param entry [in] a float to store in the container * \see Add(udword entry) * \see Empty() * \see Contains(udword entry) * \return Self-Reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ Container& Add(float entry) { // Resize if needed if(mCurNbEntries==mMaxNbEntries) Resize(); // Add new entry mEntries[mCurNbEntries++] = IR(entry); return *this; } inline_ Container& Add(const float* entries, udword nb) { // Resize if needed if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb); // Add new entry CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(float)); mCurNbEntries+=nb; return *this; } //! Add unique [slow] inline_ Container& AddUnique(udword entry) { if(!Contains(entry)) Add(entry); return *this; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Clears the container. All stored values are deleted, and it frees used ram. * \see Reset() * \return Self-Reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Container& Empty(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Resets the container. Stored values are discarded but the buffer is kept so that further calls don't need resizing again. * That's a kind of temporal coherence. * \see Empty() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void Reset() { // Avoid the write if possible // ### CMOV if(mCurNbEntries) mCurNbEntries = 0; } // HANDLE WITH CARE inline_ void ForceSize(udword size) { mCurNbEntries = size; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Sets the initial size of the container. If it already contains something, it's discarded. * \param nb [in] Number of entries * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SetSize(udword nb); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the container and get rid of unused bytes. * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Refit(); // Checks whether the container already contains a given value. bool Contains(udword entry, udword* location=null) const; // Deletes an entry - doesn't preserve insertion order. bool Delete(udword entry); // Deletes an entry - does preserve insertion order. bool DeleteKeepingOrder(udword entry); //! Deletes the very last entry. inline_ void DeleteLastEntry() { if(mCurNbEntries) mCurNbEntries--; } //! Deletes the entry whose index is given inline_ void DeleteIndex(udword index) { mEntries[index] = mEntries[--mCurNbEntries]; } // Helpers Container& FindNext(udword& entry, FindMode find_mode=FIND_CLAMP); Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP); // Data access. inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries. inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries. inline_ udword GetFirst() const { return mEntries[0]; } inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; } // Growth control inline_ float GetGrowthFactor() const { return mGrowthFactor; } //!< Returns the growth factor inline_ void SetGrowthFactor(float growth) { mGrowthFactor = growth; } //!< Sets the growth factor inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty //! Read-access as an array inline_ udword operator[](udword i) const { ASSERT(i>=0 && i=0 && i>31); return FR(y); } //! Computes 1.0f / sqrtf(x). inline_ float frsqrt(float f) { float x = f * 0.5f; udword y = 0x5f3759df - (IR(f) >> 1); // Iteration... const float fy = FR(y); const float result = fy * ( 1.5f - ( x * fy * fy ) ); // Result return result; } //! Computes 1.0f / sqrtf(x). Comes from NVIDIA. inline_ float InvSqrt(const float& x) { const udword tmp = (udword(IEEE_1_0 << 1) + IEEE_1_0 - IR(x)) >> 1; const float y = FR(tmp); return y * (1.47f - 0.47f * x * y * y); } //! Computes 1.0f / sqrtf(x). Comes from Quake3. Looks like the first one I had above. //! See http://www.magic-software.com/3DGEDInvSqrt.html inline_ float RSqrt(float number) { int i; float x2, y; const float threehalfs = 1.5f; x2 = number * 0.5f; y = number; i = IR(y); i = 0x5f3759df - (i >> 1); y = FR(i); y = y * (threehalfs - (x2 * y * y)); return y; } //! TO BE DOCUMENTED inline_ float fsqrt(float f) { udword y = ( ( SIR(f) - 0x3f800000 ) >> 1 ) + 0x3f800000; // Iteration...? // (float&)y = (3.0f - ((float&)y * (float&)y) / f) * (float&)y * 0.5f; // Result return FR(y); } //! Returns the float ranged espilon value. inline_ float fepsilon(float f) { udword b = IR(f) & 0xff800000; udword a = b | 0x00000001; // Result return FR(a) - FR(b); } //! Is the float valid ? inline_ bool IsNAN(float value) { return (IR(value)&0x7f800000) == 0x7f800000; } inline_ bool IsIndeterminate(float value) { return IR(value) == 0xffc00000; } inline_ bool IsPlusInf(float value) { return IR(value) == 0x7f800000; } inline_ bool IsMinusInf(float value) { return IR(value) == 0xff800000; } inline_ bool IsValidFloat(float value) { if(IsNAN(value)) return false; if(IsIndeterminate(value)) return false; if(IsPlusInf(value)) return false; if(IsMinusInf(value)) return false; return true; } #define CHECK_VALID_FLOAT(x) ASSERT(IsValidFloat(x)); /* //! FPU precision setting function. inline_ void SetFPU() { // This function evaluates whether the floating-point // control word is set to single precision/round to nearest/ // exceptions disabled. If these conditions don't hold, the // function changes the control word to set them and returns // TRUE, putting the old control word value in the passback // location pointed to by pwOldCW. { uword wTemp, wSave; __asm fstcw wSave if (wSave & 0x300 || // Not single mode 0x3f != (wSave & 0x3f) || // Exceptions enabled wSave & 0xC00) // Not round to nearest mode { __asm { mov ax, wSave and ax, not 300h ;; single mode or ax, 3fh ;; disable all exceptions and ax, not 0xC00 ;; round to nearest mode mov wTemp, ax fldcw wTemp } } } } */ //! This function computes the slowest possible floating-point value (you can also directly use FLT_EPSILON) inline_ float ComputeFloatEpsilon() { const float f = FR( IR(1.0f) ^ 1 ); return f - 1.0f; // You can check it's the same as FLT_EPSILON } inline_ bool IsFloatZero(float x, float epsilon=1e-6f) { return x*x < epsilon; } #define FCOMI_ST0 _asm _emit 0xdb _asm _emit 0xf0 #define FCOMIP_ST0 _asm _emit 0xdf _asm _emit 0xf0 #define FCMOVB_ST0 _asm _emit 0xda _asm _emit 0xc0 #define FCMOVNB_ST0 _asm _emit 0xdb _asm _emit 0xc0 #define FCOMI_ST1 _asm _emit 0xdb _asm _emit 0xf1 #define FCOMIP_ST1 _asm _emit 0xdf _asm _emit 0xf1 #define FCMOVB_ST1 _asm _emit 0xda _asm _emit 0xc1 #define FCMOVNB_ST1 _asm _emit 0xdb _asm _emit 0xc1 #define FCOMI_ST2 _asm _emit 0xdb _asm _emit 0xf2 #define FCOMIP_ST2 _asm _emit 0xdf _asm _emit 0xf2 #define FCMOVB_ST2 _asm _emit 0xda _asm _emit 0xc2 #define FCMOVNB_ST2 _asm _emit 0xdb _asm _emit 0xc2 #define FCOMI_ST3 _asm _emit 0xdb _asm _emit 0xf3 #define FCOMIP_ST3 _asm _emit 0xdf _asm _emit 0xf3 #define FCMOVB_ST3 _asm _emit 0xda _asm _emit 0xc3 #define FCMOVNB_ST3 _asm _emit 0xdb _asm _emit 0xc3 #define FCOMI_ST4 _asm _emit 0xdb _asm _emit 0xf4 #define FCOMIP_ST4 _asm _emit 0xdf _asm _emit 0xf4 #define FCMOVB_ST4 _asm _emit 0xda _asm _emit 0xc4 #define FCMOVNB_ST4 _asm _emit 0xdb _asm _emit 0xc4 #define FCOMI_ST5 _asm _emit 0xdb _asm _emit 0xf5 #define FCOMIP_ST5 _asm _emit 0xdf _asm _emit 0xf5 #define FCMOVB_ST5 _asm _emit 0xda _asm _emit 0xc5 #define FCMOVNB_ST5 _asm _emit 0xdb _asm _emit 0xc5 #define FCOMI_ST6 _asm _emit 0xdb _asm _emit 0xf6 #define FCOMIP_ST6 _asm _emit 0xdf _asm _emit 0xf6 #define FCMOVB_ST6 _asm _emit 0xda _asm _emit 0xc6 #define FCMOVNB_ST6 _asm _emit 0xdb _asm _emit 0xc6 #define FCOMI_ST7 _asm _emit 0xdb _asm _emit 0xf7 #define FCOMIP_ST7 _asm _emit 0xdf _asm _emit 0xf7 #define FCMOVB_ST7 _asm _emit 0xda _asm _emit 0xc7 #define FCMOVNB_ST7 _asm _emit 0xdb _asm _emit 0xc7 //! A global function to find MAX(a,b) using FCOMI/FCMOV inline_ float FCMax2(float a, float b) { return (a > b) ? a : b; } //! A global function to find MIN(a,b) using FCOMI/FCMOV inline_ float FCMin2(float a, float b) { return (a < b) ? a : b; } //! A global function to find MAX(a,b,c) using FCOMI/FCMOV inline_ float FCMax3(float a, float b, float c) { return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); } //! A global function to find MIN(a,b,c) using FCOMI/FCMOV inline_ float FCMin3(float a, float b, float c) { return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); } inline_ int ConvertToSortable(float f) { int Fi = SIR(f); int Fmask = (Fi>>31); Fi ^= Fmask; Fmask &= ~(1<<31); Fi -= Fmask; return Fi; } enum FPUMode { FPU_FLOOR = 0, FPU_CEIL = 1, FPU_BEST = 2, FPU_FORCE_DWORD = 0x7fffffff }; FUNCTION ICECORE_API FPUMode GetFPUMode(); FUNCTION ICECORE_API void SaveFPU(); FUNCTION ICECORE_API void RestoreFPU(); FUNCTION ICECORE_API void SetFPUFloorMode(); FUNCTION ICECORE_API void SetFPUCeilMode(); FUNCTION ICECORE_API void SetFPUBestMode(); FUNCTION ICECORE_API void SetFPUPrecision24(); FUNCTION ICECORE_API void SetFPUPrecision53(); FUNCTION ICECORE_API void SetFPUPrecision64(); FUNCTION ICECORE_API void SetFPURoundingChop(); FUNCTION ICECORE_API void SetFPURoundingUp(); FUNCTION ICECORE_API void SetFPURoundingDown(); FUNCTION ICECORE_API void SetFPURoundingNear(); FUNCTION ICECORE_API int intChop(const float& f); FUNCTION ICECORE_API int intFloor(const float& f); FUNCTION ICECORE_API int intCeil(const float& f); #endif // __ICEFPU_H__ ode-0.14/OPCODE/Ice/IceHPoint.cpp0000644000000000000000000000755412635011627014720 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for homogeneous points. * \file IceHPoint.cpp * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Homogeneous point. * * Use it: * - for clipping in homogeneous space (standard way) * - to differentiate between points (w=1) and vectors (w=0). * - in some cases you can also use it instead of Point for padding reasons. * * \class HPoint * \author Pierre Terdiman * \version 1.0 * \warning No cross-product in 4D. * \warning HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Point Mul = HPoint * Matrix3x3; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Point HPoint::operator*(const Matrix3x3& mat) const { return Point( x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0], x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1], x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] ); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // HPoint Mul = HPoint * Matrix4x4; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HPoint HPoint::operator*(const Matrix4x4& mat) const { return HPoint( x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0], x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1], x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2], x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3]); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // HPoint *= Matrix4x4 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HPoint& HPoint::operator*=(const Matrix4x4& mat) { float xp = x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0]; float yp = x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1]; float zp = x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2]; float wp = x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3]; x = xp; y = yp; z = zp; w = wp; return *this; } ode-0.14/OPCODE/Ice/IceHPoint.h0000644000000000000000000001634612635011627014364 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for homogeneous points. * \file IceHPoint.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEHPOINT_H__ #define __ICEHPOINT_H__ class ICEMATHS_API HPoint : public Point { public: //! Empty constructor inline_ HPoint() {} //! Constructor from floats inline_ HPoint(float xx, float yy, float zz, float ww=0.0f) : Point(xx, yy, zz), w(ww) {} //! Constructor from array inline_ HPoint(const float f[4]) : Point(f), w(f[3]) {} //! Constructor from a Point inline_ HPoint(const Point& p, float ww=0.0f) : Point(p), w(ww) {} //! Destructor inline_ ~HPoint() {} //! Clear the point inline_ HPoint& Zero() { x = y = z = w = 0.0f; return *this; } //! Assignment from values inline_ HPoint& Set(float xx, float yy, float zz, float ww ) { x = xx; y = yy; z = zz; w = ww; return *this; } //! Assignment from array inline_ HPoint& Set(const float f[4]) { x = f[X]; y = f[Y]; z = f[Z]; w = f[W]; return *this; } //! Assignment from another h-point inline_ HPoint& Set(const HPoint& src) { x = src.x; y = src.y; z = src.z; w = src.w; return *this; } //! Add a vector inline_ HPoint& Add(float xx, float yy, float zz, float ww ) { x += xx; y += yy; z += zz; w += ww; return *this; } //! Add a vector inline_ HPoint& Add(const float f[4]) { x += f[X]; y += f[Y]; z += f[Z]; w += f[W]; return *this; } //! Subtract a vector inline_ HPoint& Sub(float xx, float yy, float zz, float ww ) { x -= xx; y -= yy; z -= zz; w -= ww; return *this; } //! Subtract a vector inline_ HPoint& Sub(const float f[4]) { x -= f[X]; y -= f[Y]; z -= f[Z]; w -= f[W]; return *this; } //! Multiplies by a scalar inline_ HPoint& Mul(float s) { x *= s; y *= s; z *= s; w *= s; return *this; } //! Returns MIN(x, y, z, w); float Min() const { return MIN(x, MIN(y, MIN(z, w))); } //! Returns MAX(x, y, z, w); float Max() const { return MAX(x, MAX(y, MAX(z, w))); } //! Sets each element to be componentwise minimum HPoint& Min(const HPoint& p) { x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z); w = MIN(w, p.w); return *this; } //! Sets each element to be componentwise maximum HPoint& Max(const HPoint& p) { x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z); w = MAX(w, p.w); return *this; } //! Computes square magnitude inline_ float SquareMagnitude() const { return x*x + y*y + z*z + w*w; } //! Computes magnitude inline_ float Magnitude() const { return sqrtf(x*x + y*y + z*z + w*w); } //! Normalize the vector inline_ HPoint& Normalize() { float M = Magnitude(); if(M) { M = 1.0f / M; x *= M; y *= M; z *= M; w *= M; } return *this; } // Arithmetic operators //! Operator for HPoint Negate = - HPoint; inline_ HPoint operator-() const { return HPoint(-x, -y, -z, -w); } //! Operator for HPoint Plus = HPoint + HPoint; inline_ HPoint operator+(const HPoint& p) const { return HPoint(x + p.x, y + p.y, z + p.z, w + p.w); } //! Operator for HPoint Minus = HPoint - HPoint; inline_ HPoint operator-(const HPoint& p) const { return HPoint(x - p.x, y - p.y, z - p.z, w - p.w); } //! Operator for HPoint Mul = HPoint * HPoint; inline_ HPoint operator*(const HPoint& p) const { return HPoint(x * p.x, y * p.y, z * p.z, w * p.w); } //! Operator for HPoint Scale = HPoint * float; inline_ HPoint operator*(float s) const { return HPoint(x * s, y * s, z * s, w * s); } //! Operator for HPoint Scale = float * HPoint; inline_ friend HPoint operator*(float s, const HPoint& p) { return HPoint(s * p.x, s * p.y, s * p.z, s * p.w); } //! Operator for HPoint Div = HPoint / HPoint; inline_ HPoint operator/(const HPoint& p) const { return HPoint(x / p.x, y / p.y, z / p.z, w / p.w); } //! Operator for HPoint Scale = HPoint / float; inline_ HPoint operator/(float s) const { s = 1.0f / s; return HPoint(x * s, y * s, z * s, w * s); } //! Operator for HPoint Scale = float / HPoint; inline_ friend HPoint operator/(float s, const HPoint& p) { return HPoint(s / p.x, s / p.y, s / p.z, s / p.w); } //! Operator for float DotProd = HPoint | HPoint; inline_ float operator|(const HPoint& p) const { return x*p.x + y*p.y + z*p.z + w*p.w; } // No cross-product in 4D //! Operator for HPoint += HPoint; inline_ HPoint& operator+=(const HPoint& p) { x += p.x; y += p.y; z += p.z; w += p.w; return *this; } //! Operator for HPoint += float; inline_ HPoint& operator+=(float s) { x += s; y += s; z += s; w += s; return *this; } //! Operator for HPoint -= HPoint; inline_ HPoint& operator-=(const HPoint& p) { x -= p.x; y -= p.y; z -= p.z; w -= p.w; return *this; } //! Operator for HPoint -= float; inline_ HPoint& operator-=(float s) { x -= s; y -= s; z -= s; w -= s; return *this; } //! Operator for HPoint *= HPoint; inline_ HPoint& operator*=(const HPoint& p) { x *= p.x; y *= p.y; z *= p.z; w *= p.w; return *this; } //! Operator for HPoint *= float; inline_ HPoint& operator*=(float s) { x*=s; y*=s; z*=s; w*=s; return *this; } //! Operator for HPoint /= HPoint; inline_ HPoint& operator/=(const HPoint& p) { x /= p.x; y /= p.y; z /= p.z; w /= p.w; return *this; } //! Operator for HPoint /= float; inline_ HPoint& operator/=(float s) { s = 1.0f / s; x*=s; y*=s; z*=s; w*=s; return *this; } // Arithmetic operators //! Operator for Point Mul = HPoint * Matrix3x3; Point operator*(const Matrix3x3& mat) const; //! Operator for HPoint Mul = HPoint * Matrix4x4; HPoint operator*(const Matrix4x4& mat) const; // HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4 //! Operator for HPoint *= Matrix4x4 HPoint& operator*=(const Matrix4x4& mat); // Logical operators //! Operator for "if(HPoint==HPoint)" inline_ bool operator==(const HPoint& p) const { return ( (x==p.x)&&(y==p.y)&&(z==p.z)&&(w==p.w)); } //! Operator for "if(HPoint!=HPoint)" inline_ bool operator!=(const HPoint& p) const { return ( (x!=p.x)||(y!=p.y)||(z!=p.z)||(w!=p.w)); } // Cast operators //! Cast a HPoint to a Point. w is discarded. #ifdef _MSC_VER inline_ operator Point() const { return Point(x, y, z); } // gcc complains that conversion to a base class will never use a type conversion operator #endif public: float w; }; #endif // __ICEHPOINT_H__ ode-0.14/OPCODE/Ice/IceIndexedTriangle.cpp0000644000000000000000000005730212635011627016561 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a handy indexed triangle class. * \file IceIndexedTriangle.cpp * \author Pierre Terdiman * \date January, 17, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains an indexed triangle class. * * \class Triangle * \author Pierre Terdiman * \version 1.0 * \date 08.15.98 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Flips the winding order. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::Flip() { Swap(mVRef[1], mVRef[2]); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle area. * \param verts [in] the list of indexed vertices * \return the area */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float IndexedTriangle::Area(const Point* verts) const { if(!verts) return 0.0f; const Point& p0 = verts[0]; const Point& p1 = verts[1]; const Point& p2 = verts[2]; return ((p0-p1)^(p0-p2)).Magnitude() * 0.5f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle perimeter. * \param verts [in] the list of indexed vertices * \return the perimeter */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float IndexedTriangle::Perimeter(const Point* verts) const { if(!verts) return 0.0f; const Point& p0 = verts[0]; const Point& p1 = verts[1]; const Point& p2 = verts[2]; return p0.Distance(p1) + p0.Distance(p2) + p1.Distance(p2); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle compacity. * \param verts [in] the list of indexed vertices * \return the compacity */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float IndexedTriangle::Compacity(const Point* verts) const { if(!verts) return 0.0f; float P = Perimeter(verts); if(P==0.0f) return 0.0f; return (4.0f*PI*Area(verts)/(P*P)); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle normal. * \param verts [in] the list of indexed vertices * \param normal [out] the computed normal */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::Normal(const Point* verts, Point& normal) const { if(!verts) return; const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; normal = ((p2-p1)^(p0-p1)).Normalize(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle denormalized normal. * \param verts [in] the list of indexed vertices * \param normal [out] the computed normal */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::DenormalizedNormal(const Point* verts, Point& normal) const { if(!verts) return; const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; normal = ((p2-p1)^(p0-p1)); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle center. * \param verts [in] the list of indexed vertices * \param center [out] the computed center */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::Center(const Point* verts, Point& center) const { if(!verts) return; const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; center = (p0+p1+p2)*INV3; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the centered normal * \param verts [in] the list of indexed vertices * \param normal [out] the computed centered normal */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::CenteredNormal(const Point* verts, Point& normal) const { if(!verts) return; const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; Point Center = (p0+p1+p2)*INV3; normal = Center + ((p2-p1)^(p0-p1)).Normalize(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes a random point within the triangle. * \param verts [in] the list of indexed vertices * \param normal [out] the computed centered normal */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::RandomPoint(const Point* verts, Point& random) const { if(!verts) return; // Random barycentric coords float Alpha = UnitRandomFloat(); float Beta = UnitRandomFloat(); float Gamma = UnitRandomFloat(); float OneOverTotal = 1.0f / (Alpha + Beta + Gamma); Alpha *= OneOverTotal; Beta *= OneOverTotal; Gamma *= OneOverTotal; const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; random = Alpha*p0 + Beta*p1 + Gamma*p2; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes backface culling. * \param verts [in] the list of indexed vertices * \param source [in] source point (in local space) from which culling must be computed * \return true if the triangle is visible from the source point */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IndexedTriangle::IsVisible(const Point* verts, const Point& source) const { // Checkings if(!verts) return false; const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; // Compute denormalized normal Point Normal = (p2 - p1)^(p0 - p1); // Backface culling return (Normal | source) >= 0.0f; // Same as: // Plane PL(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); // return PL.Distance(source) > PL.d; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes backface culling. * \param verts [in] the list of indexed vertices * \param source [in] source point (in local space) from which culling must be computed * \return true if the triangle is visible from the source point */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IndexedTriangle::BackfaceCulling(const Point* verts, const Point& source) const { // Checkings if(!verts) return false; const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; // Compute base // Point Base = (p0 + p1 + p2)*INV3; // Compute denormalized normal Point Normal = (p2 - p1)^(p0 - p1); // Backface culling // return (Normal | (source - Base)) >= 0.0f; return (Normal | (source - p0)) >= 0.0f; // Same as: (but a bit faster) // Plane PL(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); // return PL.Distance(source)>0.0f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the occlusion potential of the triangle. * \param verts [in] the list of indexed vertices * \param source [in] source point (in local space) from which occlusion potential must be computed * \return the occlusion potential */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float IndexedTriangle::ComputeOcclusionPotential(const Point* verts, const Point& view) const { if(!verts) return 0.0f; // Occlusion potential: -(A * (N|V) / d^2) // A = polygon area // N = polygon normal // V = view vector // d = distance viewpoint-center of polygon float A = Area(verts); Point N; Normal(verts, N); Point C; Center(verts, C); float d = view.Distance(C); return -(A*(N|view))/(d*d); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Replaces a vertex reference with another one. * \param oldref [in] the vertex reference to replace * \param newref [in] the new vertex reference * \return true if success, else false if the input vertex reference doesn't belong to the triangle */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IndexedTriangle::ReplaceVertex(dTriIndex oldref, dTriIndex newref) { if(mVRef[0]==oldref) { mVRef[0] = newref; return true; } else if(mVRef[1]==oldref) { mVRef[1] = newref; return true; } else if(mVRef[2]==oldref) { mVRef[2] = newref; return true; } return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks whether the triangle is degenerate or not. A degenerate triangle has two common vertex references. This is a zero-area triangle. * \return true if the triangle is degenerate */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IndexedTriangle::IsDegenerate() const { if(mVRef[0]==mVRef[1]) return true; if(mVRef[1]==mVRef[2]) return true; if(mVRef[2]==mVRef[0]) return true; return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks whether the input vertex reference belongs to the triangle or not. * \param ref [in] the vertex reference to look for * \return true if the triangle contains the vertex reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IndexedTriangle::HasVertex(dTriIndex ref) const { if(mVRef[0]==ref) return true; if(mVRef[1]==ref) return true; if(mVRef[2]==ref) return true; return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks whether the input vertex reference belongs to the triangle or not. * \param ref [in] the vertex reference to look for * \param index [out] the corresponding index in the triangle * \return true if the triangle contains the vertex reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IndexedTriangle::HasVertex(dTriIndex ref, dTriIndex* index) const { if(mVRef[0]==ref) { *index = 0; return true; } if(mVRef[1]==ref) { *index = 1; return true; } if(mVRef[2]==ref) { *index = 2; return true; } return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Finds an edge in a tri, given two vertex references. * \param vref0 [in] the edge's first vertex reference * \param vref1 [in] the edge's second vertex reference * \return the edge number between 0 and 2, or 0xff if input refs are wrong. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ubyte IndexedTriangle::FindEdge(dTriIndex vref0, dTriIndex vref1) const { if(mVRef[0]==vref0 && mVRef[1]==vref1) return 0; else if(mVRef[0]==vref1 && mVRef[1]==vref0) return 0; else if(mVRef[0]==vref0 && mVRef[2]==vref1) return 1; else if(mVRef[0]==vref1 && mVRef[2]==vref0) return 1; else if(mVRef[1]==vref0 && mVRef[2]==vref1) return 2; else if(mVRef[1]==vref1 && mVRef[2]==vref0) return 2; return 0xff; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the last reference given the first two. * \param vref0 [in] the first vertex reference * \param vref1 [in] the second vertex reference * \return the last reference, or INVALID_ID if input refs are wrong. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// dTriIndex IndexedTriangle::OppositeVertex(dTriIndex vref0, dTriIndex vref1) const { if(mVRef[0]==vref0 && mVRef[1]==vref1) return mVRef[2]; else if(mVRef[0]==vref1 && mVRef[1]==vref0) return mVRef[2]; else if(mVRef[0]==vref0 && mVRef[2]==vref1) return mVRef[1]; else if(mVRef[0]==vref1 && mVRef[2]==vref0) return mVRef[1]; else if(mVRef[1]==vref0 && mVRef[2]==vref1) return mVRef[0]; else if(mVRef[1]==vref1 && mVRef[2]==vref0) return mVRef[0]; return (dTriIndex)INVALID_ID; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the three sorted vertex references according to an edge number. * edgenb = 0 => edge 0-1, returns references 0, 1, 2 * edgenb = 1 => edge 0-2, returns references 0, 2, 1 * edgenb = 2 => edge 1-2, returns references 1, 2, 0 * * \param edgenb [in] the edge number, 0, 1 or 2 * \param vref0 [out] the returned first vertex reference * \param vref1 [out] the returned second vertex reference * \param vref2 [out] the returned third vertex reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::GetVRefs(ubyte edgenb, dTriIndex& vref0, dTriIndex& vref1, dTriIndex& vref2) const { if(edgenb==0) { vref0 = mVRef[0]; vref1 = mVRef[1]; vref2 = mVRef[2]; } else if(edgenb==1) { vref0 = mVRef[0]; vref1 = mVRef[2]; vref2 = mVRef[1]; } else if(edgenb==2) { vref0 = mVRef[1]; vref1 = mVRef[2]; vref2 = mVRef[0]; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle's smallest edge length. * \param verts [in] the list of indexed vertices * \return the smallest edge length */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float IndexedTriangle::MinEdgeLength(const Point* verts) const { if(!verts) return 0.0f; float Min = MAX_FLOAT; float Length01 = verts[0].Distance(verts[1]); float Length02 = verts[0].Distance(verts[2]); float Length12 = verts[1].Distance(verts[2]); if(Length01 < Min) Min = Length01; if(Length02 < Min) Min = Length02; if(Length12 < Min) Min = Length12; return Min; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle's largest edge length. * \param verts [in] the list of indexed vertices * \return the largest edge length */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float IndexedTriangle::MaxEdgeLength(const Point* verts) const { if(!verts) return 0.0f; float Max = MIN_FLOAT; float Length01 = verts[0].Distance(verts[1]); float Length02 = verts[0].Distance(verts[2]); float Length12 = verts[1].Distance(verts[2]); if(Length01 > Max) Max = Length01; if(Length02 > Max) Max = Length02; if(Length12 > Max) Max = Length12; return Max; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes a point on the triangle according to the stabbing information. * \param verts [in] the list of indexed vertices * \param u,v [in] point's barycentric coordinates * \param pt [out] point on triangle * \param nearvtx [out] index of nearest vertex */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void IndexedTriangle::ComputePoint(const Point* verts, float u, float v, Point& pt, dTriIndex* nearvtx) const { // Checkings if(!verts) return; // Get face in local or global space const Point& p0 = verts[mVRef[0]]; const Point& p1 = verts[mVRef[1]]; const Point& p2 = verts[mVRef[2]]; // Compute point coordinates pt = (1.0f - u - v)*p0 + u*p1 + v*p2; // Compute nearest vertex if needed if(nearvtx) { // Compute distance vector Point d(p0.SquareDistance(pt), // Distance^2 from vertex 0 to point on the face p1.SquareDistance(pt), // Distance^2 from vertex 1 to point on the face p2.SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face // Get smallest distance *nearvtx = mVRef[d.SmallestAxis()]; } } //************************************** // Angle between two vectors (in radians) // we use this formula // uv = |u||v| cos(u,v) // u ^ v = w // |w| = |u||v| |sin(u,v)| //************************************** float Angle(const Point& u, const Point& v) { float NormU = u.Magnitude(); // |u| float NormV = v.Magnitude(); // |v| float Product = NormU*NormV; // |u||v| if(Product==0.0f) return 0.0f; float OneOverProduct = 1.0f / Product; // Cosinus float Cosinus = (u|v) * OneOverProduct; // Sinus Point w = u^v; float NormW = w.Magnitude(); float AbsSinus = NormW * OneOverProduct; // Remove degeneracy if(AbsSinus > 1.0f) AbsSinus = 1.0f; if(AbsSinus < -1.0f) AbsSinus = -1.0f; if(Cosinus>=0.0f) return asinf(AbsSinus); else return (PI-asinf(AbsSinus)); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the angle between two triangles. * \param tri [in] the other triangle * \param verts [in] the list of indexed vertices * \return the angle in radians */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float IndexedTriangle::Angle(const IndexedTriangle& tri, const Point* verts) const { // Checkings if(!verts) return 0.0f; // Compute face normals Point n0, n1; Normal(verts, n0); tri.Normal(verts, n1); // Compute angle float dp = n0|n1; if(dp>1.0f) return 0.0f; if(dp<-1.0f) return PI; return acosf(dp); // return ::Angle(n0,n1); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks a triangle is the same as another one. * \param tri [in] the other triangle * \return true if same triangle */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IndexedTriangle::Equal(const IndexedTriangle& tri) const { // Test all vertex references return (HasVertex(tri.mVRef[0]) && HasVertex(tri.mVRef[1]) && HasVertex(tri.mVRef[2])); } ode-0.14/OPCODE/Ice/IceIndexedTriangle.h0000644000000000000000000000666612635011627016235 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a handy indexed triangle class. * \file IceIndexedTriangle.h * \author Pierre Terdiman * \date January, 17, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "ode/common.h" /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEINDEXEDTRIANGLE_H__ #define __ICEINDEXEDTRIANGLE_H__ // Forward declarations #ifdef _MSC_VER enum CubeIndex; #else typedef int CubeIndex; #endif // An indexed triangle class. class ICEMATHS_API IndexedTriangle { public: //! Constructor inline_ IndexedTriangle() {} //! Constructor inline_ IndexedTriangle(dTriIndex r0, dTriIndex r1, dTriIndex r2) { mVRef[0]=r0; mVRef[1]=r1; mVRef[2]=r2; } //! Copy constructor inline_ IndexedTriangle(const IndexedTriangle& triangle) { mVRef[0] = triangle.mVRef[0]; mVRef[1] = triangle.mVRef[1]; mVRef[2] = triangle.mVRef[2]; } //! Destructor inline_ ~IndexedTriangle() {} //! Vertex-references dTriIndex mVRef[3]; // Methods void Flip(); float Area(const Point* verts) const; float Perimeter(const Point* verts) const; float Compacity(const Point* verts) const; void Normal(const Point* verts, Point& normal) const; void DenormalizedNormal(const Point* verts, Point& normal) const; void Center(const Point* verts, Point& center) const; void CenteredNormal(const Point* verts, Point& normal) const; void RandomPoint(const Point* verts, Point& random) const; bool IsVisible(const Point* verts, const Point& source) const; bool BackfaceCulling(const Point* verts, const Point& source) const; float ComputeOcclusionPotential(const Point* verts, const Point& view) const; bool ReplaceVertex(dTriIndex oldref, dTriIndex newref); bool IsDegenerate() const; bool HasVertex(dTriIndex ref) const; bool HasVertex(dTriIndex ref, dTriIndex* index) const; ubyte FindEdge(dTriIndex vref0, dTriIndex vref1) const; dTriIndex OppositeVertex(dTriIndex vref0, dTriIndex vref1) const; inline_ dTriIndex OppositeVertex(ubyte edgenb) const { return mVRef[2-edgenb]; } void GetVRefs(ubyte edgenb, dTriIndex& vref0, dTriIndex& vref1, dTriIndex& vref2) const; float MinEdgeLength(const Point* verts) const; float MaxEdgeLength(const Point* verts) const; void ComputePoint(const Point* verts, float u, float v, Point& pt, dTriIndex* nearvtx=null) const; float Angle(const IndexedTriangle& tri, const Point* verts) const; inline_ Plane PlaneEquation(const Point* verts) const { return Plane(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); } bool Equal(const IndexedTriangle& tri) const; CubeIndex ComputeCubeIndex(const Point* verts) const; }; #endif // __ICEINDEXEDTRIANGLE_H__ ode-0.14/OPCODE/Ice/IceLSS.h0000644000000000000000000000756112635011627013623 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for line-swept spheres. * \file IceLSS.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICELSS_H__ #define __ICELSS_H__ class ICEMATHS_API LSS : public Segment { public: //! Constructor inline_ LSS() {} //! Constructor inline_ LSS(const Segment& seg, float radius) : Segment(seg), mRadius(radius) {} //! Destructor inline_ ~LSS() {} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes an OBB surrounding the LSS. * \param box [out] the OBB */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ComputeOBB(OBB& box); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if a point is contained within the LSS. * \param pt [in] the point to test * \return true if inside the LSS * \warning point and LSS must be in same space */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ bool Contains(const Point& pt) const { return SquareDistance(pt) <= mRadius*mRadius; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if a sphere is contained within the LSS. * \param sphere [in] the sphere to test * \return true if inside the LSS * \warning sphere and LSS must be in same space */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ bool Contains(const Sphere& sphere) { float d = mRadius - sphere.mRadius; if(d>=0.0f) return SquareDistance(sphere.mCenter) <= d*d; else return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if an LSS is contained within the LSS. * \param lss [in] the LSS to test * \return true if inside the LSS * \warning both LSS must be in same space */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ bool Contains(const LSS& lss) { // We check the LSS contains the two spheres at the start and end of the sweep return Contains(Sphere(lss.mP0, lss.mRadius)) && Contains(Sphere(lss.mP0, lss.mRadius)); } float mRadius; //!< Sphere radius }; #endif // __ICELSS_H__ ode-0.14/OPCODE/Ice/IceMatrix3x3.cpp0000644000000000000000000000346312635011627015314 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for 3x3 matrices. * \file IceMatrix3x3.cpp * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * 3x3 matrix. * DirectX-compliant, ie row-column order, ie m[Row][Col]. * Same as: * m11 m12 m13 first row. * m21 m22 m23 second row. * m31 m32 m33 third row. * Stored in memory as m11 m12 m13 m21... * * Multiplication rules: * * [x'y'z'] = [xyz][M] * * x' = x*m11 + y*m21 + z*m31 * y' = x*m12 + y*m22 + z*m32 * z' = x*m13 + y*m23 + z*m33 * * \class Matrix3x3 * \author Pierre Terdiman * \version 1.0 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; // Cast operator Matrix3x3::operator Matrix4x4() const { return Matrix4x4( m[0][0], m[0][1], m[0][2], 0.0f, m[1][0], m[1][1], m[1][2], 0.0f, m[2][0], m[2][1], m[2][2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); } ode-0.14/OPCODE/Ice/IceMatrix3x3.h0000644000000000000000000004755212635011627014770 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for 3x3 matrices. * \file IceMatrix3x3.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEMATRIX3X3_H__ #define __ICEMATRIX3X3_H__ // Forward declarations class Quat; #define MATRIX3X3_EPSILON (1.0e-7f) class ICEMATHS_API Matrix3x3 { public: //! Empty constructor inline_ Matrix3x3() {} //! Constructor from 9 values inline_ Matrix3x3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; } //! Copy constructor inline_ Matrix3x3(const Matrix3x3& mat) { CopyMemory(m, &mat.m, 9*sizeof(float)); } //! Destructor inline_ ~Matrix3x3() {} //! Assign values inline_ void Set(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; } //! Sets the scale from a Point. The point is put on the diagonal. inline_ void SetScale(const Point& p) { m[0][0] = p.x; m[1][1] = p.y; m[2][2] = p.z; } //! Sets the scale from floats. Values are put on the diagonal. inline_ void SetScale(float sx, float sy, float sz) { m[0][0] = sx; m[1][1] = sy; m[2][2] = sz; } //! Scales from a Point. Each row is multiplied by a component. inline_ void Scale(const Point& p) { m[0][0] *= p.x; m[0][1] *= p.x; m[0][2] *= p.x; m[1][0] *= p.y; m[1][1] *= p.y; m[1][2] *= p.y; m[2][0] *= p.z; m[2][1] *= p.z; m[2][2] *= p.z; } //! Scales from floats. Each row is multiplied by a value. inline_ void Scale(float sx, float sy, float sz) { m[0][0] *= sx; m[0][1] *= sx; m[0][2] *= sx; m[1][0] *= sy; m[1][1] *= sy; m[1][2] *= sy; m[2][0] *= sz; m[2][1] *= sz; m[2][2] *= sz; } //! Copy from a Matrix3x3 inline_ void Copy(const Matrix3x3& source) { CopyMemory(m, source.m, 9*sizeof(float)); } // Row-column access //! Returns a row. inline_ void GetRow(const udword r, Point& p) const { p.x = m[r][0]; p.y = m[r][1]; p.z = m[r][2]; } //! Returns a row. inline_ const Point& GetRow(const udword r) const { return *(const Point*)&m[r][0]; } //! Returns a row. inline_ Point& GetRow(const udword r) { return *(Point*)&m[r][0]; } //! Sets a row. inline_ void SetRow(const udword r, const Point& p) { m[r][0] = p.x; m[r][1] = p.y; m[r][2] = p.z; } //! Returns a column. inline_ void GetCol(const udword c, Point& p) const { p.x = m[0][c]; p.y = m[1][c]; p.z = m[2][c]; } //! Sets a column. inline_ void SetCol(const udword c, const Point& p) { m[0][c] = p.x; m[1][c] = p.y; m[2][c] = p.z; } //! Computes the trace. The trace is the sum of the 3 diagonal components. inline_ float Trace() const { return m[0][0] + m[1][1] + m[2][2]; } //! Clears the matrix. inline_ void Zero() { ZeroMemory(&m, sizeof(m)); } //! Sets the identity matrix. inline_ void Identity() { Zero(); m[0][0] = m[1][1] = m[2][2] = 1.0f; } //! Checks for identity inline_ bool IsIdentity() const { if(IR(m[0][0])!=IEEE_1_0) return false; if(IR(m[0][1])!=0) return false; if(IR(m[0][2])!=0) return false; if(IR(m[1][0])!=0) return false; if(IR(m[1][1])!=IEEE_1_0) return false; if(IR(m[1][2])!=0) return false; if(IR(m[2][0])!=0) return false; if(IR(m[2][1])!=0) return false; if(IR(m[2][2])!=IEEE_1_0) return false; return true; } //! Checks matrix validity inline_ BOOL IsValid() const { for(udword j=0;j<3;j++) { for(udword i=0;i<3;i++) { if(!IsValidFloat(m[j][i])) return FALSE; } } return TRUE; } //! Makes a skew-symmetric matrix (a.k.a. Star(*) Matrix) //! [ 0.0 -a.z a.y ] //! [ a.z 0.0 -a.x ] //! [ -a.y a.x 0.0 ] //! This is also called a "cross matrix" since for any vectors A and B, //! A^B = Skew(A) * B = - B * Skew(A); inline_ void SkewSymmetric(const Point& a) { m[0][0] = 0.0f; m[0][1] = -a.z; m[0][2] = a.y; m[1][0] = a.z; m[1][1] = 0.0f; m[1][2] = -a.x; m[2][0] = -a.y; m[2][1] = a.x; m[2][2] = 0.0f; } //! Negates the matrix inline_ void Neg() { m[0][0] = -m[0][0]; m[0][1] = -m[0][1]; m[0][2] = -m[0][2]; m[1][0] = -m[1][0]; m[1][1] = -m[1][1]; m[1][2] = -m[1][2]; m[2][0] = -m[2][0]; m[2][1] = -m[2][1]; m[2][2] = -m[2][2]; } //! Neg from another matrix inline_ void Neg(const Matrix3x3& mat) { m[0][0] = -mat.m[0][0]; m[0][1] = -mat.m[0][1]; m[0][2] = -mat.m[0][2]; m[1][0] = -mat.m[1][0]; m[1][1] = -mat.m[1][1]; m[1][2] = -mat.m[1][2]; m[2][0] = -mat.m[2][0]; m[2][1] = -mat.m[2][1]; m[2][2] = -mat.m[2][2]; } //! Add another matrix inline_ void Add(const Matrix3x3& mat) { m[0][0] += mat.m[0][0]; m[0][1] += mat.m[0][1]; m[0][2] += mat.m[0][2]; m[1][0] += mat.m[1][0]; m[1][1] += mat.m[1][1]; m[1][2] += mat.m[1][2]; m[2][0] += mat.m[2][0]; m[2][1] += mat.m[2][1]; m[2][2] += mat.m[2][2]; } //! Sub another matrix inline_ void Sub(const Matrix3x3& mat) { m[0][0] -= mat.m[0][0]; m[0][1] -= mat.m[0][1]; m[0][2] -= mat.m[0][2]; m[1][0] -= mat.m[1][0]; m[1][1] -= mat.m[1][1]; m[1][2] -= mat.m[1][2]; m[2][0] -= mat.m[2][0]; m[2][1] -= mat.m[2][1]; m[2][2] -= mat.m[2][2]; } //! Mac inline_ void Mac(const Matrix3x3& a, const Matrix3x3& b, float s) { m[0][0] = a.m[0][0] + b.m[0][0] * s; m[0][1] = a.m[0][1] + b.m[0][1] * s; m[0][2] = a.m[0][2] + b.m[0][2] * s; m[1][0] = a.m[1][0] + b.m[1][0] * s; m[1][1] = a.m[1][1] + b.m[1][1] * s; m[1][2] = a.m[1][2] + b.m[1][2] * s; m[2][0] = a.m[2][0] + b.m[2][0] * s; m[2][1] = a.m[2][1] + b.m[2][1] * s; m[2][2] = a.m[2][2] + b.m[2][2] * s; } //! Mac inline_ void Mac(const Matrix3x3& a, float s) { m[0][0] += a.m[0][0] * s; m[0][1] += a.m[0][1] * s; m[0][2] += a.m[0][2] * s; m[1][0] += a.m[1][0] * s; m[1][1] += a.m[1][1] * s; m[1][2] += a.m[1][2] * s; m[2][0] += a.m[2][0] * s; m[2][1] += a.m[2][1] * s; m[2][2] += a.m[2][2] * s; } //! this = A * s inline_ void Mult(const Matrix3x3& a, float s) { m[0][0] = a.m[0][0] * s; m[0][1] = a.m[0][1] * s; m[0][2] = a.m[0][2] * s; m[1][0] = a.m[1][0] * s; m[1][1] = a.m[1][1] * s; m[1][2] = a.m[1][2] * s; m[2][0] = a.m[2][0] * s; m[2][1] = a.m[2][1] * s; m[2][2] = a.m[2][2] * s; } inline_ void Add(const Matrix3x3& a, const Matrix3x3& b) { m[0][0] = a.m[0][0] + b.m[0][0]; m[0][1] = a.m[0][1] + b.m[0][1]; m[0][2] = a.m[0][2] + b.m[0][2]; m[1][0] = a.m[1][0] + b.m[1][0]; m[1][1] = a.m[1][1] + b.m[1][1]; m[1][2] = a.m[1][2] + b.m[1][2]; m[2][0] = a.m[2][0] + b.m[2][0]; m[2][1] = a.m[2][1] + b.m[2][1]; m[2][2] = a.m[2][2] + b.m[2][2]; } inline_ void Sub(const Matrix3x3& a, const Matrix3x3& b) { m[0][0] = a.m[0][0] - b.m[0][0]; m[0][1] = a.m[0][1] - b.m[0][1]; m[0][2] = a.m[0][2] - b.m[0][2]; m[1][0] = a.m[1][0] - b.m[1][0]; m[1][1] = a.m[1][1] - b.m[1][1]; m[1][2] = a.m[1][2] - b.m[1][2]; m[2][0] = a.m[2][0] - b.m[2][0]; m[2][1] = a.m[2][1] - b.m[2][1]; m[2][2] = a.m[2][2] - b.m[2][2]; } //! this = a * b inline_ void Mult(const Matrix3x3& a, const Matrix3x3& b) { m[0][0] = a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[1][0] + a.m[0][2] * b.m[2][0]; m[0][1] = a.m[0][0] * b.m[0][1] + a.m[0][1] * b.m[1][1] + a.m[0][2] * b.m[2][1]; m[0][2] = a.m[0][0] * b.m[0][2] + a.m[0][1] * b.m[1][2] + a.m[0][2] * b.m[2][2]; m[1][0] = a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[1][0] + a.m[1][2] * b.m[2][0]; m[1][1] = a.m[1][0] * b.m[0][1] + a.m[1][1] * b.m[1][1] + a.m[1][2] * b.m[2][1]; m[1][2] = a.m[1][0] * b.m[0][2] + a.m[1][1] * b.m[1][2] + a.m[1][2] * b.m[2][2]; m[2][0] = a.m[2][0] * b.m[0][0] + a.m[2][1] * b.m[1][0] + a.m[2][2] * b.m[2][0]; m[2][1] = a.m[2][0] * b.m[0][1] + a.m[2][1] * b.m[1][1] + a.m[2][2] * b.m[2][1]; m[2][2] = a.m[2][0] * b.m[0][2] + a.m[2][1] * b.m[1][2] + a.m[2][2] * b.m[2][2]; } //! this = transpose(a) * b inline_ void MultAtB(const Matrix3x3& a, const Matrix3x3& b) { m[0][0] = a.m[0][0] * b.m[0][0] + a.m[1][0] * b.m[1][0] + a.m[2][0] * b.m[2][0]; m[0][1] = a.m[0][0] * b.m[0][1] + a.m[1][0] * b.m[1][1] + a.m[2][0] * b.m[2][1]; m[0][2] = a.m[0][0] * b.m[0][2] + a.m[1][0] * b.m[1][2] + a.m[2][0] * b.m[2][2]; m[1][0] = a.m[0][1] * b.m[0][0] + a.m[1][1] * b.m[1][0] + a.m[2][1] * b.m[2][0]; m[1][1] = a.m[0][1] * b.m[0][1] + a.m[1][1] * b.m[1][1] + a.m[2][1] * b.m[2][1]; m[1][2] = a.m[0][1] * b.m[0][2] + a.m[1][1] * b.m[1][2] + a.m[2][1] * b.m[2][2]; m[2][0] = a.m[0][2] * b.m[0][0] + a.m[1][2] * b.m[1][0] + a.m[2][2] * b.m[2][0]; m[2][1] = a.m[0][2] * b.m[0][1] + a.m[1][2] * b.m[1][1] + a.m[2][2] * b.m[2][1]; m[2][2] = a.m[0][2] * b.m[0][2] + a.m[1][2] * b.m[1][2] + a.m[2][2] * b.m[2][2]; } //! this = a * transpose(b) inline_ void MultABt(const Matrix3x3& a, const Matrix3x3& b) { m[0][0] = a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[0][1] + a.m[0][2] * b.m[0][2]; m[0][1] = a.m[0][0] * b.m[1][0] + a.m[0][1] * b.m[1][1] + a.m[0][2] * b.m[1][2]; m[0][2] = a.m[0][0] * b.m[2][0] + a.m[0][1] * b.m[2][1] + a.m[0][2] * b.m[2][2]; m[1][0] = a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[0][1] + a.m[1][2] * b.m[0][2]; m[1][1] = a.m[1][0] * b.m[1][0] + a.m[1][1] * b.m[1][1] + a.m[1][2] * b.m[1][2]; m[1][2] = a.m[1][0] * b.m[2][0] + a.m[1][1] * b.m[2][1] + a.m[1][2] * b.m[2][2]; m[2][0] = a.m[2][0] * b.m[0][0] + a.m[2][1] * b.m[0][1] + a.m[2][2] * b.m[0][2]; m[2][1] = a.m[2][0] * b.m[1][0] + a.m[2][1] * b.m[1][1] + a.m[2][2] * b.m[1][2]; m[2][2] = a.m[2][0] * b.m[2][0] + a.m[2][1] * b.m[2][1] + a.m[2][2] * b.m[2][2]; } //! Makes a rotation matrix mapping vector "from" to vector "to". Matrix3x3& FromTo(const Point& from, const Point& to); //! Set a rotation matrix around the X axis. //! 1 0 0 //! RX = 0 cx sx //! 0 -sx cx void RotX(float angle); //! Set a rotation matrix around the Y axis. //! cy 0 -sy //! RY = 0 1 0 //! sy 0 cy void RotY(float angle); //! Set a rotation matrix around the Z axis. //! cz sz 0 //! RZ = -sz cz 0 //! 0 0 1 void RotZ(float angle); //! cy sx.sy -sy.cx //! RY.RX 0 cx sx //! sy -sx.cy cx.cy void RotYX(float y, float x); //! Make a rotation matrix about an arbitrary axis Matrix3x3& Rot(float angle, const Point& axis); //! Transpose the matrix. void Transpose() { TSwap(m[1][0], m[0][1]); TSwap(m[2][0], m[0][2]); TSwap(m[2][1], m[1][2]); } //! this = Transpose(a) void Transpose(const Matrix3x3& a) { m[0][0] = a.m[0][0]; m[0][1] = a.m[1][0]; m[0][2] = a.m[2][0]; m[1][0] = a.m[0][1]; m[1][1] = a.m[1][1]; m[1][2] = a.m[2][1]; m[2][0] = a.m[0][2]; m[2][1] = a.m[1][2]; m[2][2] = a.m[2][2]; } //! Compute the determinant of the matrix. We use the rule of Sarrus. float Determinant() const { return (m[0][0]*m[1][1]*m[2][2] + m[0][1]*m[1][2]*m[2][0] + m[0][2]*m[1][0]*m[2][1]) - (m[2][0]*m[1][1]*m[0][2] + m[2][1]*m[1][2]*m[0][0] + m[2][2]*m[1][0]*m[0][1]); } /* //! Compute a cofactor. Used for matrix inversion. float CoFactor(ubyte row, ubyte column) const { static const sdword gIndex[3+2] = { 0, 1, 2, 0, 1 }; return (m[gIndex[row+1]][gIndex[column+1]]*m[gIndex[row+2]][gIndex[column+2]] - m[gIndex[row+2]][gIndex[column+1]]*m[gIndex[row+1]][gIndex[column+2]]); } */ //! Invert the matrix. Determinant must be different from zero, else matrix can't be inverted. Matrix3x3& Invert() { float Det = Determinant(); // Must be !=0 float OneOverDet = 1.0f / Det; Matrix3x3 Temp; Temp.m[0][0] = +(m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDet; Temp.m[1][0] = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDet; Temp.m[2][0] = +(m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDet; Temp.m[0][1] = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDet; Temp.m[1][1] = +(m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDet; Temp.m[2][1] = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDet; Temp.m[0][2] = +(m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDet; Temp.m[1][2] = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDet; Temp.m[2][2] = +(m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDet; *this = Temp; return *this; } Matrix3x3& Normalize(); //! this = exp(a) Matrix3x3& Exp(const Matrix3x3& a); void FromQuat(const Quat &q); void FromQuatL2(const Quat &q, float l2); // Arithmetic operators //! Operator for Matrix3x3 Plus = Matrix3x3 + Matrix3x3; inline_ Matrix3x3 operator+(const Matrix3x3& mat) const { return Matrix3x3( m[0][0] + mat.m[0][0], m[0][1] + mat.m[0][1], m[0][2] + mat.m[0][2], m[1][0] + mat.m[1][0], m[1][1] + mat.m[1][1], m[1][2] + mat.m[1][2], m[2][0] + mat.m[2][0], m[2][1] + mat.m[2][1], m[2][2] + mat.m[2][2]); } //! Operator for Matrix3x3 Minus = Matrix3x3 - Matrix3x3; inline_ Matrix3x3 operator-(const Matrix3x3& mat) const { return Matrix3x3( m[0][0] - mat.m[0][0], m[0][1] - mat.m[0][1], m[0][2] - mat.m[0][2], m[1][0] - mat.m[1][0], m[1][1] - mat.m[1][1], m[1][2] - mat.m[1][2], m[2][0] - mat.m[2][0], m[2][1] - mat.m[2][1], m[2][2] - mat.m[2][2]); } //! Operator for Matrix3x3 Mul = Matrix3x3 * Matrix3x3; inline_ Matrix3x3 operator*(const Matrix3x3& mat) const { return Matrix3x3( m[0][0]*mat.m[0][0] + m[0][1]*mat.m[1][0] + m[0][2]*mat.m[2][0], m[0][0]*mat.m[0][1] + m[0][1]*mat.m[1][1] + m[0][2]*mat.m[2][1], m[0][0]*mat.m[0][2] + m[0][1]*mat.m[1][2] + m[0][2]*mat.m[2][2], m[1][0]*mat.m[0][0] + m[1][1]*mat.m[1][0] + m[1][2]*mat.m[2][0], m[1][0]*mat.m[0][1] + m[1][1]*mat.m[1][1] + m[1][2]*mat.m[2][1], m[1][0]*mat.m[0][2] + m[1][1]*mat.m[1][2] + m[1][2]*mat.m[2][2], m[2][0]*mat.m[0][0] + m[2][1]*mat.m[1][0] + m[2][2]*mat.m[2][0], m[2][0]*mat.m[0][1] + m[2][1]*mat.m[1][1] + m[2][2]*mat.m[2][1], m[2][0]*mat.m[0][2] + m[2][1]*mat.m[1][2] + m[2][2]*mat.m[2][2]); } //! Operator for Point Mul = Matrix3x3 * Point; inline_ Point operator*(const Point& v) const { return Point(GetRow(0)|v, GetRow(1)|v, GetRow(2)|v); } //! Operator for Matrix3x3 Mul = Matrix3x3 * float; inline_ Matrix3x3 operator*(float s) const { return Matrix3x3( m[0][0]*s, m[0][1]*s, m[0][2]*s, m[1][0]*s, m[1][1]*s, m[1][2]*s, m[2][0]*s, m[2][1]*s, m[2][2]*s); } //! Operator for Matrix3x3 Mul = float * Matrix3x3; inline_ friend Matrix3x3 operator*(float s, const Matrix3x3& mat) { return Matrix3x3( s*mat.m[0][0], s*mat.m[0][1], s*mat.m[0][2], s*mat.m[1][0], s*mat.m[1][1], s*mat.m[1][2], s*mat.m[2][0], s*mat.m[2][1], s*mat.m[2][2]); } //! Operator for Matrix3x3 Div = Matrix3x3 / float; inline_ Matrix3x3 operator/(float s) const { if (s) s = 1.0f / s; return Matrix3x3( m[0][0]*s, m[0][1]*s, m[0][2]*s, m[1][0]*s, m[1][1]*s, m[1][2]*s, m[2][0]*s, m[2][1]*s, m[2][2]*s); } //! Operator for Matrix3x3 Div = float / Matrix3x3; inline_ friend Matrix3x3 operator/(float s, const Matrix3x3& mat) { return Matrix3x3( s/mat.m[0][0], s/mat.m[0][1], s/mat.m[0][2], s/mat.m[1][0], s/mat.m[1][1], s/mat.m[1][2], s/mat.m[2][0], s/mat.m[2][1], s/mat.m[2][2]); } //! Operator for Matrix3x3 += Matrix3x3 inline_ Matrix3x3& operator+=(const Matrix3x3& mat) { m[0][0] += mat.m[0][0]; m[0][1] += mat.m[0][1]; m[0][2] += mat.m[0][2]; m[1][0] += mat.m[1][0]; m[1][1] += mat.m[1][1]; m[1][2] += mat.m[1][2]; m[2][0] += mat.m[2][0]; m[2][1] += mat.m[2][1]; m[2][2] += mat.m[2][2]; return *this; } //! Operator for Matrix3x3 -= Matrix3x3 inline_ Matrix3x3& operator-=(const Matrix3x3& mat) { m[0][0] -= mat.m[0][0]; m[0][1] -= mat.m[0][1]; m[0][2] -= mat.m[0][2]; m[1][0] -= mat.m[1][0]; m[1][1] -= mat.m[1][1]; m[1][2] -= mat.m[1][2]; m[2][0] -= mat.m[2][0]; m[2][1] -= mat.m[2][1]; m[2][2] -= mat.m[2][2]; return *this; } //! Operator for Matrix3x3 *= Matrix3x3 inline_ Matrix3x3& operator*=(const Matrix3x3& mat) { Point TempRow; GetRow(0, TempRow); m[0][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0]; m[0][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1]; m[0][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2]; GetRow(1, TempRow); m[1][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0]; m[1][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1]; m[1][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2]; GetRow(2, TempRow); m[2][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0]; m[2][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1]; m[2][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2]; return *this; } //! Operator for Matrix3x3 *= float inline_ Matrix3x3& operator*=(float s) { m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; return *this; } //! Operator for Matrix3x3 /= float inline_ Matrix3x3& operator/=(float s) { if (s) s = 1.0f / s; m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; return *this; } // Cast operators //! Cast a Matrix3x3 to a Matrix4x4. operator Matrix4x4() const; //! Cast a Matrix3x3 to a Quat. operator Quat() const; inline_ const Point& operator[](int row) const { return *(const Point*)&m[row][0]; } inline_ Point& operator[](int row) { return *(Point*)&m[row][0]; } public: float m[3][3]; }; #endif // __ICEMATRIX3X3_H__ ode-0.14/OPCODE/Ice/IceMatrix4x4.cpp0000644000000000000000000001407112635011627015313 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for 4x4 matrices. * \file IceMatrix4x4.cpp * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * 4x4 matrix. * DirectX-compliant, ie row-column order, ie m[Row][Col]. * Same as: * m11 m12 m13 m14 first row. * m21 m22 m23 m24 second row. * m31 m32 m33 m34 third row. * m41 m42 m43 m44 fourth row. * Translation is (m41, m42, m43), (m14, m24, m34, m44) = (0, 0, 0, 1). * Stored in memory as m11 m12 m13 m14 m21... * * Multiplication rules: * * [x'y'z'1] = [xyz1][M] * * x' = x*m11 + y*m21 + z*m31 + m41 * y' = x*m12 + y*m22 + z*m32 + m42 * z' = x*m13 + y*m23 + z*m33 + m43 * 1' = 0 + 0 + 0 + m44 * * \class Matrix4x4 * \author Pierre Terdiman * \version 1.0 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Inverts a PR matrix. (which only contains a rotation and a translation) * This is faster and less subject to FPU errors than the generic inversion code. * * \relates Matrix4x4 * \fn InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src) * \param dest [out] destination matrix * \param src [in] source matrix */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ICEMATHS_API void IceMaths::InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src) { dest.m[0][0] = src.m[0][0]; dest.m[1][0] = src.m[0][1]; dest.m[2][0] = src.m[0][2]; dest.m[3][0] = -(src.m[3][0]*src.m[0][0] + src.m[3][1]*src.m[0][1] + src.m[3][2]*src.m[0][2]); dest.m[0][1] = src.m[1][0]; dest.m[1][1] = src.m[1][1]; dest.m[2][1] = src.m[1][2]; dest.m[3][1] = -(src.m[3][0]*src.m[1][0] + src.m[3][1]*src.m[1][1] + src.m[3][2]*src.m[1][2]); dest.m[0][2] = src.m[2][0]; dest.m[1][2] = src.m[2][1]; dest.m[2][2] = src.m[2][2]; dest.m[3][2] = -(src.m[3][0]*src.m[2][0] + src.m[3][1]*src.m[2][1] + src.m[3][2]*src.m[2][2]); dest.m[0][3] = 0.0f; dest.m[1][3] = 0.0f; dest.m[2][3] = 0.0f; dest.m[3][3] = 1.0f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Compute the cofactor of the Matrix at a specified location /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Matrix4x4::CoFactor(udword row, udword col) const { return (( m[(row+1)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+3)&3][(col+3)&3] + m[(row+1)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+3)&3][(col+1)&3] + m[(row+1)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+3)&3][(col+2)&3]) - (m[(row+3)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+1)&3][(col+3)&3] + m[(row+3)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+1)&3][(col+1)&3] + m[(row+3)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+1)&3][(col+2)&3])) * ((row + col) & 1 ? -1.0f : +1.0f); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Compute the determinant of the Matrix /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Matrix4x4::Determinant() const { return m[0][0] * CoFactor(0, 0) + m[0][1] * CoFactor(0, 1) + m[0][2] * CoFactor(0, 2) + m[0][3] * CoFactor(0, 3); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Compute the inverse of the matrix /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Matrix4x4& Matrix4x4::Invert() { float Det = Determinant(); Matrix4x4 Temp; if(fabsf(Det) < MATRIX4X4_EPSILON) return *this; // The matrix is not invertible! Singular case! float IDet = 1.0f / Det; Temp.m[0][0] = CoFactor(0,0) * IDet; Temp.m[1][0] = CoFactor(0,1) * IDet; Temp.m[2][0] = CoFactor(0,2) * IDet; Temp.m[3][0] = CoFactor(0,3) * IDet; Temp.m[0][1] = CoFactor(1,0) * IDet; Temp.m[1][1] = CoFactor(1,1) * IDet; Temp.m[2][1] = CoFactor(1,2) * IDet; Temp.m[3][1] = CoFactor(1,3) * IDet; Temp.m[0][2] = CoFactor(2,0) * IDet; Temp.m[1][2] = CoFactor(2,1) * IDet; Temp.m[2][2] = CoFactor(2,2) * IDet; Temp.m[3][2] = CoFactor(2,3) * IDet; Temp.m[0][3] = CoFactor(3,0) * IDet; Temp.m[1][3] = CoFactor(3,1) * IDet; Temp.m[2][3] = CoFactor(3,2) * IDet; Temp.m[3][3] = CoFactor(3,3) * IDet; *this = Temp; return *this; } ode-0.14/OPCODE/Ice/IceMatrix4x4.h0000644000000000000000000005036712635011627014770 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for 4x4 matrices. * \file IceMatrix4x4.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEMATRIX4X4_H__ #define __ICEMATRIX4X4_H__ // Forward declarations class PRS; class PR; #define MATRIX4X4_EPSILON (1.0e-7f) class ICEMATHS_API Matrix4x4 { // void LUBackwardSubstitution( sdword *indx, float* b ); // void LUDecomposition( sdword* indx, float* d ); public: //! Empty constructor. inline_ Matrix4x4() {} //! Constructor from 16 values inline_ Matrix4x4( float m00, float m01, float m02, float m03, float m10, float m11, float m12, float m13, float m20, float m21, float m22, float m23, float m30, float m31, float m32, float m33) { m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03; m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13; m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23; m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33; } //! Copy constructor inline_ Matrix4x4(const Matrix4x4& mat) { CopyMemory(m, &mat.m, 16*sizeof(float)); } //! Destructor. inline_ ~Matrix4x4() {} //! Assign values (rotation only) inline_ Matrix4x4& Set( float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; return *this; } //! Assign values inline_ Matrix4x4& Set( float m00, float m01, float m02, float m03, float m10, float m11, float m12, float m13, float m20, float m21, float m22, float m23, float m30, float m31, float m32, float m33) { m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03; m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13; m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23; m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33; return *this; } //! Copy from a Matrix4x4 inline_ void Copy(const Matrix4x4& source) { CopyMemory(m, source.m, 16*sizeof(float)); } // Row-column access //! Returns a row. inline_ void GetRow(const udword r, HPoint& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; p.w=m[r][3]; } //! Returns a row. inline_ void GetRow(const udword r, Point& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; } //! Returns a row. inline_ const HPoint& GetRow(const udword r) const { return *(const HPoint*)&m[r][0]; } //! Returns a row. inline_ HPoint& GetRow(const udword r) { return *(HPoint*)&m[r][0]; } //! Sets a row. inline_ void SetRow(const udword r, const HPoint& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]=p.w; } //! Sets a row. inline_ void SetRow(const udword r, const Point& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]= (r!=3) ? 0.0f : 1.0f; } //! Returns a column. inline_ void GetCol(const udword c, HPoint& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; p.w=m[3][c]; } //! Returns a column. inline_ void GetCol(const udword c, Point& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; } //! Sets a column. inline_ void SetCol(const udword c, const HPoint& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]=p.w; } //! Sets a column. inline_ void SetCol(const udword c, const Point& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]= (c!=3) ? 0.0f : 1.0f; } // Translation //! Returns the translation part of the matrix. inline_ const HPoint& GetTrans() const { return GetRow(3); } //! Gets the translation part of the matrix inline_ void GetTrans(Point& p) const { p.x=m[3][0]; p.y=m[3][1]; p.z=m[3][2]; } //! Sets the translation part of the matrix, from a Point. inline_ void SetTrans(const Point& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; } //! Sets the translation part of the matrix, from a HPoint. inline_ void SetTrans(const HPoint& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; m[3][3]=p.w; } //! Sets the translation part of the matrix, from floats. inline_ void SetTrans(float tx, float ty, float tz) { m[3][0]=tx; m[3][1]=ty; m[3][2]=tz; } // Scale //! Sets the scale from a Point. The point is put on the diagonal. inline_ void SetScale(const Point& p) { m[0][0]=p.x; m[1][1]=p.y; m[2][2]=p.z; } //! Sets the scale from floats. Values are put on the diagonal. inline_ void SetScale(float sx, float sy, float sz) { m[0][0]=sx; m[1][1]=sy; m[2][2]=sz; } //! Scales from a Point. Each row is multiplied by a component. void Scale(const Point& p) { m[0][0] *= p.x; m[1][0] *= p.y; m[2][0] *= p.z; m[0][1] *= p.x; m[1][1] *= p.y; m[2][1] *= p.z; m[0][2] *= p.x; m[1][2] *= p.y; m[2][2] *= p.z; } //! Scales from floats. Each row is multiplied by a value. void Scale(float sx, float sy, float sz) { m[0][0] *= sx; m[1][0] *= sy; m[2][0] *= sz; m[0][1] *= sx; m[1][1] *= sy; m[2][1] *= sz; m[0][2] *= sx; m[1][2] *= sy; m[2][2] *= sz; } /* //! Returns a row. inline_ HPoint GetRow(const udword row) const { return mRow[row]; } //! Sets a row. inline_ Matrix4x4& SetRow(const udword row, const HPoint& p) { mRow[row] = p; return *this; } //! Sets a row. Matrix4x4& SetRow(const udword row, const Point& p) { m[row][0] = p.x; m[row][1] = p.y; m[row][2] = p.z; m[row][3] = (row != 3) ? 0.0f : 1.0f; return *this; } //! Returns a column. HPoint GetCol(const udword col) const { HPoint Res; Res.x = m[0][col]; Res.y = m[1][col]; Res.z = m[2][col]; Res.w = m[3][col]; return Res; } //! Sets a column. Matrix4x4& SetCol(const udword col, const HPoint& p) { m[0][col] = p.x; m[1][col] = p.y; m[2][col] = p.z; m[3][col] = p.w; return *this; } //! Sets a column. Matrix4x4& SetCol(const udword col, const Point& p) { m[0][col] = p.x; m[1][col] = p.y; m[2][col] = p.z; m[3][col] = (col != 3) ? 0.0f : 1.0f; return *this; } */ //! Computes the trace. The trace is the sum of the 4 diagonal components. inline_ float Trace() const { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; } //! Computes the trace of the upper 3x3 matrix. inline_ float Trace3x3() const { return m[0][0] + m[1][1] + m[2][2]; } //! Clears the matrix. inline_ void Zero() { ZeroMemory(&m, sizeof(m)); } //! Sets the identity matrix. inline_ void Identity() { Zero(); m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; } //! Checks for identity inline_ bool IsIdentity() const { if(IR(m[0][0])!=IEEE_1_0) return false; if(IR(m[0][1])!=0) return false; if(IR(m[0][2])!=0) return false; if(IR(m[0][3])!=0) return false; if(IR(m[1][0])!=0) return false; if(IR(m[1][1])!=IEEE_1_0) return false; if(IR(m[1][2])!=0) return false; if(IR(m[1][3])!=0) return false; if(IR(m[2][0])!=0) return false; if(IR(m[2][1])!=0) return false; if(IR(m[2][2])!=IEEE_1_0) return false; if(IR(m[2][3])!=0) return false; if(IR(m[3][0])!=0) return false; if(IR(m[3][1])!=0) return false; if(IR(m[3][2])!=0) return false; if(IR(m[3][3])!=IEEE_1_0) return false; return true; } //! Checks matrix validity inline_ BOOL IsValid() const { for(udword j=0;j<4;j++) { for(udword i=0;i<4;i++) { if(!IsValidFloat(m[j][i])) return FALSE; } } return TRUE; } //! Sets a rotation matrix around the X axis. void RotX(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[1][1] = m[2][2] = Cos; m[2][1] = -Sin; m[1][2] = Sin; } //! Sets a rotation matrix around the Y axis. void RotY(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[2][2] = Cos; m[2][0] = Sin; m[0][2] = -Sin; } //! Sets a rotation matrix around the Z axis. void RotZ(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[1][1] = Cos; m[1][0] = -Sin; m[0][1] = Sin; } //! Makes a rotation matrix about an arbitrary axis Matrix4x4& Rot(float angle, Point& p1, Point& p2); //! Transposes the matrix. void Transpose() { TSwap(m[1][0], m[0][1]); TSwap(m[2][0], m[0][2]); TSwap(m[3][0], m[0][3]); TSwap(m[1][2], m[2][1]); TSwap(m[1][3], m[3][1]); TSwap(m[2][3], m[3][2]); } //! Computes a cofactor. Used for matrix inversion. float CoFactor(udword row, udword col) const; //! Computes the determinant of the matrix. float Determinant() const; //! Inverts the matrix. Determinant must be different from zero, else matrix can't be inverted. Matrix4x4& Invert(); // Matrix& ComputeAxisMatrix(Point& axis, float angle); // Cast operators //! Casts a Matrix4x4 to a Matrix3x3. inline_ operator Matrix3x3() const { return Matrix3x3( m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2]); } //! Casts a Matrix4x4 to a Quat. operator Quat() const; //! Casts a Matrix4x4 to a PR. operator PR() const; // Arithmetic operators //! Operator for Matrix4x4 Plus = Matrix4x4 + Matrix4x4; inline_ Matrix4x4 operator+(const Matrix4x4& mat) const { return Matrix4x4( m[0][0]+mat.m[0][0], m[0][1]+mat.m[0][1], m[0][2]+mat.m[0][2], m[0][3]+mat.m[0][3], m[1][0]+mat.m[1][0], m[1][1]+mat.m[1][1], m[1][2]+mat.m[1][2], m[1][3]+mat.m[1][3], m[2][0]+mat.m[2][0], m[2][1]+mat.m[2][1], m[2][2]+mat.m[2][2], m[2][3]+mat.m[2][3], m[3][0]+mat.m[3][0], m[3][1]+mat.m[3][1], m[3][2]+mat.m[3][2], m[3][3]+mat.m[3][3]); } //! Operator for Matrix4x4 Minus = Matrix4x4 - Matrix4x4; inline_ Matrix4x4 operator-(const Matrix4x4& mat) const { return Matrix4x4( m[0][0]-mat.m[0][0], m[0][1]-mat.m[0][1], m[0][2]-mat.m[0][2], m[0][3]-mat.m[0][3], m[1][0]-mat.m[1][0], m[1][1]-mat.m[1][1], m[1][2]-mat.m[1][2], m[1][3]-mat.m[1][3], m[2][0]-mat.m[2][0], m[2][1]-mat.m[2][1], m[2][2]-mat.m[2][2], m[2][3]-mat.m[2][3], m[3][0]-mat.m[3][0], m[3][1]-mat.m[3][1], m[3][2]-mat.m[3][2], m[3][3]-mat.m[3][3]); } //! Operator for Matrix4x4 Mul = Matrix4x4 * Matrix4x4; inline_ Matrix4x4 operator*(const Matrix4x4& mat) const { return Matrix4x4( m[0][0]*mat.m[0][0] + m[0][1]*mat.m[1][0] + m[0][2]*mat.m[2][0] + m[0][3]*mat.m[3][0], m[0][0]*mat.m[0][1] + m[0][1]*mat.m[1][1] + m[0][2]*mat.m[2][1] + m[0][3]*mat.m[3][1], m[0][0]*mat.m[0][2] + m[0][1]*mat.m[1][2] + m[0][2]*mat.m[2][2] + m[0][3]*mat.m[3][2], m[0][0]*mat.m[0][3] + m[0][1]*mat.m[1][3] + m[0][2]*mat.m[2][3] + m[0][3]*mat.m[3][3], m[1][0]*mat.m[0][0] + m[1][1]*mat.m[1][0] + m[1][2]*mat.m[2][0] + m[1][3]*mat.m[3][0], m[1][0]*mat.m[0][1] + m[1][1]*mat.m[1][1] + m[1][2]*mat.m[2][1] + m[1][3]*mat.m[3][1], m[1][0]*mat.m[0][2] + m[1][1]*mat.m[1][2] + m[1][2]*mat.m[2][2] + m[1][3]*mat.m[3][2], m[1][0]*mat.m[0][3] + m[1][1]*mat.m[1][3] + m[1][2]*mat.m[2][3] + m[1][3]*mat.m[3][3], m[2][0]*mat.m[0][0] + m[2][1]*mat.m[1][0] + m[2][2]*mat.m[2][0] + m[2][3]*mat.m[3][0], m[2][0]*mat.m[0][1] + m[2][1]*mat.m[1][1] + m[2][2]*mat.m[2][1] + m[2][3]*mat.m[3][1], m[2][0]*mat.m[0][2] + m[2][1]*mat.m[1][2] + m[2][2]*mat.m[2][2] + m[2][3]*mat.m[3][2], m[2][0]*mat.m[0][3] + m[2][1]*mat.m[1][3] + m[2][2]*mat.m[2][3] + m[2][3]*mat.m[3][3], m[3][0]*mat.m[0][0] + m[3][1]*mat.m[1][0] + m[3][2]*mat.m[2][0] + m[3][3]*mat.m[3][0], m[3][0]*mat.m[0][1] + m[3][1]*mat.m[1][1] + m[3][2]*mat.m[2][1] + m[3][3]*mat.m[3][1], m[3][0]*mat.m[0][2] + m[3][1]*mat.m[1][2] + m[3][2]*mat.m[2][2] + m[3][3]*mat.m[3][2], m[3][0]*mat.m[0][3] + m[3][1]*mat.m[1][3] + m[3][2]*mat.m[2][3] + m[3][3]*mat.m[3][3]); } //! Operator for HPoint Mul = Matrix4x4 * HPoint; inline_ HPoint operator*(const HPoint& v) const { return HPoint(GetRow(0)|v, GetRow(1)|v, GetRow(2)|v, GetRow(3)|v); } //! Operator for Point Mul = Matrix4x4 * Point; inline_ Point operator*(const Point& v) const { return Point( m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3], m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3], m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3] ); } //! Operator for Matrix4x4 Scale = Matrix4x4 * float; inline_ Matrix4x4 operator*(float s) const { return Matrix4x4( m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s, m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s, m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s, m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s); } //! Operator for Matrix4x4 Scale = float * Matrix4x4; inline_ friend Matrix4x4 operator*(float s, const Matrix4x4& mat) { return Matrix4x4( s*mat.m[0][0], s*mat.m[0][1], s*mat.m[0][2], s*mat.m[0][3], s*mat.m[1][0], s*mat.m[1][1], s*mat.m[1][2], s*mat.m[1][3], s*mat.m[2][0], s*mat.m[2][1], s*mat.m[2][2], s*mat.m[2][3], s*mat.m[3][0], s*mat.m[3][1], s*mat.m[3][2], s*mat.m[3][3]); } //! Operator for Matrix4x4 Div = Matrix4x4 / float; inline_ Matrix4x4 operator/(float s) const { if(s) s = 1.0f / s; return Matrix4x4( m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s, m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s, m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s, m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s); } //! Operator for Matrix4x4 Div = float / Matrix4x4; inline_ friend Matrix4x4 operator/(float s, const Matrix4x4& mat) { return Matrix4x4( s/mat.m[0][0], s/mat.m[0][1], s/mat.m[0][2], s/mat.m[0][3], s/mat.m[1][0], s/mat.m[1][1], s/mat.m[1][2], s/mat.m[1][3], s/mat.m[2][0], s/mat.m[2][1], s/mat.m[2][2], s/mat.m[2][3], s/mat.m[3][0], s/mat.m[3][1], s/mat.m[3][2], s/mat.m[3][3]); } //! Operator for Matrix4x4 += Matrix4x4; inline_ Matrix4x4& operator+=(const Matrix4x4& mat) { m[0][0]+=mat.m[0][0]; m[0][1]+=mat.m[0][1]; m[0][2]+=mat.m[0][2]; m[0][3]+=mat.m[0][3]; m[1][0]+=mat.m[1][0]; m[1][1]+=mat.m[1][1]; m[1][2]+=mat.m[1][2]; m[1][3]+=mat.m[1][3]; m[2][0]+=mat.m[2][0]; m[2][1]+=mat.m[2][1]; m[2][2]+=mat.m[2][2]; m[2][3]+=mat.m[2][3]; m[3][0]+=mat.m[3][0]; m[3][1]+=mat.m[3][1]; m[3][2]+=mat.m[3][2]; m[3][3]+=mat.m[3][3]; return *this; } //! Operator for Matrix4x4 -= Matrix4x4; inline_ Matrix4x4& operator-=(const Matrix4x4& mat) { m[0][0]-=mat.m[0][0]; m[0][1]-=mat.m[0][1]; m[0][2]-=mat.m[0][2]; m[0][3]-=mat.m[0][3]; m[1][0]-=mat.m[1][0]; m[1][1]-=mat.m[1][1]; m[1][2]-=mat.m[1][2]; m[1][3]-=mat.m[1][3]; m[2][0]-=mat.m[2][0]; m[2][1]-=mat.m[2][1]; m[2][2]-=mat.m[2][2]; m[2][3]-=mat.m[2][3]; m[3][0]-=mat.m[3][0]; m[3][1]-=mat.m[3][1]; m[3][2]-=mat.m[3][2]; m[3][3]-=mat.m[3][3]; return *this; } //! Operator for Matrix4x4 *= Matrix4x4; Matrix4x4& operator*=(const Matrix4x4& mat) { HPoint TempRow; GetRow(0, TempRow); m[0][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; m[0][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; m[0][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; m[0][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; GetRow(1, TempRow); m[1][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; m[1][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; m[1][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; m[1][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; GetRow(2, TempRow); m[2][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; m[2][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; m[2][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; m[2][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; GetRow(3, TempRow); m[3][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; m[3][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; m[3][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; m[3][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; return *this; } //! Operator for Matrix4x4 *= float; inline_ Matrix4x4& operator*=(float s) { m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s; m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s; m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s; m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s; return *this; } //! Operator for Matrix4x4 /= float; inline_ Matrix4x4& operator/=(float s) { if(s) s = 1.0f / s; m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s; m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s; m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s; m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s; return *this; } inline_ const HPoint& operator[](int row) const { return *(const HPoint*)&m[row][0]; } inline_ HPoint& operator[](int row) { return *(HPoint*)&m[row][0]; } public: float m[4][4]; }; //! Quickly rotates & translates a vector, using the 4x3 part of a 4x4 matrix inline_ void TransformPoint4x3(Point& dest, const Point& source, const Matrix4x4& rot) { dest.x = rot.m[3][0] + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0]; dest.y = rot.m[3][1] + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1]; dest.z = rot.m[3][2] + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2]; } //! Quickly rotates a vector, using the 3x3 part of a 4x4 matrix inline_ void TransformPoint3x3(Point& dest, const Point& source, const Matrix4x4& rot) { dest.x = source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0]; dest.y = source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1]; dest.z = source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2]; } ICEMATHS_API void InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src); #endif // __ICEMATRIX4X4_H__ ode-0.14/OPCODE/Ice/IceMemoryMacros.h0000644000000000000000000000674712635011627015604 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains all memory macros. * \file IceMemoryMacros.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEMEMORYMACROS_H__ #define __ICEMEMORYMACROS_H__ #undef ZeroMemory #undef CopyMemory #undef MoveMemory #undef FillMemory //! Clears a buffer. //! \param addr [in] buffer address //! \param size [in] buffer length //! \see FillMemory //! \see StoreDwords //! \see CopyMemory //! \see MoveMemory inline_ void ZeroMemory(void* addr, udword size) { memset(addr, 0, size); } //! Fills a buffer with a given byte. //! \param addr [in] buffer address //! \param size [in] buffer length //! \param val [in] the byte value //! \see StoreDwords //! \see ZeroMemory //! \see CopyMemory //! \see MoveMemory inline_ void FillMemory(void* dest, udword size, ubyte val) { memset(dest, val, size); } //! Fills a buffer with a given dword. //! \param addr [in] buffer address //! \param nb [in] number of dwords to write //! \param value [in] the dword value //! \see FillMemory //! \see ZeroMemory //! \see CopyMemory //! \see MoveMemory //! \warning writes nb*4 bytes ! inline_ void StoreDwords(udword* dest, udword nb, udword value) { while(nb--) *dest++ = value; } //! Copies a buffer. //! \param addr [in] destination buffer address //! \param addr [in] source buffer address //! \param size [in] buffer length //! \see ZeroMemory //! \see FillMemory //! \see StoreDwords //! \see MoveMemory inline_ void CopyMemory(void* dest, const void* src, udword size) { memcpy(dest, src, size); } //! Moves a buffer. //! \param addr [in] destination buffer address //! \param addr [in] source buffer address //! \param size [in] buffer length //! \see ZeroMemory //! \see FillMemory //! \see StoreDwords //! \see CopyMemory inline_ void MoveMemory(void* dest, const void* src, udword size) { memmove(dest, src, size); } #define SIZEOFOBJECT sizeof(*this) //!< Gives the size of current object. Avoid some mistakes (e.g. "sizeof(this)"). //#define CLEAROBJECT { memset(this, 0, SIZEOFOBJECT); } //!< Clears current object. Laziness is my business. HANDLE WITH CARE. #define DELETESINGLE(x) if (x) { delete x; x = null; } //!< Deletes an instance of a class. #define DELETEARRAY(x) if (x) { delete []x; x = null; } //!< Deletes an array. #define SAFE_RELEASE(x) if (x) { (x)->Release(); (x) = null; } //!< Safe D3D-style release #define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; } //!< Safe ICE-style release #ifdef __ICEERROR_H__ #define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY); //!< Standard alloc checking. HANDLE WITH CARE. #else #define CHECKALLOC(x) if(!x) return false; #endif //! Standard allocation cycle #define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr); #endif // __ICEMEMORYMACROS_H__ ode-0.14/OPCODE/Ice/IceOBB.cpp0000644000000000000000000003035712635011627014116 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains OBB-related code. * \file IceOBB.cpp * \author Pierre Terdiman * \date January, 29, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * An Oriented Bounding Box (OBB). * \class OBB * \author Pierre Terdiman * \version 1.0 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if a point is contained within the OBB. * \param p [in] the world point to test * \return true if inside the OBB */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool OBB::ContainsPoint(const Point& p) const { // Point in OBB test using lazy evaluation and early exits // Translate to box space Point RelPoint = p - mCenter; // Point * mRot maps from box space to world space // mRot * Point maps from world space to box space (what we need here) float f = mRot.m[0][0] * RelPoint.x + mRot.m[0][1] * RelPoint.y + mRot.m[0][2] * RelPoint.z; if(f >= mExtents.x || f <= -mExtents.x) return false; f = mRot.m[1][0] * RelPoint.x + mRot.m[1][1] * RelPoint.y + mRot.m[1][2] * RelPoint.z; if(f >= mExtents.y || f <= -mExtents.y) return false; f = mRot.m[2][0] * RelPoint.x + mRot.m[2][1] * RelPoint.y + mRot.m[2][2] * RelPoint.z; if(f >= mExtents.z || f <= -mExtents.z) return false; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds an OBB from an AABB and a world transform. * \param aabb [in] the aabb * \param mat [in] the world transform */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBB::Create(const AABB& aabb, const Matrix4x4& mat) { // Note: must be coherent with Rotate() aabb.GetCenter(mCenter); aabb.GetExtents(mExtents); // Here we have the same as OBB::Rotate(mat) where the obb is (mCenter, mExtents, Identity). // So following what's done in Rotate: // - x-form the center mCenter *= mat; // - combine rotation with identity, i.e. just use given matrix mRot = mat; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the obb planes. * \param planes [out] 6 box planes * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool OBB::ComputePlanes(Plane* planes) const { // Checkings if(!planes) return false; Point Axis0 = mRot[0]; Point Axis1 = mRot[1]; Point Axis2 = mRot[2]; // Writes normals planes[0].n = Axis0; planes[1].n = -Axis0; planes[2].n = Axis1; planes[3].n = -Axis1; planes[4].n = Axis2; planes[5].n = -Axis2; // Compute a point on each plane Point p0 = mCenter + Axis0 * mExtents.x; Point p1 = mCenter - Axis0 * mExtents.x; Point p2 = mCenter + Axis1 * mExtents.y; Point p3 = mCenter - Axis1 * mExtents.y; Point p4 = mCenter + Axis2 * mExtents.z; Point p5 = mCenter - Axis2 * mExtents.z; // Compute d planes[0].d = -(planes[0].n|p0); planes[1].d = -(planes[1].n|p1); planes[2].d = -(planes[2].n|p2); planes[3].d = -(planes[3].n|p3); planes[4].d = -(planes[4].n|p4); planes[5].d = -(planes[5].n|p5); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the obb points. * \param pts [out] 8 box points * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool OBB::ComputePoints(Point* pts) const { // Checkings if(!pts) return false; Point Axis0 = mRot[0]; Point Axis1 = mRot[1]; Point Axis2 = mRot[2]; Axis0 *= mExtents.x; Axis1 *= mExtents.y; Axis2 *= mExtents.z; // 7+------+6 0 = --- // /| /| 1 = +-- // / | / | 2 = ++- // / 4+---/--+5 3 = -+- // 3+------+2 / y z 4 = --+ // | / | / | / 5 = +-+ // |/ |/ |/ 6 = +++ // 0+------+1 *---x 7 = -++ pts[0] = mCenter - Axis0 - Axis1 - Axis2; pts[1] = mCenter + Axis0 - Axis1 - Axis2; pts[2] = mCenter + Axis0 + Axis1 - Axis2; pts[3] = mCenter - Axis0 + Axis1 - Axis2; pts[4] = mCenter - Axis0 - Axis1 + Axis2; pts[5] = mCenter + Axis0 - Axis1 + Axis2; pts[6] = mCenter + Axis0 + Axis1 + Axis2; pts[7] = mCenter - Axis0 + Axis1 + Axis2; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes vertex normals. * \param pts [out] 8 box points * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool OBB::ComputeVertexNormals(Point* pts) const { static const float VertexNormals[] = { -INVSQRT3, -INVSQRT3, -INVSQRT3, INVSQRT3, -INVSQRT3, -INVSQRT3, INVSQRT3, INVSQRT3, -INVSQRT3, -INVSQRT3, INVSQRT3, -INVSQRT3, -INVSQRT3, -INVSQRT3, INVSQRT3, INVSQRT3, -INVSQRT3, INVSQRT3, INVSQRT3, INVSQRT3, INVSQRT3, -INVSQRT3, INVSQRT3, INVSQRT3 }; if(!pts) return false; const Point* VN = (const Point*)VertexNormals; for(udword i=0;i<8;i++) { pts[i] = VN[i] * mRot; } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns edges. * \return 24 indices (12 edges) indexing the list returned by ComputePoints() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const udword* OBB::GetEdges() const { static const udword Indices[] = { 0, 1, 1, 2, 2, 3, 3, 0, 7, 6, 6, 5, 5, 4, 4, 7, 1, 5, 6, 2, 3, 7, 4, 0 }; return Indices; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns local edge normals. * \return edge normals in local space */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const Point* OBB::GetLocalEdgeNormals() const { static const float EdgeNormals[] = { 0, -INVSQRT2, -INVSQRT2, // 0-1 INVSQRT2, 0, -INVSQRT2, // 1-2 0, INVSQRT2, -INVSQRT2, // 2-3 -INVSQRT2, 0, -INVSQRT2, // 3-0 0, INVSQRT2, INVSQRT2, // 7-6 INVSQRT2, 0, INVSQRT2, // 6-5 0, -INVSQRT2, INVSQRT2, // 5-4 -INVSQRT2, 0, INVSQRT2, // 4-7 INVSQRT2, -INVSQRT2, 0, // 1-5 INVSQRT2, INVSQRT2, 0, // 6-2 -INVSQRT2, INVSQRT2, 0, // 3-7 -INVSQRT2, -INVSQRT2, 0 // 4-0 }; return (const Point*)EdgeNormals; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns world edge normal * \param edge_index [in] 0 <= edge index < 12 * \param world_normal [out] edge normal in world space */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBB::ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const { ASSERT(edge_index<12); world_normal = GetLocalEdgeNormals()[edge_index] * mRot; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes an LSS surrounding the OBB. * \param lss [out] the LSS */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBB::ComputeLSS(LSS& lss) const { Point Axis0 = mRot[0]; Point Axis1 = mRot[1]; Point Axis2 = mRot[2]; switch(mExtents.LargestAxis()) { case 0: lss.mRadius = (mExtents.y + mExtents.z)*0.5f; lss.mP0 = mCenter + Axis0 * (mExtents.x - lss.mRadius); lss.mP1 = mCenter - Axis0 * (mExtents.x - lss.mRadius); break; case 1: lss.mRadius = (mExtents.x + mExtents.z)*0.5f; lss.mP0 = mCenter + Axis1 * (mExtents.y - lss.mRadius); lss.mP1 = mCenter - Axis1 * (mExtents.y - lss.mRadius); break; case 2: lss.mRadius = (mExtents.x + mExtents.y)*0.5f; lss.mP0 = mCenter + Axis2 * (mExtents.z - lss.mRadius); lss.mP1 = mCenter - Axis2 * (mExtents.z - lss.mRadius); break; default: {} } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the OBB is inside another OBB. * \param box [in] the other OBB * \return TRUE if we're inside the other box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL OBB::IsInside(const OBB& box) const { // Make a 4x4 from the box & inverse it Matrix4x4 M0Inv; { Matrix4x4 M0 = box.mRot; M0.SetTrans(box.mCenter); InvertPRMatrix(M0Inv, M0); } // With our inversed 4x4, create box1 in space of box0 OBB _1in0; Rotate(M0Inv, _1in0); // This should cancel out box0's rotation, i.e. it's now an AABB. // => Center(0,0,0), Rot(identity) // The two boxes are in the same space so now we can compare them. // Create the AABB of (box1 in space of box0) const Matrix3x3& mtx = _1in0.mRot; float f = fabsf(mtx.m[0][0] * mExtents.x) + fabsf(mtx.m[1][0] * mExtents.y) + fabsf(mtx.m[2][0] * mExtents.z) - box.mExtents.x; if(f > _1in0.mCenter.x) return FALSE; if(-f < _1in0.mCenter.x) return FALSE; f = fabsf(mtx.m[0][1] * mExtents.x) + fabsf(mtx.m[1][1] * mExtents.y) + fabsf(mtx.m[2][1] * mExtents.z) - box.mExtents.y; if(f > _1in0.mCenter.y) return FALSE; if(-f < _1in0.mCenter.y) return FALSE; f = fabsf(mtx.m[0][2] * mExtents.x) + fabsf(mtx.m[1][2] * mExtents.y) + fabsf(mtx.m[2][2] * mExtents.z) - box.mExtents.z; if(f > _1in0.mCenter.z) return FALSE; if(-f < _1in0.mCenter.z) return FALSE; return TRUE; } ode-0.14/OPCODE/Ice/IceOBB.h0000644000000000000000000002300012635011627013546 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains OBB-related code. (oriented bounding box) * \file IceOBB.h * \author Pierre Terdiman * \date January, 13, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEOBB_H__ #define __ICEOBB_H__ // Forward declarations class LSS; class ICEMATHS_API OBB { public: //! Constructor inline_ OBB() {} //! Constructor inline_ OBB(const Point& center, const Point& extents, const Matrix3x3& rot) : mCenter(center), mExtents(extents), mRot(rot) {} //! Destructor inline_ ~OBB() {} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an empty OBB. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SetEmpty() { mCenter.Zero(); mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); mRot.Identity(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Tests if a point is contained within the OBB. * \param p [in] the world point to test * \return true if inside the OBB */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ContainsPoint(const Point& p) const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds an OBB from an AABB and a world transform. * \param aabb [in] the aabb * \param mat [in] the world transform */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Create(const AABB& aabb, const Matrix4x4& mat); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recomputes the OBB after an arbitrary transform by a 4x4 matrix. * \param mtx [in] the transform matrix * \param obb [out] the transformed OBB */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void Rotate(const Matrix4x4& mtx, OBB& obb) const { // The extents remain constant obb.mExtents = mExtents; // The center gets x-formed obb.mCenter = mCenter * mtx; // Combine rotations obb.mRot = mRot * Matrix3x3(mtx); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the OBB is valid. * \return true if the box is valid */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL IsValid() const { // Consistency condition for (Center, Extents) boxes: Extents >= 0.0f if(mExtents.x < 0.0f) return FALSE; if(mExtents.y < 0.0f) return FALSE; if(mExtents.z < 0.0f) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the obb planes. * \param planes [out] 6 box planes * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ComputePlanes(Plane* planes) const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the obb points. * \param pts [out] 8 box points * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ComputePoints(Point* pts) const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes vertex normals. * \param pts [out] 8 box points * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool ComputeVertexNormals(Point* pts) const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns edges. * \return 24 indices (12 edges) indexing the list returned by ComputePoints() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const udword* GetEdges() const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns local edge normals. * \return edge normals in local space */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const Point* GetLocalEdgeNormals() const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns world edge normal * \param edge_index [in] 0 <= edge index < 12 * \param world_normal [out] edge normal in world space */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes an LSS surrounding the OBB. * \param lss [out] the LSS */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void ComputeLSS(LSS& lss) const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the OBB is inside another OBB. * \param box [in] the other OBB * \return TRUE if we're inside the other box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL IsInside(const OBB& box) const; inline_ const Point& GetCenter() const { return mCenter; } inline_ const Point& GetExtents() const { return mExtents; } inline_ const Matrix3x3& GetRot() const { return mRot; } inline_ void GetRotatedExtents(Matrix3x3& extents) const { extents = mRot; extents.Scale(mExtents); } Point mCenter; //!< B for Box Point mExtents; //!< B for Bounding Matrix3x3 mRot; //!< O for Oriented // Orientation is stored in row-major format, // i.e. rows = eigen vectors of the covariance matrix }; #endif // __ICEOBB_H__ ode-0.14/OPCODE/Ice/IcePairs.h0000644000000000000000000000337312635011627014235 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a simple pair class. * \file IcePairs.h * \author Pierre Terdiman * \date January, 13, 2003 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEPAIRS_H__ #define __ICEPAIRS_H__ //! A generic couple structure struct ICECORE_API Pair { inline_ Pair() {} inline_ Pair(udword i0, udword i1) : id0(i0), id1(i1) {} udword id0; //!< First index of the pair udword id1; //!< Second index of the pair }; class ICECORE_API Pairs : private Container { public: // Constructor / Destructor Pairs() {} ~Pairs() {} inline_ udword GetNbPairs() const { return GetNbEntries()>>1; } inline_ const Pair* GetPairs() const { return (const Pair*)GetEntries(); } inline_ const Pair* GetPair(udword i) const { return (const Pair*)&GetEntries()[i+i]; } inline_ BOOL HasPairs() const { return IsNotEmpty(); } inline_ void ResetPairs() { Reset(); } inline_ void DeleteLastPair() { DeleteLastEntry(); DeleteLastEntry(); } inline_ void AddPair(const Pair& p) { Add(p.id0).Add(p.id1); } inline_ void AddPair(udword id0, udword id1) { Add(id0).Add(id1); } }; #endif // __ICEPAIRS_H__ ode-0.14/OPCODE/Ice/IcePlane.cpp0000644000000000000000000000376412635011627014555 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for planes. * \file IcePlane.cpp * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Plane class. * \class Plane * \author Pierre Terdiman * \version 1.0 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the plane equation from 3 points. * \param p0 [in] first point * \param p1 [in] second point * \param p2 [in] third point * \return Self-reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Plane& Plane::Set(const Point& p0, const Point& p1, const Point& p2) { Point Edge0 = p1 - p0; Point Edge1 = p2 - p0; n = Edge0 ^ Edge1; n.Normalize(); d = -(p0 | n); return *this; } ode-0.14/OPCODE/Ice/IcePlane.h0000644000000000000000000001156612635011627014221 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for planes. * \file IcePlane.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEPLANE_H__ #define __ICEPLANE_H__ #define PLANE_EPSILON (1.0e-7f) class ICEMATHS_API Plane { public: //! Constructor inline_ Plane() { } //! Constructor from a normal and a distance inline_ Plane(float nx, float ny, float nz, float d) { Set(nx, ny, nz, d); } //! Constructor from a point on the plane and a normal inline_ Plane(const Point& p, const Point& n) { Set(p, n); } //! Constructor from three points inline_ Plane(const Point& p0, const Point& p1, const Point& p2) { Set(p0, p1, p2); } //! Constructor from a normal and a distance inline_ Plane(const Point& _n, float _d) { n = _n; d = _d; } //! Copy constructor inline_ Plane(const Plane& plane) : n(plane.n), d(plane.d) { } //! Destructor inline_ ~Plane() { } inline_ Plane& Zero() { n.Zero(); d = 0.0f; return *this; } inline_ Plane& Set(float nx, float ny, float nz, float _d) { n.Set(nx, ny, nz); d = _d; return *this; } inline_ Plane& Set(const Point& p, const Point& _n) { n = _n; d = - p | _n; return *this; } Plane& Set(const Point& p0, const Point& p1, const Point& p2); inline_ float Distance(const Point& p) const { return (p | n) + d; } inline_ bool Belongs(const Point& p) const { return fabsf(Distance(p)) < PLANE_EPSILON; } inline_ void Normalize() { float Denom = 1.0f / n.Magnitude(); n.x *= Denom; n.y *= Denom; n.z *= Denom; d *= Denom; } public: // Members Point n; //!< The normal to the plane float d; //!< The distance from the origin // Cast operators inline_ operator Point() const { return n; } inline_ operator HPoint() const { return HPoint(n, d); } // Arithmetic operators inline_ Plane operator*(const Matrix4x4& m) const { // Old code from Irion. Kept for reference. Plane Ret(*this); return Ret *= m; } inline_ Plane& operator*=(const Matrix4x4& m) { // Old code from Irion. Kept for reference. Point n2 = HPoint(n, 0.0f) * m; d = -((Point) (HPoint( -d*n, 1.0f ) * m) | n2); n = n2; return *this; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster. * \param transformed [out] transformed plane * \param plane [in] source plane * \param transform [in] transform matrix * \warning the plane normal must be unit-length */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void TransformPlane(Plane& transformed, const Plane& plane, const Matrix4x4& transform) { // Rotate the normal using the rotation part of the 4x4 matrix transformed.n = plane.n * Matrix3x3(transform); // Compute new d transformed.d = plane.d - (Point(transform.GetTrans())|transformed.n); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster. * \param plane [in/out] source plane (transformed on return) * \param transform [in] transform matrix * \warning the plane normal must be unit-length */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void TransformPlane(Plane& plane, const Matrix4x4& transform) { // Rotate the normal using the rotation part of the 4x4 matrix plane.n *= Matrix3x3(transform); // Compute new d plane.d -= Point(transform.GetTrans())|plane.n; } #endif // __ICEPLANE_H__ ode-0.14/OPCODE/Ice/IcePoint.cpp0000644000000000000000000001634212635011627014603 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for 3D vectors. * \file IcePoint.cpp * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * 3D point. * * The name is "Point" instead of "Vector" since a vector is N-dimensional, whereas a point is an implicit "vector of dimension 3". * So the choice was between "Point" and "Vector3", the first one looked better (IMHO). * * Some people, then, use a typedef to handle both points & vectors using the same class: typedef Point Vector3; * This is bad since it opens the door to a lot of confusion while reading the code. I know it may sounds weird but check this out: * * \code * Point P0,P1 = some 3D points; * Point Delta = P1 - P0; * \endcode * * This compiles fine, although you should have written: * * \code * Point P0,P1 = some 3D points; * Vector3 Delta = P1 - P0; * \endcode * * Subtle things like this are not caught at compile-time, and when you find one in the code, you never know whether it's a mistake * from the author or something you don't get. * * One way to handle it at compile-time would be to use different classes for Point & Vector3, only overloading operator "-" for vectors. * But then, you get a lot of redundant code in thoses classes, and basically it's really a lot of useless work. * * Another way would be to use homogeneous points: w=1 for points, w=0 for vectors. That's why the HPoint class exists. Now, to store * your model's vertices and in most cases, you really want to use Points to save ram. * * \class Point * \author Pierre Terdiman * \version 1.0 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Creates a positive unit random vector. * \return Self-reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Point& Point::PositiveUnitRandomVector() { x = UnitRandomFloat(); y = UnitRandomFloat(); z = UnitRandomFloat(); Normalize(); return *this; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Creates a unit random vector. * \return Self-reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Point& Point::UnitRandomVector() { x = UnitRandomFloat() - 0.5f; y = UnitRandomFloat() - 0.5f; z = UnitRandomFloat() - 0.5f; Normalize(); return *this; } // Cast operator // WARNING: not inlined Point::operator HPoint() const { return HPoint(x, y, z, 0.0f); } Point& Point::Refract(const Point& eye, const Point& n, float refractindex, Point& refracted) { // Point EyePt = eye position // Point p = current vertex // Point n = vertex normal // Point rv = refracted vector // Eye vector - doesn't need to be normalized Point Env; Env.x = eye.x - x; Env.y = eye.y - y; Env.z = eye.z - z; float NDotE = n|Env; float NDotN = n|n; NDotE /= refractindex; // Refracted vector refracted = n*NDotE - Env*NDotN; return *this; } Point& Point::ProjectToPlane(const Plane& p) { *this-= (p.d + (*this|p.n))*p.n; return *this; } void Point::ProjectToScreen(float halfrenderwidth, float halfrenderheight, const Matrix4x4& mat, HPoint& projected) const { projected = HPoint(x, y, z, 1.0f) * mat; projected.w = 1.0f / projected.w; projected.x*=projected.w; projected.y*=projected.w; projected.z*=projected.w; projected.x *= halfrenderwidth; projected.x += halfrenderwidth; projected.y *= -halfrenderheight; projected.y += halfrenderheight; } void Point::SetNotUsed() { // We use a particular integer pattern : 0xffffffff everywhere. This is a NAN. x = y = z = FR(0xffffffff); } BOOL Point::IsNotUsed() const { if(IR(x)!=0xffffffff) return FALSE; if(IR(y)!=0xffffffff) return FALSE; if(IR(z)!=0xffffffff) return FALSE; return TRUE; } Point& Point::Mult(const Matrix3x3& mat, const Point& a) { x = a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2]; y = a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2]; z = a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2]; return *this; } Point& Point::Mult2(const Matrix3x3& mat1, const Point& a1, const Matrix3x3& mat2, const Point& a2) { x = a1.x * mat1.m[0][0] + a1.y * mat1.m[0][1] + a1.z * mat1.m[0][2] + a2.x * mat2.m[0][0] + a2.y * mat2.m[0][1] + a2.z * mat2.m[0][2]; y = a1.x * mat1.m[1][0] + a1.y * mat1.m[1][1] + a1.z * mat1.m[1][2] + a2.x * mat2.m[1][0] + a2.y * mat2.m[1][1] + a2.z * mat2.m[1][2]; z = a1.x * mat1.m[2][0] + a1.y * mat1.m[2][1] + a1.z * mat1.m[2][2] + a2.x * mat2.m[2][0] + a2.y * mat2.m[2][1] + a2.z * mat2.m[2][2]; return *this; } Point& Point::Mac(const Matrix3x3& mat, const Point& a) { x += a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2]; y += a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2]; z += a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2]; return *this; } Point& Point::TransMult(const Matrix3x3& mat, const Point& a) { x = a.x * mat.m[0][0] + a.y * mat.m[1][0] + a.z * mat.m[2][0]; y = a.x * mat.m[0][1] + a.y * mat.m[1][1] + a.z * mat.m[2][1]; z = a.x * mat.m[0][2] + a.y * mat.m[1][2] + a.z * mat.m[2][2]; return *this; } Point& Point::Transform(const Point& r, const Matrix3x3& rotpos, const Point& linpos) { x = r.x * rotpos.m[0][0] + r.y * rotpos.m[0][1] + r.z * rotpos.m[0][2] + linpos.x; y = r.x * rotpos.m[1][0] + r.y * rotpos.m[1][1] + r.z * rotpos.m[1][2] + linpos.y; z = r.x * rotpos.m[2][0] + r.y * rotpos.m[2][1] + r.z * rotpos.m[2][2] + linpos.z; return *this; } Point& Point::InvTransform(const Point& r, const Matrix3x3& rotpos, const Point& linpos) { float sx = r.x - linpos.x; float sy = r.y - linpos.y; float sz = r.z - linpos.z; x = sx * rotpos.m[0][0] + sy * rotpos.m[1][0] + sz * rotpos.m[2][0]; y = sx * rotpos.m[0][1] + sy * rotpos.m[1][1] + sz * rotpos.m[2][1]; z = sx * rotpos.m[0][2] + sy * rotpos.m[1][2] + sz * rotpos.m[2][2]; return *this; } ode-0.14/OPCODE/Ice/IcePoint.h0000644000000000000000000004622612635011627014254 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for 3D vectors. * \file IcePoint.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEPOINT_H__ #define __ICEPOINT_H__ // Forward declarations class HPoint; class Plane; class Matrix3x3; class Matrix4x4; #define CROSS2D(a, b) (a.x*b.y - b.x*a.y) const float EPSILON2 = 1.0e-20f; class ICEMATHS_API Point { public: //! Empty constructor inline_ Point() {} //! Constructor from a single float // inline_ Point(float val) : x(val), y(val), z(val) {} // Removed since it introduced the nasty "Point T = *Matrix4x4.GetTrans();" bug....... //! Constructor from floats inline_ Point(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {} //! Constructor from array inline_ Point(const float f[3]) : x(f[X]), y(f[Y]), z(f[Z]) {} //! Copy constructor inline_ Point(const Point& p) : x(p.x), y(p.y), z(p.z) {} //! Destructor inline_ ~Point() {} //! Clears the vector inline_ Point& Zero() { x = y = z = 0.0f; return *this; } //! + infinity inline_ Point& SetPlusInfinity() { x = y = z = MAX_FLOAT; return *this; } //! - infinity inline_ Point& SetMinusInfinity() { x = y = z = MIN_FLOAT; return *this; } //! Sets positive unit random vector Point& PositiveUnitRandomVector(); //! Sets unit random vector Point& UnitRandomVector(); //! Assignment from values inline_ Point& Set(float xx, float yy, float zz) { x = xx; y = yy; z = zz; return *this; } //! Assignment from array inline_ Point& Set(const float f[3]) { x = f[X]; y = f[Y]; z = f[Z]; return *this; } //! Assignment from another point inline_ Point& Set(const Point& src) { x = src.x; y = src.y; z = src.z; return *this; } //! Adds a vector inline_ Point& Add(const Point& p) { x += p.x; y += p.y; z += p.z; return *this; } //! Adds a vector inline_ Point& Add(float xx, float yy, float zz) { x += xx; y += yy; z += zz; return *this; } //! Adds a vector inline_ Point& Add(const float f[3]) { x += f[X]; y += f[Y]; z += f[Z]; return *this; } //! Adds vectors inline_ Point& Add(const Point& p, const Point& q) { x = p.x+q.x; y = p.y+q.y; z = p.z+q.z; return *this; } //! Subtracts a vector inline_ Point& Sub(const Point& p) { x -= p.x; y -= p.y; z -= p.z; return *this; } //! Subtracts a vector inline_ Point& Sub(float xx, float yy, float zz) { x -= xx; y -= yy; z -= zz; return *this; } //! Subtracts a vector inline_ Point& Sub(const float f[3]) { x -= f[X]; y -= f[Y]; z -= f[Z]; return *this; } //! Subtracts vectors inline_ Point& Sub(const Point& p, const Point& q) { x = p.x-q.x; y = p.y-q.y; z = p.z-q.z; return *this; } //! this = -this inline_ Point& Neg() { x = -x; y = -y; z = -z; return *this; } //! this = -a inline_ Point& Neg(const Point& a) { x = -a.x; y = -a.y; z = -a.z; return *this; } //! Multiplies by a scalar inline_ Point& Mult(float s) { x *= s; y *= s; z *= s; return *this; } //! this = a * scalar inline_ Point& Mult(const Point& a, float scalar) { x = a.x * scalar; y = a.y * scalar; z = a.z * scalar; return *this; } //! this = a + b * scalar inline_ Point& Mac(const Point& a, const Point& b, float scalar) { x = a.x + b.x * scalar; y = a.y + b.y * scalar; z = a.z + b.z * scalar; return *this; } //! this = this + a * scalar inline_ Point& Mac(const Point& a, float scalar) { x += a.x * scalar; y += a.y * scalar; z += a.z * scalar; return *this; } //! this = a - b * scalar inline_ Point& Msc(const Point& a, const Point& b, float scalar) { x = a.x - b.x * scalar; y = a.y - b.y * scalar; z = a.z - b.z * scalar; return *this; } //! this = this - a * scalar inline_ Point& Msc(const Point& a, float scalar) { x -= a.x * scalar; y -= a.y * scalar; z -= a.z * scalar; return *this; } //! this = a + b * scalarb + c * scalarc inline_ Point& Mac2(const Point& a, const Point& b, float scalarb, const Point& c, float scalarc) { x = a.x + b.x * scalarb + c.x * scalarc; y = a.y + b.y * scalarb + c.y * scalarc; z = a.z + b.z * scalarb + c.z * scalarc; return *this; } //! this = a - b * scalarb - c * scalarc inline_ Point& Msc2(const Point& a, const Point& b, float scalarb, const Point& c, float scalarc) { x = a.x - b.x * scalarb - c.x * scalarc; y = a.y - b.y * scalarb - c.y * scalarc; z = a.z - b.z * scalarb - c.z * scalarc; return *this; } //! this = mat * a inline_ Point& Mult(const Matrix3x3& mat, const Point& a); //! this = mat1 * a1 + mat2 * a2 inline_ Point& Mult2(const Matrix3x3& mat1, const Point& a1, const Matrix3x3& mat2, const Point& a2); //! this = this + mat * a inline_ Point& Mac(const Matrix3x3& mat, const Point& a); //! this = transpose(mat) * a inline_ Point& TransMult(const Matrix3x3& mat, const Point& a); //! Linear interpolate between two vectors: this = a + t * (b - a) inline_ Point& Lerp(const Point& a, const Point& b, float t) { x = a.x + t * (b.x - a.x); y = a.y + t * (b.y - a.y); z = a.z + t * (b.z - a.z); return *this; } //! Hermite interpolate between p1 and p2. p0 and p3 are used for finding gradient at p1 and p2. //! this = p0 * (2t^2 - t^3 - t)/2 //! + p1 * (3t^3 - 5t^2 + 2)/2 //! + p2 * (4t^2 - 3t^3 + t)/2 //! + p3 * (t^3 - t^2)/2 inline_ Point& Herp(const Point& p0, const Point& p1, const Point& p2, const Point& p3, float t) { float t2 = t * t; float t3 = t2 * t; float kp0 = (2.0f * t2 - t3 - t) * 0.5f; float kp1 = (3.0f * t3 - 5.0f * t2 + 2.0f) * 0.5f; float kp2 = (4.0f * t2 - 3.0f * t3 + t) * 0.5f; float kp3 = (t3 - t2) * 0.5f; x = p0.x * kp0 + p1.x * kp1 + p2.x * kp2 + p3.x * kp3; y = p0.y * kp0 + p1.y * kp1 + p2.y * kp2 + p3.y * kp3; z = p0.z * kp0 + p1.z * kp1 + p2.z * kp2 + p3.z * kp3; return *this; } //! this = rotpos * r + linpos inline_ Point& Transform(const Point& r, const Matrix3x3& rotpos, const Point& linpos); //! this = trans(rotpos) * (r - linpos) inline_ Point& InvTransform(const Point& r, const Matrix3x3& rotpos, const Point& linpos); //! Returns MIN(x, y, z); inline_ float Min() const { return MIN(x, MIN(y, z)); } //! Returns MAX(x, y, z); inline_ float Max() const { return MAX(x, MAX(y, z)); } //! Sets each element to be componentwise minimum inline_ Point& Min(const Point& p) { x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z); return *this; } //! Sets each element to be componentwise maximum inline_ Point& Max(const Point& p) { x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z); return *this; } //! Clamps each element inline_ Point& Clamp(float min, float max) { if(xmax) x=max; if(ymax) y=max; if(zmax) z=max; return *this; } //! Computes square magnitude inline_ float SquareMagnitude() const { return x*x + y*y + z*z; } //! Computes magnitude inline_ float Magnitude() const { return sqrtf(x*x + y*y + z*z); } //! Computes volume inline_ float Volume() const { return x * y * z; } //! Checks the point is near zero inline_ bool ApproxZero() const { return SquareMagnitude() < EPSILON2; } //! Tests for exact zero vector inline_ BOOL IsZero() const { if(IR(x) || IR(y) || IR(z)) return FALSE; return TRUE; } //! Checks point validity inline_ BOOL IsValid() const { if(!IsValidFloat(x)) return FALSE; if(!IsValidFloat(y)) return FALSE; if(!IsValidFloat(z)) return FALSE; return TRUE; } //! Slighty moves the point void Tweak(udword coord_mask, udword tweak_mask) { if(coord_mask&1) { udword Dummy = IR(x); Dummy^=tweak_mask; x = FR(Dummy); } if(coord_mask&2) { udword Dummy = IR(y); Dummy^=tweak_mask; y = FR(Dummy); } if(coord_mask&4) { udword Dummy = IR(z); Dummy^=tweak_mask; z = FR(Dummy); } } #define TWEAKMASK 0x3fffff #define TWEAKNOTMASK ~TWEAKMASK //! Slighty moves the point out inline_ void TweakBigger() { udword Dummy = (IR(x)&TWEAKNOTMASK); if(!IS_NEGATIVE_FLOAT(x)) Dummy+=TWEAKMASK+1; x = FR(Dummy); Dummy = (IR(y)&TWEAKNOTMASK); if(!IS_NEGATIVE_FLOAT(y)) Dummy+=TWEAKMASK+1; y = FR(Dummy); Dummy = (IR(z)&TWEAKNOTMASK); if(!IS_NEGATIVE_FLOAT(z)) Dummy+=TWEAKMASK+1; z = FR(Dummy); } //! Slighty moves the point in inline_ void TweakSmaller() { udword Dummy = (IR(x)&TWEAKNOTMASK); if(IS_NEGATIVE_FLOAT(x)) Dummy+=TWEAKMASK+1; x = FR(Dummy); Dummy = (IR(y)&TWEAKNOTMASK); if(IS_NEGATIVE_FLOAT(y)) Dummy+=TWEAKMASK+1; y = FR(Dummy); Dummy = (IR(z)&TWEAKNOTMASK); if(IS_NEGATIVE_FLOAT(z)) Dummy+=TWEAKMASK+1; z = FR(Dummy); } //! Normalizes the vector inline_ Point& Normalize() { float M = x*x + y*y + z*z; if(M) { M = 1.0f / sqrtf(M); x *= M; y *= M; z *= M; } return *this; } //! Sets vector length inline_ Point& SetLength(float length) { float NewLength = length / Magnitude(); x *= NewLength; y *= NewLength; z *= NewLength; return *this; } //! Clamps vector length inline_ Point& ClampLength(float limit_length) { if(limit_length>=0.0f) // Magnitude must be positive { float CurrentSquareLength = SquareMagnitude(); if(CurrentSquareLength > limit_length * limit_length) { float Coeff = limit_length / sqrtf(CurrentSquareLength); x *= Coeff; y *= Coeff; z *= Coeff; } } return *this; } //! Computes distance to another point inline_ float Distance(const Point& b) const { return sqrtf((x - b.x)*(x - b.x) + (y - b.y)*(y - b.y) + (z - b.z)*(z - b.z)); } //! Computes square distance to another point inline_ float SquareDistance(const Point& b) const { return ((x - b.x)*(x - b.x) + (y - b.y)*(y - b.y) + (z - b.z)*(z - b.z)); } //! Dot product dp = this|a inline_ float Dot(const Point& p) const { return p.x * x + p.y * y + p.z * z; } //! Cross product this = a x b inline_ Point& Cross(const Point& a, const Point& b) { x = a.y * b.z - a.z * b.y; y = a.z * b.x - a.x * b.z; z = a.x * b.y - a.y * b.x; return *this; } //! Vector code ( bitmask = sign(z) | sign(y) | sign(x) ) inline_ udword VectorCode() const { return (IR(x)>>31) | ((IR(y)&SIGN_BITMASK)>>30) | ((IR(z)&SIGN_BITMASK)>>29); } //! Returns largest axis inline_ PointComponent LargestAxis() const { const float* Vals = &x; PointComponent m = X; if(Vals[Y] > Vals[m]) m = Y; if(Vals[Z] > Vals[m]) m = Z; return m; } //! Returns closest axis inline_ PointComponent ClosestAxis() const { const float* Vals = &x; PointComponent m = X; if(AIR(Vals[Y]) > AIR(Vals[m])) m = Y; if(AIR(Vals[Z]) > AIR(Vals[m])) m = Z; return m; } //! Returns smallest axis inline_ PointComponent SmallestAxis() const { const float* Vals = &x; PointComponent m = X; if(Vals[Y] < Vals[m]) m = Y; if(Vals[Z] < Vals[m]) m = Z; return m; } //! Refracts the point Point& Refract(const Point& eye, const Point& n, float refractindex, Point& refracted); //! Projects the point onto a plane Point& ProjectToPlane(const Plane& p); //! Projects the point onto the screen void ProjectToScreen(float halfrenderwidth, float halfrenderheight, const Matrix4x4& mat, HPoint& projected) const; //! Unfolds the point onto a plane according to edge(a,b) Point& Unfold(Plane& p, Point& a, Point& b); //! Hash function from Ville Miettinen inline_ udword GetHashValue() const { const udword* h = (const udword*)(this); udword f = (h[0]+h[1]*11-(h[2]*17)) & 0x7fffffff; // avoid problems with +-0 return (f>>22)^(f>>12)^(f); } //! Stuff magic values in the point, marking it as explicitely not used. void SetNotUsed(); //! Checks the point is marked as not used BOOL IsNotUsed() const; // Arithmetic operators //! Unary operator for Point Negate = - Point inline_ Point operator-() const { return Point(-x, -y, -z); } //! Operator for Point Plus = Point + Point. inline_ Point operator+(const Point& p) const { return Point(x + p.x, y + p.y, z + p.z); } //! Operator for Point Minus = Point - Point. inline_ Point operator-(const Point& p) const { return Point(x - p.x, y - p.y, z - p.z); } //! Operator for Point Mul = Point * Point. inline_ Point operator*(const Point& p) const { return Point(x * p.x, y * p.y, z * p.z); } //! Operator for Point Scale = Point * float. inline_ Point operator*(float s) const { return Point(x * s, y * s, z * s ); } //! Operator for Point Scale = float * Point. inline_ friend Point operator*(float s, const Point& p) { return Point(s * p.x, s * p.y, s * p.z); } //! Operator for Point Div = Point / Point. inline_ Point operator/(const Point& p) const { return Point(x / p.x, y / p.y, z / p.z); } //! Operator for Point Scale = Point / float. inline_ Point operator/(float s) const { s = 1.0f / s; return Point(x * s, y * s, z * s); } //! Operator for Point Scale = float / Point. inline_ friend Point operator/(float s, const Point& p) { return Point(s / p.x, s / p.y, s / p.z); } //! Operator for float DotProd = Point | Point. inline_ float operator|(const Point& p) const { return x*p.x + y*p.y + z*p.z; } //! Operator for Point VecProd = Point ^ Point. inline_ Point operator^(const Point& p) const { return Point( y * p.z - z * p.y, z * p.x - x * p.z, x * p.y - y * p.x ); } //! Operator for Point += Point. inline_ Point& operator+=(const Point& p) { x += p.x; y += p.y; z += p.z; return *this; } //! Operator for Point += float. inline_ Point& operator+=(float s) { x += s; y += s; z += s; return *this; } //! Operator for Point -= Point. inline_ Point& operator-=(const Point& p) { x -= p.x; y -= p.y; z -= p.z; return *this; } //! Operator for Point -= float. inline_ Point& operator-=(float s) { x -= s; y -= s; z -= s; return *this; } //! Operator for Point *= Point. inline_ Point& operator*=(const Point& p) { x *= p.x; y *= p.y; z *= p.z; return *this; } //! Operator for Point *= float. inline_ Point& operator*=(float s) { x *= s; y *= s; z *= s; return *this; } //! Operator for Point /= Point. inline_ Point& operator/=(const Point& p) { x /= p.x; y /= p.y; z /= p.z; return *this; } //! Operator for Point /= float. inline_ Point& operator/=(float s) { s = 1.0f/s; x *= s; y *= s; z *= s; return *this; } // Logical operators //! Operator for "if(Point==Point)" inline_ bool operator==(const Point& p) const { return ( (IR(x)==IR(p.x))&&(IR(y)==IR(p.y))&&(IR(z)==IR(p.z))); } //! Operator for "if(Point!=Point)" inline_ bool operator!=(const Point& p) const { return ( (IR(x)!=IR(p.x))||(IR(y)!=IR(p.y))||(IR(z)!=IR(p.z))); } // Arithmetic operators //! Operator for Point Mul = Point * Matrix3x3. inline_ Point operator*(const Matrix3x3& mat) const { class ShadowMatrix3x3{ public: float m[3][3]; }; // To allow inlining const ShadowMatrix3x3* Mat = (const ShadowMatrix3x3*)&mat; return Point( x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0], x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1], x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2] ); } //! Operator for Point Mul = Point * Matrix4x4. inline_ Point operator*(const Matrix4x4& mat) const { class ShadowMatrix4x4{ public: float m[4][4]; }; // To allow inlining const ShadowMatrix4x4* Mat = (const ShadowMatrix4x4*)&mat; return Point( x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0] + Mat->m[3][0], x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1] + Mat->m[3][1], x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2] + Mat->m[3][2]); } //! Operator for Point *= Matrix3x3. inline_ Point& operator*=(const Matrix3x3& mat) { class ShadowMatrix3x3{ public: float m[3][3]; }; // To allow inlining const ShadowMatrix3x3* Mat = (const ShadowMatrix3x3*)&mat; float xp = x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0]; float yp = x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1]; float zp = x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2]; x = xp; y = yp; z = zp; return *this; } //! Operator for Point *= Matrix4x4. inline_ Point& operator*=(const Matrix4x4& mat) { class ShadowMatrix4x4{ public: float m[4][4]; }; // To allow inlining const ShadowMatrix4x4* Mat = (const ShadowMatrix4x4*)&mat; float xp = x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0] + Mat->m[3][0]; float yp = x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1] + Mat->m[3][1]; float zp = x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2] + Mat->m[3][2]; x = xp; y = yp; z = zp; return *this; } // Cast operators //! Cast a Point to a HPoint. w is set to zero. operator HPoint() const; inline_ operator const float*() const { return &x; } inline_ operator float*() { return &x; } public: float x, y, z; }; FUNCTION ICEMATHS_API void Normalize1(Point& a); FUNCTION ICEMATHS_API void Normalize2(Point& a); #endif //__ICEPOINT_H__ ode-0.14/OPCODE/Ice/IcePreprocessor.h0000644000000000000000000000712412635011627015643 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains preprocessor stuff. This should be the first included header. * \file IcePreprocessor.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICEPREPROCESSOR_H__ #define __ICEPREPROCESSOR_H__ // Check platform #if defined( _WIN32 ) || defined( WIN32 ) // #pragma message("Compiling on Windows...") #define PLATFORM_WINDOWS #else // don't issue pragmas on unknown platforms // #pragma message("Compiling on unknown platform...") #endif // Check compiler #if defined(_MSC_VER) // #pragma message("Compiling with VC++...") #define COMPILER_VISUAL_CPP #else // don't issue pragmas on unknown platforms // #pragma message("Compiling with unknown compiler...") #endif // Check compiler options. If this file is included in user-apps, this // shouldn't be needed, so that they can use what they like best. #ifndef ICE_DONT_CHECK_COMPILER_OPTIONS #ifdef COMPILER_VISUAL_CPP #if defined(_CHAR_UNSIGNED) #endif #if defined(_CPPRTTI) #error Please disable RTTI... #endif #if defined(_CPPUNWIND) #error Please disable exceptions... #endif #if defined(_MT) // Multithreading #endif #endif #endif // Check debug mode #ifdef DEBUG // May be defined instead of _DEBUG. Let's fix it. #ifndef _DEBUG #define _DEBUG #endif #endif #ifdef _DEBUG // Here you may define items for debug builds #endif #ifndef THIS_FILE #define THIS_FILE __FILE__ #endif #ifndef ICE_NO_DLL #ifdef ICECORE_EXPORTS #define ICECORE_API __declspec(dllexport) #else #define ICECORE_API __declspec(dllimport) #endif #else #define ICECORE_API #endif // Don't override new/delete // #define DEFAULT_NEWDELETE #define DONT_TRACK_MEMORY_LEAKS #define FUNCTION extern "C" // Cosmetic stuff [mainly useful with multiple inheritance] #define override(base_class) virtual // Our own inline keyword, so that: // - we can switch to __forceinline to check it's really better or not // - we can remove __forceinline if the compiler doesn't support it // #define inline_ __forceinline // #define inline_ inline // Contributed by Bruce Mitchener #if defined(COMPILER_VISUAL_CPP) #define inline_ __forceinline // #define inline_ inline #elif defined(__GNUC__) && __GNUC__ < 3 #define inline_ inline #elif defined(__GNUC__) #define inline_ inline __attribute__ ((always_inline)) #else #define inline_ inline #endif // Down the hatch #ifdef _MSC_VER #pragma inline_depth( 255 ) #endif #ifdef COMPILER_VISUAL_CPP #pragma intrinsic(memcmp) #pragma intrinsic(memcpy) #pragma intrinsic(memset) #pragma intrinsic(strcat) #pragma intrinsic(strcmp) #pragma intrinsic(strcpy) #pragma intrinsic(strlen) #pragma intrinsic(abs) #pragma intrinsic(labs) #endif // ANSI compliance #ifdef _DEBUG // Remove painful warning in debug inline_ bool __False__(){ return false; } #define for if(__False__()){} else for #else #define for if(0){} else for #endif #endif // __ICEPREPROCESSOR_H__ ode-0.14/OPCODE/Ice/IceRandom.cpp0000644000000000000000000000213612635011627014726 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for random generators. * \file IceRandom.cpp * \author Pierre Terdiman * \date August, 9, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceCore; void IceCore:: SRand(udword seed) { srand(seed); } udword IceCore::Rand() { return rand(); } static BasicRandom gRandomGenerator(42); udword IceCore::GetRandomIndex(udword max_index) { // We don't use rand() since it's limited to RAND_MAX udword Index = gRandomGenerator.Randomize(); return Index % max_index; } ode-0.14/OPCODE/Ice/IceRandom.h0000644000000000000000000000305112635011627014370 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for random generators. * \file IceRandom.h * \author Pierre Terdiman * \date August, 9, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICERANDOM_H__ #define __ICERANDOM_H__ FUNCTION ICECORE_API void SRand(udword seed); FUNCTION ICECORE_API udword Rand(); //! Returns a unit random floating-point value inline_ float UnitRandomFloat() { return float(Rand()) * ONE_OVER_RAND_MAX; } //! Returns a random index so that 0<= index < max_index ICECORE_API udword GetRandomIndex(udword max_index); class ICECORE_API BasicRandom { public: //! Constructor inline_ BasicRandom(udword seed=0) : mRnd(seed) {} //! Destructor inline_ ~BasicRandom() {} inline_ void SetSeed(udword seed) { mRnd = seed; } inline_ udword GetCurrentValue() const { return mRnd; } inline_ udword Randomize() { mRnd = mRnd * 2147001325 + 715136305; return mRnd; } private: udword mRnd; }; #endif // __ICERANDOM_H__ ode-0.14/OPCODE/Ice/IceRay.cpp0000644000000000000000000000470012635011627014240 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for rays. * \file IceRay.cpp * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Ray class. * A ray is a half-line P(t) = mOrig + mDir * t, with 0 <= t <= +infinity * \class Ray * \author Pierre Terdiman * \version 1.0 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* O = Origin = impact point i = normalized vector along the x axis j = normalized vector along the y axis = actually the normal vector in O D = Direction vector, norm |D| = 1 N = Projection of D on y axis, norm |N| = normal reaction T = Projection of D on x axis, norm |T| = tangential reaction R = Reflexion vector ^y | | | _ _ _| _ _ _ * * *| \ | / \ |N / | R\ | /D \ | / | \ | / _________\|/______*_______>x O T Let define theta = angle between D and N. Then cos(theta) = |N| / |D| = |N| since D is normalized. j|D = |j|*|D|*cos(theta) => |N| = j|D Then we simply have: D = N + T To compute tangential reaction : T = D - N To compute reflexion vector : R = N - T = N - (D-N) = 2*N - D */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; float Ray::SquareDistance(const Point& point, float* t) const { Point Diff = point - mOrig; float fT = Diff | mDir; if(fT<=0.0f) { fT = 0.0f; } else { fT /= mDir.SquareMagnitude(); Diff -= fT*mDir; } if(t) *t = fT; return Diff.SquareMagnitude(); } ode-0.14/OPCODE/Ice/IceRay.h0000644000000000000000000001112012635011627013677 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for rays. * \file IceRay.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICERAY_H__ #define __ICERAY_H__ class ICEMATHS_API Ray { public: //! Constructor inline_ Ray() {} //! Constructor inline_ Ray(const Point& orig, const Point& dir) : mOrig(orig), mDir(dir) {} //! Copy constructor inline_ Ray(const Ray& ray) : mOrig(ray.mOrig), mDir(ray.mDir) {} //! Destructor inline_ ~Ray() {} float SquareDistance(const Point& point, float* t=null) const; inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); } Point mOrig; //!< Ray origin Point mDir; //!< Normalized direction }; inline_ void ComputeReflexionVector(Point& reflected, const Point& incoming_dir, const Point& outward_normal) { reflected = incoming_dir - outward_normal * 2.0f * (incoming_dir|outward_normal); } inline_ void ComputeReflexionVector(Point& reflected, const Point& source, const Point& impact, const Point& normal) { Point V = impact - source; reflected = V - normal * 2.0f * (V|normal); } inline_ void DecomposeVector(Point& normal_compo, Point& tangent_compo, const Point& outward_dir, const Point& outward_normal) { normal_compo = outward_normal * (outward_dir|outward_normal); tangent_compo = outward_dir - normal_compo; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Transforms a direction vector from world space to local space * \param local_dir [out] direction vector in local space * \param world_dir [in] direction vector in world space * \param world [in] world transform */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void ComputeLocalDirection(Point& local_dir, const Point& world_dir, const Matrix4x4& world) { // Get world direction back in local space // Matrix3x3 InvWorld = world; // local_dir = InvWorld * world_dir; local_dir = Matrix3x3(world) * world_dir; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Transforms a position vector from world space to local space * \param local_pt [out] position vector in local space * \param world_pt [in] position vector in world space * \param world [in] world transform */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void ComputeLocalPoint(Point& local_pt, const Point& world_pt, const Matrix4x4& world) { // Get world vertex back in local space Matrix4x4 InvWorld = world; InvWorld.Invert(); local_pt = world_pt * InvWorld; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Transforms a ray from world space to local space * \param local_ray [out] ray in local space * \param world_ray [in] ray in world space * \param world [in] world transform */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void ComputeLocalRay(Ray& local_ray, const Ray& world_ray, const Matrix4x4& world) { // Get world ray back in local space ComputeLocalDirection(local_ray.mDir, world_ray.mDir, world); ComputeLocalPoint(local_ray.mOrig, world_ray.mOrig, world); } #endif // __ICERAY_H__ ode-0.14/OPCODE/Ice/IceRevisitedRadix.cpp0000644000000000000000000005300212635011627016432 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains source code from the article "Radix Sort Revisited". * \file IceRevisitedRadix.cpp * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Revisited Radix Sort. * This is my new radix routine: * - it uses indices and doesn't recopy the values anymore, hence wasting less ram * - it creates all the histograms in one run instead of four * - it sorts words faster than dwords and bytes faster than words * - it correctly sorts negative floating-point values by patching the offsets * - it automatically takes advantage of temporal coherence * - multiple keys support is a side effect of temporal coherence * - it may be worth recoding in asm... (mainly to use FCOMI, FCMOV, etc) [it's probably memory-bound anyway] * * History: * - 08.15.98: very first version * - 04.04.00: recoded for the radix article * - 12.xx.00: code lifting * - 09.18.01: faster CHECK_PASS_VALIDITY thanks to Mark D. Shattuck (who provided other tips, not included here) * - 10.11.01: added local ram support * - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting...... * - 01.02.02: - "mIndices" renamed => "mRanks". That's a rank sorter after all. * - ranks are not "reset" anymore, but implicit on first calls * - 07.05.02: - offsets rewritten with one less indirection. * - 11.03.02: - "bool" replaced with RadixHint enum * * \class RadixSort * \author Pierre Terdiman * \version 1.4 * \date August, 15, 1998 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* To do: - add an offset parameter between two input values (avoid some data recopy sometimes) - unroll ? asm ? - 11 bits trick & 3 passes as Michael did - prefetch stuff the day I have a P3 - make a version with 16-bits indices ? */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceCore; #define INVALIDATE_RANKS mCurrentSize|=0x80000000 #define VALIDATE_RANKS mCurrentSize&=0x7fffffff #define CURRENT_SIZE (mCurrentSize&0x7fffffff) #define INVALID_RANKS (mCurrentSize&0x80000000) #define CHECK_RESIZE(n) \ if(n!=mPreviousSize) \ { \ if(n>mCurrentSize) Resize(n); \ else ResetRanks(); \ mPreviousSize = n; \ } #define CREATE_HISTOGRAMS(type, buffer) \ /* Clear counters/histograms */ \ ZeroMemory(mHistogram, 256*4*sizeof(udword)); \ \ /* Prepare to count */ \ ubyte* p = (ubyte*)input; \ ubyte* pe = &p[nb*4]; \ udword* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \ udword* h1= &mHistogram[256]; /* Histogram for second pass */ \ udword* h2= &mHistogram[512]; /* Histogram for third pass */ \ udword* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \ \ bool AlreadySorted = true; /* Optimism... */ \ \ if(INVALID_RANKS) \ { \ /* Prepare for temporal coherence */ \ type* Running = (type*)buffer; \ type PrevVal = *Running; \ \ while(p!=pe) \ { \ /* Read input buffer in previous sorted order */ \ type Val = *Running++; \ /* Check whether already sorted or not */ \ if(ValCurSize) Resize(nb); mCurrentSize = nb; INVALIDATE_RANKS; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Main sort routine. * This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. * \param input [in] a list of integer values to sort * \param nb [in] number of values to sort, must be < 2^31 * \param hint [in] RADIX_SIGNED to handle negative values, RADIX_UNSIGNED if you know your input buffer only contains positive values * \return Self-Reference */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint) { // Checkings if(!input || !nb || nb&0x80000000) return *this; // Stats mTotalCalls++; // Resize lists if needed CheckResize(nb); #ifdef RADIX_LOCAL_RAM // Allocate histograms & offsets on the stack udword mHistogram[256*4]; // udword mOffset[256]; udword* mLink[256]; #endif // Create histograms (counters). Counters for all passes are created in one run. // Pros: read input buffer once instead of four times // Cons: mHistogram is 4Kb instead of 1Kb // We must take care of signed/unsigned values for temporal coherence.... I just // have 2 code paths even if just a single opcode changes. Self-modifying code, someone? if(hint==RADIX_UNSIGNED) { CREATE_HISTOGRAMS(udword, input); } else { CREATE_HISTOGRAMS(sdword, input); } // Compute #negative values involved if needed udword NbNegativeValues = 0; if(hint==RADIX_SIGNED) { // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128 // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte, // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers. udword* h3= &mHistogram[768]; for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part } // Radix sort, j is the pass number (0=LSB, 3=MSB) for(udword j=0;j<4;j++) { CHECK_PASS_VALIDITY(j); // Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is // not a problem, numbers are correctly sorted anyway. if(PerformPass) { // Should we care about negative values? if(j!=3 || hint==RADIX_UNSIGNED) { // Here we deal with positive values only // Create offsets // mOffset[0] = 0; // for(udword i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; mLink[0] = mRanks2; for(udword i=1;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; } else { // This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place. // Create biased offsets, in order for negative numbers to be sorted as well // mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones // for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers // Fixing the wrong place for negative values // mOffset[128] = 0; mLink[128] = mRanks2; // for(i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; for(udword i=129;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; } // Perform Radix Sort ubyte* InputBytes = (ubyte*)input; InputBytes += j; if(INVALID_RANKS) { // for(udword i=0;i>24; // Radix byte, same as above. AND is useless here (udword). // ### cmp to be killed. Not good. Later. // if(Radix<128) mRanks2[mOffset[Radix]++] = i; // Number is positive, same as above // else mRanks2[--mOffset[Radix]] = i; // Number is negative, flip the sorting order if(Radix<128) *mLink[Radix]++ = i; // Number is positive, same as above else *(--mLink[Radix]) = i; // Number is negative, flip the sorting order } VALIDATE_RANKS; } else { for(udword i=0;i>24; // Radix byte, same as above. AND is useless here (udword). // ### cmp to be killed. Not good. Later. // if(Radix<128) mRanks2[mOffset[Radix]++] = mRanks[i]; // Number is positive, same as above // else mRanks2[--mOffset[Radix]] = mRanks[i]; // Number is negative, flip the sorting order if(Radix<128) *mLink[Radix]++ = mRanks[i]; // Number is positive, same as above else *(--mLink[Radix]) = mRanks[i]; // Number is negative, flip the sorting order } } // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; } else { // The pass is useless, yet we still have to reverse the order of current list if all values are negative. if(UniqueVal>=128) { if(INVALID_RANKS) { // ###Possible? for(udword i=0;i=SqrLen) { fT = 1.0f; Diff -= Dir; } else { fT /= SqrLen; Diff -= fT*Dir; } } if(t) *t = fT; return Diff.SquareMagnitude(); } ode-0.14/OPCODE/Ice/IceSegment.h0000644000000000000000000000510212635011627014551 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for segments. * \file IceSegment.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICESEGMENT_H__ #define __ICESEGMENT_H__ class ICEMATHS_API Segment { public: //! Constructor inline_ Segment() {} //! Constructor inline_ Segment(const Point& p0, const Point& p1) : mP0(p0), mP1(p1) {} //! Copy constructor inline_ Segment(const Segment& seg) : mP0(seg.mP0), mP1(seg.mP1) {} //! Destructor inline_ ~Segment() {} inline_ const Point& GetOrigin() const { return mP0; } inline_ Point ComputeDirection() const { return mP1 - mP0; } inline_ void ComputeDirection(Point& dir) const { dir = mP1 - mP0; } inline_ float ComputeLength() const { return mP1.Distance(mP0); } inline_ float ComputeSquareLength() const { return mP1.SquareDistance(mP0); } inline_ void SetOriginDirection(const Point& origin, const Point& direction) { mP0 = mP1 = origin; mP1 += direction; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes a point on the segment * \param pt [out] point on segment * \param t [in] point's parameter [t=0 => pt = mP0, t=1 => pt = mP1] */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void ComputePoint(Point& pt, float t) const { pt = mP0 + t * (mP1 - mP0); } float SquareDistance(const Point& point, float* t=null) const; inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); } Point mP0; //!< Start of segment Point mP1; //!< End of segment }; #endif // __ICESEGMENT_H__ ode-0.14/OPCODE/Ice/IceTriList.h0000644000000000000000000000427312635011627014551 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a triangle container. * \file IceTrilist.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICETRILIST_H__ #define __ICETRILIST_H__ class ICEMATHS_API TriList : public Container { public: // Constructor / Destructor TriList() {} ~TriList() {} inline_ udword GetNbTriangles() const { return GetNbEntries()/9; } inline_ Triangle* GetTriangles() const { return (Triangle*)GetEntries(); } void AddTri(const Triangle& tri) { Add(tri.mVerts[0].x).Add(tri.mVerts[0].y).Add(tri.mVerts[0].z); Add(tri.mVerts[1].x).Add(tri.mVerts[1].y).Add(tri.mVerts[1].z); Add(tri.mVerts[2].x).Add(tri.mVerts[2].y).Add(tri.mVerts[2].z); } void AddTri(const Point& p0, const Point& p1, const Point& p2) { Add(p0.x).Add(p0.y).Add(p0.z); Add(p1.x).Add(p1.y).Add(p1.z); Add(p2.x).Add(p2.y).Add(p2.z); } }; class ICEMATHS_API TriangleList : public Container { public: // Constructor / Destructor TriangleList() {} ~TriangleList() {} inline_ udword GetNbTriangles() const { return GetNbEntries()/3; } inline_ IndexedTriangle* GetTriangles() const { return (IndexedTriangle*)GetEntries();} void AddTriangle(const IndexedTriangle& tri) { Add((udword)tri.mVRef[0]).Add((udword)tri.mVRef[1]).Add((udword)tri.mVRef[2]); } void AddTriangle(udword vref0, udword vref1, udword vref2) { Add(vref0).Add(vref1).Add(vref2); } }; #endif //__ICETRILIST_H__ ode-0.14/OPCODE/Ice/IceTriangle.cpp0000644000000000000000000003015212635011627015252 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a handy triangle class. * \file IceTriangle.cpp * \author Pierre Terdiman * \date January, 17, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace IceMaths; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a triangle class. * * \class Tri * \author Pierre Terdiman * \version 1.0 * \date 08.15.98 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static sdword VPlaneSideEps(const Point& v, const Plane& plane, float epsilon) { // Compute distance from current vertex to the plane float Dist = plane.Distance(v); // Compute side: // 1 = the vertex is on the positive side of the plane // -1 = the vertex is on the negative side of the plane // 0 = the vertex is on the plane (within epsilon) return Dist > epsilon ? 1 : Dist < -epsilon ? -1 : 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Flips the winding order. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Triangle::Flip() { Point Tmp = mVerts[1]; mVerts[1] = mVerts[2]; mVerts[2] = Tmp; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle area. * \return the area */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Triangle::Area() const { const Point& p0 = mVerts[0]; const Point& p1 = mVerts[1]; const Point& p2 = mVerts[2]; return ((p0 - p1)^(p0 - p2)).Magnitude() * 0.5f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle perimeter. * \return the perimeter */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Triangle::Perimeter() const { const Point& p0 = mVerts[0]; const Point& p1 = mVerts[1]; const Point& p2 = mVerts[2]; return p0.Distance(p1) + p0.Distance(p2) + p1.Distance(p2); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle compacity. * \return the compacity */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Triangle::Compacity() const { float P = Perimeter(); if(P==0.0f) return 0.0f; return (4.0f*PI*Area()/(P*P)); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle normal. * \param normal [out] the computed normal */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Triangle::Normal(Point& normal) const { const Point& p0 = mVerts[0]; const Point& p1 = mVerts[1]; const Point& p2 = mVerts[2]; normal = ((p0 - p1)^(p0 - p2)).Normalize(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle denormalized normal. * \param normal [out] the computed normal */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Triangle::DenormalizedNormal(Point& normal) const { const Point& p0 = mVerts[0]; const Point& p1 = mVerts[1]; const Point& p2 = mVerts[2]; normal = ((p0 - p1)^(p0 - p2)); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle center. * \param center [out] the computed center */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Triangle::Center(Point& center) const { const Point& p0 = mVerts[0]; const Point& p1 = mVerts[1]; const Point& p2 = mVerts[2]; center = (p0 + p1 + p2)*INV3; } PartVal Triangle::TestAgainstPlane(const Plane& plane, float epsilon) const { bool Pos = false, Neg = false; // Loop through all vertices for(udword i=0;i<3;i++) { // Compute side: sdword Side = VPlaneSideEps(mVerts[i], plane, epsilon); if (Side < 0) Neg = true; else if (Side > 0) Pos = true; } if (!Pos && !Neg) return TRI_ON_PLANE; else if (Pos && Neg) return TRI_INTERSECT; else if (Pos && !Neg) return TRI_PLUS_SPACE; else if (!Pos && Neg) return TRI_MINUS_SPACE; // What?! return TRI_FORCEDWORD; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle moment. * \param m [out] the moment */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* void Triangle::ComputeMoment(Moment& m) { // Compute the area of the triangle m.mArea = Area(); // Compute the centroid Center(m.mCentroid); // Second-order components. Handle zero-area faces. Point& p = mVerts[0]; Point& q = mVerts[1]; Point& r = mVerts[2]; if(m.mArea==0.0f) { // This triangle has zero area. The second order components would be eliminated with the usual formula, so, for the // sake of robustness we use an alternative form. These are the centroid and second-order components of the triangle's vertices. m.mCovariance.m[0][0] = (p.x*p.x + q.x*q.x + r.x*r.x); m.mCovariance.m[0][1] = (p.x*p.y + q.x*q.y + r.x*r.y); m.mCovariance.m[0][2] = (p.x*p.z + q.x*q.z + r.x*r.z); m.mCovariance.m[1][1] = (p.y*p.y + q.y*q.y + r.y*r.y); m.mCovariance.m[1][2] = (p.y*p.z + q.y*q.z + r.y*r.z); m.mCovariance.m[2][2] = (p.z*p.z + q.z*q.z + r.z*r.z); m.mCovariance.m[2][1] = m.mCovariance.m[1][2]; m.mCovariance.m[1][0] = m.mCovariance.m[0][1]; m.mCovariance.m[2][0] = m.mCovariance.m[0][2]; } else { const float OneOverTwelve = 1.0f / 12.0f; m.mCovariance.m[0][0] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.x + p.x*p.x + q.x*q.x + r.x*r.x) * OneOverTwelve; m.mCovariance.m[0][1] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.y + p.x*p.y + q.x*q.y + r.x*r.y) * OneOverTwelve; m.mCovariance.m[1][1] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.y + p.y*p.y + q.y*q.y + r.y*r.y) * OneOverTwelve; m.mCovariance.m[0][2] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.z + p.x*p.z + q.x*q.z + r.x*r.z) * OneOverTwelve; m.mCovariance.m[1][2] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.z + p.y*p.z + q.y*q.z + r.y*r.z) * OneOverTwelve; m.mCovariance.m[2][2] = m.mArea * (9.0f * m.mCentroid.z*m.mCentroid.z + p.z*p.z + q.z*q.z + r.z*r.z) * OneOverTwelve; m.mCovariance.m[2][1] = m.mCovariance.m[1][2]; m.mCovariance.m[1][0] = m.mCovariance.m[0][1]; m.mCovariance.m[2][0] = m.mCovariance.m[0][2]; } } */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle's smallest edge length. * \return the smallest edge length */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Triangle::MinEdgeLength() const { float Min = MAX_FLOAT; float Length01 = mVerts[0].Distance(mVerts[1]); float Length02 = mVerts[0].Distance(mVerts[2]); float Length12 = mVerts[1].Distance(mVerts[2]); if(Length01 < Min) Min = Length01; if(Length02 < Min) Min = Length02; if(Length12 < Min) Min = Length12; return Min; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the triangle's largest edge length. * \return the largest edge length */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float Triangle::MaxEdgeLength() const { float Max = MIN_FLOAT; float Length01 = mVerts[0].Distance(mVerts[1]); float Length02 = mVerts[0].Distance(mVerts[2]); float Length12 = mVerts[1].Distance(mVerts[2]); if(Length01 > Max) Max = Length01; if(Length02 > Max) Max = Length02; if(Length12 > Max) Max = Length12; return Max; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes a point on the triangle according to the stabbing information. * \param u,v [in] point's barycentric coordinates * \param pt [out] point on triangle * \param nearvtx [out] index of nearest vertex */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Triangle::ComputePoint(float u, float v, Point& pt, udword* nearvtx) const { // Compute point coordinates pt = (1.0f - u - v)*mVerts[0] + u*mVerts[1] + v*mVerts[2]; // Compute nearest vertex if needed if(nearvtx) { // Compute distance vector Point d(mVerts[0].SquareDistance(pt), // Distance^2 from vertex 0 to point on the face mVerts[1].SquareDistance(pt), // Distance^2 from vertex 1 to point on the face mVerts[2].SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face // Get smallest distance *nearvtx = d.SmallestAxis(); } } void Triangle::Inflate(float fat_coeff, bool constant_border) { // Compute triangle center Point TriangleCenter; Center(TriangleCenter); // Don't normalize? // Normalize => add a constant border, regardless of triangle size // Don't => add more to big triangles for(udword i=0;i<3;i++) { Point v = mVerts[i] - TriangleCenter; if(constant_border) v.Normalize(); mVerts[i] += v * fat_coeff; } } ode-0.14/OPCODE/Ice/IceTriangle.h0000644000000000000000000000466412635011627014730 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a handy triangle class. * \file IceTriangle.h * \author Pierre Terdiman * \date January, 17, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICETRIANGLE_H__ #define __ICETRIANGLE_H__ // Forward declarations class Moment; // Partitioning values enum PartVal { TRI_MINUS_SPACE = 0, //!< Triangle is in the negative space TRI_PLUS_SPACE = 1, //!< Triangle is in the positive space TRI_INTERSECT = 2, //!< Triangle intersects plane TRI_ON_PLANE = 3, //!< Triangle and plane are coplanar TRI_FORCEDWORD = 0x7fffffff }; // A triangle class. class ICEMATHS_API Triangle { public: //! Constructor inline_ Triangle() {} //! Constructor inline_ Triangle(const Point& p0, const Point& p1, const Point& p2) { mVerts[0]=p0; mVerts[1]=p1; mVerts[2]=p2; } //! Copy constructor inline_ Triangle(const Triangle& triangle) { mVerts[0] = triangle.mVerts[0]; mVerts[1] = triangle.mVerts[1]; mVerts[2] = triangle.mVerts[2]; } //! Destructor inline_ ~Triangle() {} //! Vertices Point mVerts[3]; // Methods void Flip(); float Area() const; float Perimeter() const; float Compacity() const; void Normal(Point& normal) const; void DenormalizedNormal(Point& normal) const; void Center(Point& center) const; inline_ Plane PlaneEquation() const { return Plane(mVerts[0], mVerts[1], mVerts[2]); } PartVal TestAgainstPlane(const Plane& plane, float epsilon) const; // float Distance(Point& cp, Point& cq, Tri& tri); void ComputeMoment(Moment& m); float MinEdgeLength() const; float MaxEdgeLength() const; void ComputePoint(float u, float v, Point& pt, udword* nearvtx=null) const; void Inflate(float fat_coeff, bool constant_border); }; #endif // __ICETRIANGLE_H__ ode-0.14/OPCODE/Ice/IceTypes.h0000644000000000000000000001655212635011627014266 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains custom types. * \file IceTypes.h * \author Pierre Terdiman * \date April, 4, 2000 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __ICETYPES_H__ #define __ICETYPES_H__ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Things to help us compile on non-windows platforms /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define USE_HANDLE_MANAGER // Constants #define PI 3.1415926535897932384626433832795028841971693993751f //!< PI #define HALFPI 1.57079632679489661923f //!< 0.5 * PI #define TWOPI 6.28318530717958647692f //!< 2.0 * PI #define INVPI 0.31830988618379067154f //!< 1.0 / PI #define RADTODEG 57.2957795130823208768f //!< 180.0 / PI, convert radians to degrees #define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians #define EXP 2.71828182845904523536f //!< e #define INVLOG2 3.32192809488736234787f //!< 1.0 / log10(2) #define LN2 0.693147180559945f //!< ln(2) #define INVLN2 1.44269504089f //!< 1.0f / ln(2) #define INV3 0.33333333333333333333f //!< 1/3 #define INV6 0.16666666666666666666f //!< 1/6 #define INV7 0.14285714285714285714f //!< 1/7 #define INV9 0.11111111111111111111f //!< 1/9 #define INV255 0.00392156862745098039f //!< 1/255 #define SQRT2 1.41421356237f //!< sqrt(2) #define INVSQRT2 0.707106781188f //!< 1 / sqrt(2) #define SQRT3 1.73205080757f //!< sqrt(3) #define INVSQRT3 0.577350269189f //!< 1 / sqrt(3) #define null 0 //!< our own NULL pointer // Custom types used in ICE typedef signed char sbyte; //!< sizeof(sbyte) must be 1 typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1 typedef signed short sword; //!< sizeof(sword) must be 2 typedef unsigned short uword; //!< sizeof(uword) must be 2 typedef signed int sdword; //!< sizeof(sdword) must be 4 typedef unsigned int udword; //!< sizeof(udword) must be 4 typedef signed __int64 sqword; //!< sizeof(sqword) must be 8 typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8 typedef float float32; //!< sizeof(float32) must be 4 typedef double float64; //!< sizeof(float64) must be 4 ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1); ICE_COMPILE_TIME_ASSERT(sizeof(sbyte)==1); ICE_COMPILE_TIME_ASSERT(sizeof(sword)==2); ICE_COMPILE_TIME_ASSERT(sizeof(uword)==2); ICE_COMPILE_TIME_ASSERT(sizeof(udword)==4); ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4); ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8); ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8); //! TO BE DOCUMENTED #define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name typedef udword DynID; //!< Dynamic identifier #ifdef USE_HANDLE_MANAGER typedef udword KID; //!< Kernel ID // DECLARE_ICE_HANDLE(KID); #else typedef uword KID; //!< Kernel ID #endif typedef udword RTYPE; //!< Relationship-type (!) between owners and references #define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers) #ifdef USE_HANDLE_MANAGER #define INVALID_KID 0xffffffff //!< Invalid Kernel ID #else #define INVALID_KID 0xffff //!< Invalid Kernel ID #endif #define INVALID_NUMBER 0xDEADBEEF //!< Standard junk value // Define BOOL if needed #ifndef BOOL typedef int BOOL; //!< Another boolean type. #endif //! Union of a float and a sdword typedef union { float f; //!< The float sdword d; //!< The integer }scell; //! Union of a float and a udword typedef union { float f; //!< The float udword d; //!< The integer }ucell; // Type ranges #define MAX_SBYTE 0x7f //!< max possible sbyte value #define MIN_SBYTE 0x80 //!< min possible sbyte value #define MAX_UBYTE 0xff //!< max possible ubyte value #define MIN_UBYTE 0x00 //!< min possible ubyte value #define MAX_SWORD 0x7fff //!< max possible sword value #define MIN_SWORD 0x8000 //!< min possible sword value #define MAX_UWORD 0xffff //!< max possible uword value #define MIN_UWORD 0x0000 //!< min possible uword value #define MAX_SDWORD 0x7fffffff //!< max possible sdword value #define MIN_SDWORD 0x80000000 //!< min possible sdword value #define MAX_UDWORD 0xffffffff //!< max possible udword value #define MIN_UDWORD 0x00000000 //!< min possible udword value #define MAX_FLOAT FLT_MAX //!< max possible float value #define MIN_FLOAT (-FLT_MAX) //!< min possible loat value #define IEEE_1_0 0x3f800000 //!< integer representation of 1.0 #define IEEE_255_0 0x437f0000 //!< integer representation of 255.0 #define IEEE_MAX_FLOAT 0x7f7fffff //!< integer representation of MAX_FLOAT #define IEEE_MIN_FLOAT 0xff7fffff //!< integer representation of MIN_FLOAT #define IEEE_UNDERFLOW_LIMIT 0x1a000000 #define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand() // typedef int (__stdcall* PROC)(); -- Oleh Derevenko: Conflicts with Windows headers in x64 mode //!< A standard procedure call. typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call typedef void** VTABLE; //!< A V-Table. #undef MIN #undef MAX #define MIN(a, b) ((a) < (b) ? (a) : (b)) //!< Returns the min value between a and b #define MAX(a, b) ((a) > (b) ? (a) : (b)) //!< Returns the max value between a and b #define MAXMAX(a,b,c) ((a) > (b) ? MAX (a,c) : MAX (b,c)) //!< Returns the max value between a, b and c template inline_ const T& TMin (const T& a, const T& b) { return b < a ? b : a; } template inline_ const T& TMax (const T& a, const T& b) { return a < b ? b : a; } template inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; } template inline_ void TSetMax (T& a, const T& b) { if(a> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa); n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc); n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0); n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00); n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000); // Etc for larger intergers (64 bits in Java) // NOTE: the >> operation must be unsigned! (>>> in java) } //! Count the number of '1' bits in a 32 bit word (from Steve Baker's Cute Code Collection) inline_ udword CountBits(udword n) { // This relies of the fact that the count of n bits can NOT overflow // an n bit interger. EG: 1 bit count takes a 1 bit interger, 2 bit counts // 2 bit interger, 3 bit count requires only a 2 bit interger. // So we add all bit pairs, then each nible, then each byte etc... n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1); n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2); n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4); n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8); n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16); // Etc for larger intergers (64 bits in Java) // NOTE: the >> operation must be unsigned! (>>> in java) return n; } //! Even faster? inline_ udword CountBits2(udword bits) { bits = bits - ((bits >> 1) & 0x55555555); bits = ((bits >> 2) & 0x33333333) + (bits & 0x33333333); bits = ((bits >> 4) + bits) & 0x0F0F0F0F; return (bits * 0x01010101) >> 24; } //! Spread out bits. EG 00001111 -> 0101010101 //! 00001010 -> 0100010000 //! This is used to interleve to intergers to produce a `Morten Key' //! used in Space Filling Curves (See DrDobbs Journal, July 1999) //! Order is important. inline_ void SpreadBits(udword& n) { n = ( n & 0x0000ffff) | (( n & 0xffff0000) << 16); n = ( n & 0x000000ff) | (( n & 0x0000ff00) << 8); n = ( n & 0x000f000f) | (( n & 0x00f000f0) << 4); n = ( n & 0x03030303) | (( n & 0x0c0c0c0c) << 2); n = ( n & 0x11111111) | (( n & 0x22222222) << 1); } // Next Largest Power of 2 // Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm // that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with // the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next // largest power of 2. For a 32-bit value: inline_ udword nlpo2(udword x) { x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return x+1; } //! Test to see if a number is an exact power of two (from Steve Baker's Cute Code Collection) inline_ bool IsPowerOfTwo(udword n) { return ((n&(n-1))==0); } //! Zero the least significant '1' bit in a word. (from Steve Baker's Cute Code Collection) inline_ void ZeroLeastSetBit(udword& n) { n&=(n-1); } //! Set the least significant N bits in a word. (from Steve Baker's Cute Code Collection) inline_ void SetLeastNBits(udword& x, udword n) { x|=~(~0<> 31; return (x^y)-y; } //!< Alternative min function inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); } // Determine if one of the bytes in a 4 byte word is zero inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); } // To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0 inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); } // inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); } // Most Significant 1 Bit // Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set) // can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits. // This process yields a bit vector with the same most significant 1 as x, but all 1's below it. // Bitwise AND of the original value with the complement of the "folded" value shifted down by one // yields the most significant bit. For a 32-bit value: inline_ udword msb32(udword x) { x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return (x & ~(x >> 1)); } /* "Just call it repeatedly with various input values and always with the same variable as "memory". The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1 does no filtering at all. I seem to recall from college that this is called an IIR (Infinite Impulse Response) filter. As opposed to the more typical FIR (Finite Impulse Response). Also, I'd say that you can make more intelligent and interesting filters than this, for example filters that remove wrong responses from the mouse because it's being moved too fast. You'd want such a filter to be applied before this one, of course." (JCAB on Flipcode) */ inline_ float FeedbackFilter(float val, float& memory, float sharpness) { ASSERT(sharpness>=0.0f && sharpness<=1.0f && "Invalid sharpness value in feedback filter"); if(sharpness<0.0f) sharpness = 0.0f; else if(sharpness>1.0f) sharpness = 1.0f; return memory = val * sharpness + memory * (1.0f - sharpness); } //! If you can guarantee that your input domain (i.e. value of x) is slightly //! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the //! following code to clamp the resulting value into [-32768,+32767] range: inline_ int ClampToInt16(int x) { // ASSERT(abs(x) < (int)((1<<31u)-32767)); int delta = 32767 - x; x += (delta>>31) & delta; delta = x + 32768; x -= (delta>>31) & delta; return x; } // Generic functions template inline_ void TSwap(Type& a, Type& b) { const Type c = a; a = b; b = c; } template inline_ Type TClamp(const Type& x, const Type& lo, const Type& hi) { return ((xhi) ? hi : x); } template inline_ void TSort(Type& a, Type& b) { if(a>b) TSwap(a, b); } template inline_ void TSort(Type& a, Type& b, Type& c) { if(a>b) TSwap(a, b); if(b>c) TSwap(b, c); if(a>b) TSwap(a, b); if(b>c) TSwap(b, c); } // Prevent nasty user-manipulations (strategy borrowed from Charles Bloom) // #define PREVENT_COPY(curclass) void operator = (const curclass& object) { ASSERT(!"Bad use of operator ="); } // ... actually this is better ! #define PREVENT_COPY(cur_class) private: cur_class(const cur_class& object); cur_class& operator=(const cur_class& object); //! TO BE DOCUMENTED #define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member) //! TO BE DOCUMENTED #ifndef ARRAYSIZE #define ARRAYSIZE(p) (sizeof(p)/sizeof((p)[0])) #endif // #ifndef ARRAYSIZE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns the alignment of the input address. * \fn Alignment() * \param address [in] address to check * \return the best alignment (e.g. 1 for odd addresses, etc) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FUNCTION ICECORE_API udword Alignment(udword address); #define IS_ALIGNED_2(x) ((x&1)==0) #define IS_ALIGNED_4(x) ((x&3)==0) #define IS_ALIGNED_8(x) ((x&7)==0) inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; } // Compute implicit coords from an index: // The idea is to get back 2D coords from a 1D index. // For example: // // 0 1 2 ... nbu-1 // nbu nbu+1 i ... // // We have i, we're looking for the equivalent (u=2, v=1) location. // i = u + v*nbu // <=> i/nbu = u/nbu + v // Since 0 <= u < nbu, u/nbu = 0 (integer) // Hence: v = i/nbu // Then we simply put it back in the original equation to compute u = i - v*nbu inline_ void Compute2DCoords(udword& u, udword& v, udword i, udword nbu) { v = i / nbu; u = i - (v * nbu); } // In 3D: i = u + v*nbu + w*nbu*nbv // <=> i/(nbu*nbv) = u/(nbu*nbv) + v/nbv + w // u/(nbu*nbv) is null since u/nbu was null already. // v/nbv is null as well for the same reason. // Hence w = i/(nbu*nbv) // Then we're left with a 2D problem: i' = i - w*nbu*nbv = u + v*nbu inline_ void Compute3DCoords(udword& u, udword& v, udword& w, udword i, udword nbu, udword nbu_nbv) { w = i / (nbu_nbv); Compute2DCoords(u, v, i - (w * nbu_nbv), nbu); } #endif // __ICEUTILS_H__ ode-0.14/OPCODE/Ice/Makefile.am0000644000000000000000000000205512635011627014415 0ustar rootrootAM_CPPFLAGS = -I$(top_srcdir)/OPCODE \ -I$(top_srcdir)/include \ -I$(top_builddir)/include noinst_LTLIBRARIES = libIce.la libIce_la_SOURCES = \ IceAABB.cpp IceAABB.h IceAxes.h \ IceBoundingSphere.h IceContainer.cpp IceContainer.h \ IceFPU.h IceHPoint.cpp IceHPoint.h \ IceIndexedTriangle.cpp IceIndexedTriangle.h IceLSS.h \ IceMatrix3x3.cpp IceMatrix3x3.h IceMatrix4x4.cpp \ IceMatrix4x4.h IceMemoryMacros.h IceOBB.cpp \ IceOBB.h IcePairs.h IcePlane.cpp \ IcePlane.h IcePoint.cpp IcePoint.h \ IcePreprocessor.h IceRandom.cpp IceRandom.h \ IceRay.cpp IceRay.h IceRevisitedRadix.cpp \ IceRevisitedRadix.h IceSegment.cpp IceSegment.h \ IceTriangle.cpp IceTriangle.h IceTriList.h \ IceTypes.h IceUtils.cpp IceUtils.h ode-0.14/OPCODE/Makefile.am0000644000000000000000000000415512635011627013720 0ustar rootrootEXTRA_DIST = COPYING \ ReadMe.txt \ README-ODE.txt \ TemporalCoherence.txt SUBDIRS = Ice noinst_LTLIBRARIES = libOPCODE.la AM_CPPFLAGS= -I$(top_srcdir)/include \ -I$(top_builddir)/include libOPCODE_la_SOURCES = OPC_AABBCollider.cpp OPC_AABBCollider.h \ OPC_AABBTree.cpp OPC_AABBTree.h \ OPC_BaseModel.cpp OPC_BaseModel.h \ OPC_Collider.cpp OPC_Collider.h \ OPC_Common.cpp OPC_Common.h \ OPC_HybridModel.cpp OPC_HybridModel.h \ OPC_LSSCollider.cpp OPC_LSSCollider.h \ OPC_MeshInterface.cpp OPC_MeshInterface.h \ OPC_Model.cpp OPC_Model.h \ OPC_OBBCollider.cpp OPC_OBBCollider.h \ Opcode.cpp Opcode.h \ OPC_OptimizedTree.cpp OPC_OptimizedTree.h \ OPC_Picking.cpp OPC_Picking.h \ OPC_PlanesCollider.cpp OPC_PlanesCollider.h \ OPC_RayCollider.cpp OPC_RayCollider.h \ OPC_SphereCollider.cpp OPC_SphereCollider.h \ OPC_TreeBuilders.cpp OPC_TreeBuilders.h \ OPC_TreeCollider.cpp OPC_TreeCollider.h \ OPC_VolumeCollider.cpp OPC_VolumeCollider.h \ OPC_Settings.h \ OPC_SphereAABBOverlap.h \ OPC_BoxBoxOverlap.h \ OPC_SphereTriOverlap.h \ OPC_PlanesAABBOverlap.h \ OPC_TriBoxOverlap.h \ OPC_IceHook.h \ OPC_PlanesTriOverlap.h \ OPC_TriTriOverlap.h \ OPC_LSSAABBOverlap.h \ OPC_RayAABBOverlap.h \ Stdafx.h \ OPC_LSSTriOverlap.h \ OPC_RayTriOverlap.h ode-0.14/OPCODE/OPC_AABBCollider.cpp0000644000000000000000000006266512635011627015246 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for an AABB collider. * \file OPC_AABBCollider.cpp * \author Pierre Terdiman * \date January, 1st, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains an AABB-vs-tree collider. * * \class AABBCollider * \author Pierre Terdiman * \version 1.3 * \date January, 1st, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; #include "OPC_BoxBoxOverlap.h" #include "OPC_TriBoxOverlap.h" #define SET_CONTACT(prim_index, flag) \ /* Set contact status */ \ mFlags |= flag; \ mTouchedPrimitives->Add(udword(prim_index)); //! AABB-triangle test #define AABB_PRIM(prim_index, flag) \ /* Request vertices from the app */ \ VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \ mLeafVerts[0] = *VP.Vertex[0]; \ mLeafVerts[1] = *VP.Vertex[1]; \ mLeafVerts[2] = *VP.Vertex[2]; \ /* Perform triangle-box overlap test */ \ if(TriBoxOverlap()) \ { \ SET_CONTACT(prim_index, flag) \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBCollider::AABBCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBCollider::~AABBCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] a box cache * \param box [in] collision AABB in world space * \param model [in] Opcode model to collide with * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const Model& model) { // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, box)) return true; if(!model.HasLeafNodes()) { if(model.IsQuantized()) { const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a collision query : * - reset stats & contact status * - check temporal coherence * * \param cache [in/out] a box cache * \param box [in] AABB in world space * \return TRUE if we can return immediately */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL AABBCollider::InitQuery(AABBCache& cache, const CollisionAABB& box) { // 1) Call the base method VolumeCollider::InitQuery(); // 2) Keep track of the query box mBox = box; // 3) Setup destination pointer mTouchedPrimitives = &cache.TouchedPrimitives; // 4) Special case: 1-triangle meshes [Opcode 1.3] if(mCurrentModel && mCurrentModel->HasSingleNode()) { if(!SkipPrimitiveTests()) { // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. mTouchedPrimitives->Reset(); // Perform overlap test between the unique triangle and the box (and set contact status if needed) AABB_PRIM(udword(0), OPC_CONTACT) // Return immediately regardless of status return TRUE; } } // 5) Check temporal coherence : if(TemporalCoherenceEnabled()) { // Here we use temporal coherence // => check results from previous frame before performing the collision query if(FirstContactEnabled()) { // We're only interested in the first contact found => test the unique previously touched face if(mTouchedPrimitives->GetNbEntries()) { // Get index of previously touched face = the first entry in the array udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); // Then reset the array: // - if the overlap test below is successful, the index we'll get added back anyway // - if it isn't, then the array should be reset anyway for the normal query mTouchedPrimitives->Reset(); // Perform overlap test between the cached triangle and the box (and set contact status if needed) AABB_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) // Return immediately if possible if(GetContactStatus()) return TRUE; } // else no face has been touched during previous query // => we'll have to perform a normal query } else { // We're interested in all contacts =>test the new real box N(ew) against the previous fat box P(revious): if(IsCacheValid(cache) && mBox.IsInside(cache.FatBox)) { // - if N is included in P, return previous list // => we simply leave the list (mTouchedFaces) unchanged // Set contact status if needed if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; // In any case we don't need to do a query return TRUE; } else { // - else do the query using a fat N // Reset cache since we'll about to perform a real query mTouchedPrimitives->Reset(); // Make a fat box so that coherence will work for subsequent frames mBox.mExtents *= cache.FatCoeff; // Update cache with query data (signature for cached faces) cache.FatBox = mBox; } } } else { // Here we don't use temporal coherence => do a normal query mTouchedPrimitives->Reset(); } // 5) Precompute min & max bounds if needed mMin = box.mCenter - box.mExtents; mMax = box.mCenter + box.mExtents; return FALSE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Collision query for vanilla AABB trees. * \param cache [in/out] a box cache * \param box [in] collision AABB in world space * \param tree [in] AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const AABBTree* tree) { // This is typically called for a scene tree, full of -AABBs-, not full of triangles. // So we don't really have "primitives" to deal with. Hence it doesn't work with // "FirstContact" + "TemporalCoherence". ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); // Checkings if(!tree) return false; // Init collision query if(InitQuery(cache, box)) return true; // Perform collision query _Collide(tree); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the AABB completely contains the box. In which case we can end the query sooner. * \param bc [in] box center * \param be [in] box extents * \return true if the AABB contains the whole box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL AABBCollider::AABBContainsBox(const Point& bc, const Point& be) { if(mMin.x > bc.x - be.x) return FALSE; if(mMin.y > bc.y - be.y) return FALSE; if(mMin.z > bc.z - be.z) return FALSE; if(mMax.x < bc.x + be.x) return FALSE; if(mMax.y < bc.y + be.y) return FALSE; if(mMax.z < bc.z + be.z) return FALSE; return TRUE; } #define TEST_BOX_IN_AABB(center, extents) \ if(AABBContainsBox(center, extents)) \ { \ /* Set contact status */ \ mFlags |= OPC_CONTACT; \ _Dump(node); \ return; \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_Collide(const AABBCollisionNode* node) { // Perform AABB-AABB overlap test if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { AABB_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) { // Perform AABB-AABB overlap test if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_Collide(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform AABB-AABB overlap test if(!AABBAABBOverlap(Extents, Center)) return; TEST_BOX_IN_AABB(Center, Extents) if(node->IsLeaf()) { AABB_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform AABB-AABB overlap test if(!AABBAABBOverlap(Extents, Center)) return; TEST_BOX_IN_AABB(Center, Extents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_Collide(const AABBNoLeafNode* node) { // Perform AABB-AABB overlap test if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) { // Perform AABB-AABB overlap test if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_Collide(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform AABB-AABB overlap test if(!AABBAABBOverlap(Extents, Center)) return; TEST_BOX_IN_AABB(Center, Extents) if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform AABB-AABB overlap test if(!AABBAABBOverlap(Extents, Center)) return; TEST_BOX_IN_AABB(Center, Extents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for vanilla AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBCollider::_Collide(const AABBTreeNode* node) { // Perform AABB-AABB overlap test Point Center, Extents; node->GetAABB()->GetCenter(Center); node->GetAABB()->GetExtents(Extents); if(!AABBAABBOverlap(Center, Extents)) return; if(node->IsLeaf() || AABBContainsBox(Center, Extents)) { mFlags |= OPC_CONTACT; mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives()); } else { _Collide(node->GetPos()); _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridAABBCollider::HybridAABBCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridAABBCollider::~HybridAABBCollider() { } bool HybridAABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const HybridModel& model) { // We don't want primitive tests here! mFlags |= OPC_NO_PRIMITIVE_TESTS; // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, box)) return true; // Special case for 1-leaf trees if(mCurrentModel && mCurrentModel->HasSingleNode()) { // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles udword Nb = mIMesh->GetNbTriangles(); // Loop through all triangles for(udword i=0;imCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } // We only have a list of boxes so far if(GetContactStatus()) { // Reset contact status, since it currently only reflects collisions with leaf boxes Collider::InitQuery(); // Change dest container so that we can use built-in overlap tests and get collided primitives cache.TouchedPrimitives.Reset(); mTouchedPrimitives = &cache.TouchedPrimitives; // Read touched leaf boxes udword Nb = mTouchedBoxes.GetNbEntries(); const udword* Touched = mTouchedBoxes.GetEntries(); const LeafTriangles* LT = model.GetLeafTriangles(); const udword* Indices = model.GetIndices(); // Loop through touched leaves while(Nb--) { const LeafTriangles& CurrentLeaf = LT[*Touched++]; // Each leaf box has a set of triangles udword NbTris = CurrentLeaf.GetNbTriangles(); if(Indices) { const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = *T++; AABB_PRIM(TriangleIndex, OPC_CONTACT) } } else { udword BaseIndex = CurrentLeaf.GetTriangleIndex(); // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = BaseIndex++; AABB_PRIM(TriangleIndex, OPC_CONTACT) } } } } return true; } ode-0.14/OPCODE/OPC_AABBCollider.h0000644000000000000000000001052712635011627014701 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for an AABB collider. * \file OPC_AABBCollider.h * \author Pierre Terdiman * \date January, 1st, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_AABBCOLLIDER_H__ #define __OPC_AABBCOLLIDER_H__ struct OPCODE_API AABBCache : VolumeCache { AABBCache() : FatCoeff(1.1f) { FatBox.mCenter.Zero(); FatBox.mExtents.Zero(); } // Cached faces signature CollisionAABB FatBox; //!< Box used when performing the query resulting in cached faces // User settings float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere }; class OPCODE_API AABBCollider : public VolumeCollider { public: // Constructor / Destructor AABBCollider(); virtual ~AABBCollider(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] a box cache * \param box [in] collision AABB in world space * \param model [in] Opcode model to collide with * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Collide(AABBCache& cache, const CollisionAABB& box, const Model& model); // bool Collide(AABBCache& cache, const CollisionAABB& box, const AABBTree* tree); protected: CollisionAABB mBox; //!< Query box in (center, extents) form Point mMin; //!< Query box min point Point mMax; //!< Query box max point // Leaf description Point mLeafVerts[3]; //!< Triangle vertices // Internal methods void _Collide(const AABBCollisionNode* node); void _Collide(const AABBNoLeafNode* node); void _Collide(const AABBQuantizedNode* node); void _Collide(const AABBQuantizedNoLeafNode* node); void _Collide(const AABBTreeNode* node); void _CollideNoPrimitiveTest(const AABBCollisionNode* node); void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); // Overlap tests inline_ BOOL AABBContainsBox(const Point& bc, const Point& be); inline_ BOOL AABBAABBOverlap(const Point& b, const Point& Pb); inline_ BOOL TriBoxOverlap(); // Init methods BOOL InitQuery(AABBCache& cache, const CollisionAABB& box); }; class OPCODE_API HybridAABBCollider : public AABBCollider { public: // Constructor / Destructor HybridAABBCollider(); virtual ~HybridAABBCollider(); bool Collide(AABBCache& cache, const CollisionAABB& box, const HybridModel& model); protected: Container mTouchedBoxes; }; #endif // __OPC_AABBCOLLIDER_H__ ode-0.14/OPCODE/OPC_AABBTree.cpp0000644000000000000000000005330712635011627014401 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a versatile AABB tree. * \file OPC_AABBTree.cpp * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a generic AABB tree node. * * \class AABBTreeNode * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a generic AABB tree. * This is a vanilla AABB tree, without any particular optimization. It contains anonymous references to * user-provided primitives, which can theoretically be anything - triangles, boxes, etc. Each primitive * is surrounded by an AABB, regardless of the primitive's nature. When the primitive is a triangle, the * resulting tree can be converted into an optimized tree. If the primitive is a box, the resulting tree * can be used for culling - VFC or occlusion -, assuming you cull on a mesh-by-mesh basis (modern way). * * \class AABBTree * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBTreeNode::AABBTreeNode() : mPos (null), #ifndef OPC_NO_NEG_VANILLA_TREE mNeg (null), #endif mNodePrimitives (null), mNbPrimitives (0) { #ifdef OPC_USE_TREE_COHERENCE mBitmask = 0; #endif } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBTreeNode::~AABBTreeNode() { // Opcode 1.3: const AABBTreeNode* Pos = GetPos(); #ifndef OPC_NO_NEG_VANILLA_TREE const AABBTreeNode* Neg = GetNeg(); if(!(mPos&1)) DELETESINGLE(Pos); if(!(mNeg&1)) DELETESINGLE(Neg); #else if(!(mPos&1)) DELETEARRAY(Pos); #endif mNodePrimitives = null; // This was just a shortcut to the global list => no release mNbPrimitives = 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Splits the node along a given axis. * The list of indices is reorganized according to the split values. * \param axis [in] splitting axis index * \param builder [in] the tree builder * \return the number of primitives assigned to the first child * \warning this method reorganizes the internal list of primitives */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword AABBTreeNode::Split(udword axis, AABBTreeBuilder* builder) { // Get node split value float SplitValue = builder->GetSplittingValue(mNodePrimitives, mNbPrimitives, mBV, axis); udword NbPos = 0; // Loop through all node-related primitives. Their indices range from mNodePrimitives[0] to mNodePrimitives[mNbPrimitives-1]. // Those indices map the global list in the tree builder. for(udword i=0;iGetSplittingValue(Index, axis); // Reorganize the list of indices in this order: positive - negative. if(PrimitiveValue > SplitValue) { // Swap entries udword Tmp = mNodePrimitives[i]; mNodePrimitives[i] = mNodePrimitives[NbPos]; mNodePrimitives[NbPos] = Tmp; // Count primitives assigned to positive space NbPos++; } } return NbPos; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Subdivides the node. * * N * / \ * / \ * N/2 N/2 * / \ / \ * N/4 N/4 N/4 N/4 * (etc) * * A well-balanced tree should have a O(log n) depth. * A degenerate tree would have a O(n) depth. * Note a perfectly-balanced tree is not well-suited to collision detection anyway. * * \param builder [in] the tree builder * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeNode::Subdivide(AABBTreeBuilder* builder) { // Checkings if(!builder) return false; // Stop subdividing if we reach a leaf node. This is always performed here, // else we could end in trouble if user overrides this. if(mNbPrimitives==1) return true; // Let the user validate the subdivision if(!builder->ValidateSubdivision(mNodePrimitives, mNbPrimitives, mBV)) return true; bool ValidSplit = true; // Optimism... udword NbPos; if(builder->mSettings.mRules & SPLIT_LARGEST_AXIS) { // Find the largest axis to split along Point Extents; mBV.GetExtents(Extents); // Box extents udword Axis = Extents.LargestAxis(); // Index of largest axis // Split along the axis NbPos = Split(Axis, builder); // Check split validity if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false; } else if(builder->mSettings.mRules & SPLIT_SPLATTER_POINTS) { // Compute the means Point Means(0.0f, 0.0f, 0.0f); for(udword i=0;iGetSplittingValues(Index); } Means/=float(mNbPrimitives); // Compute variances Point Vars(0.0f, 0.0f, 0.0f); for(udword i=0;iGetSplittingValues(Index); Point Delta = Center - Means; Vars += Delta * Delta; } Vars/=float(mNbPrimitives-1); // Choose axis with greatest variance udword Axis = Vars.LargestAxis(); // Split along the axis NbPos = Split(Axis, builder); // Check split validity if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false; } else if(builder->mSettings.mRules & SPLIT_BALANCED) { // Test 3 axis, take the best float Results[3]; NbPos = Split(0, builder); Results[0] = float(NbPos)/float(mNbPrimitives); NbPos = Split(1, builder); Results[1] = float(NbPos)/float(mNbPrimitives); NbPos = Split(2, builder); Results[2] = float(NbPos)/float(mNbPrimitives); Results[0]-=0.5f; Results[0]*=Results[0]; Results[1]-=0.5f; Results[1]*=Results[1]; Results[2]-=0.5f; Results[2]*=Results[2]; udword Min=0; if(Results[1]mSettings.mRules & SPLIT_BEST_AXIS) { // Test largest, then middle, then smallest axis... // Sort axis Point Extents; mBV.GetExtents(Extents); // Box extents udword SortedAxis[] = { 0, 1, 2 }; float* Keys = (float*)&Extents.x; for(udword j=0;j<3;j++) { for(udword i=0;i<2;i++) { if(Keys[SortedAxis[i]]mSettings.mRules & SPLIT_FIFTY) { // Don't even bother splitting (mainly a performance test) NbPos = mNbPrimitives>>1; } else return false; // Unknown splitting rules // Check the subdivision has been successful if(!ValidSplit) { // Here, all boxes lie in the same sub-space. Two strategies: // - if the tree *must* be complete, make an arbitrary 50-50 split // - else stop subdividing // if(builder->mSettings.mRules&SPLIT_COMPLETE) if(builder->mSettings.mLimit==1) { builder->IncreaseNbInvalidSplits(); NbPos = mNbPrimitives>>1; } else return true; } // Now create children and assign their pointers. if(builder->mNodeBase) { // We use a pre-allocated linear pool for complete trees [Opcode 1.3] AABBTreeNode* Pool = (AABBTreeNode*)builder->mNodeBase; udword Count = builder->GetCount() - 1; // Count begins to 1... // Set last bit to tell it shouldn't be freed ### pretty ugly, find a better way. Maybe one bit in mNbPrimitives ASSERT(!(udword(&Pool[Count+0])&1)); ASSERT(!(udword(&Pool[Count+1])&1)); mPos = size_t(&Pool[Count+0])|1; #ifndef OPC_NO_NEG_VANILLA_TREE mNeg = size_t(&Pool[Count+1])|1; #endif } else { // Non-complete trees and/or Opcode 1.2 allocate nodes on-the-fly #ifndef OPC_NO_NEG_VANILLA_TREE mPos = (size_t)new AABBTreeNode; CHECKALLOC(mPos); mNeg = (size_t)new AABBTreeNode; CHECKALLOC(mNeg); #else AABBTreeNode* PosNeg = new AABBTreeNode[2]; CHECKALLOC(PosNeg); mPos = (size_t)PosNeg; #endif } // Update stats builder->IncreaseCount(2); // Assign children AABBTreeNode* Pos = (AABBTreeNode*)GetPos(); AABBTreeNode* Neg = (AABBTreeNode*)GetNeg(); Pos->mNodePrimitives = &mNodePrimitives[0]; Pos->mNbPrimitives = NbPos; Neg->mNodePrimitives = &mNodePrimitives[NbPos]; Neg->mNbPrimitives = mNbPrimitives - NbPos; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive hierarchy building in a top-down fashion. * \param builder [in] the tree builder */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeNode::_BuildHierarchy(AABBTreeBuilder* builder) { // 1) Compute the global box for current node. The box is stored in mBV. builder->ComputeGlobalBox(mNodePrimitives, mNbPrimitives, mBV); // 2) Subdivide current node Subdivide(builder); // 3) Recurse AABBTreeNode* Pos = (AABBTreeNode*)GetPos(); AABBTreeNode* Neg = (AABBTreeNode*)GetNeg(); if(Pos) Pos->_BuildHierarchy(builder); if(Neg) Neg->_BuildHierarchy(builder); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the tree (top-down). * \param builder [in] the tree builder */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeNode::_Refit(AABBTreeBuilder* builder) { // 1) Recompute the new global box for current node builder->ComputeGlobalBox(mNodePrimitives, mNbPrimitives, mBV); // 2) Recurse AABBTreeNode* Pos = (AABBTreeNode*)GetPos(); AABBTreeNode* Neg = (AABBTreeNode*)GetNeg(); if(Pos) Pos->_Refit(builder); if(Neg) Neg->_Refit(builder); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBTree::AABBTree() : mIndices(null), mPool(null), mTotalNbNodes(0) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBTree::~AABBTree() { Release(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Releases the tree. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTree::Release() { DELETEARRAY(mPool); DELETEARRAY(mIndices); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds a generic AABB tree from a tree builder. * \param builder [in] the tree builder * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTree::Build(AABBTreeBuilder* builder) { // Checkings if(!builder || !builder->mNbPrimitives) return false; // Release previous tree Release(); // Init stats builder->SetCount(1); builder->SetNbInvalidSplits(0); // Initialize indices. This list will be modified during build. mIndices = new dTriIndex[builder->mNbPrimitives]; CHECKALLOC(mIndices); // Identity permutation for(udword i=0;imNbPrimitives;i++) mIndices[i] = i; // Setup initial node. Here we have a complete permutation of the app's primitives. mNodePrimitives = mIndices; mNbPrimitives = builder->mNbPrimitives; // Use a linear array for complete trees (since we can predict the final number of nodes) [Opcode 1.3] // if(builder->mRules&SPLIT_COMPLETE) if(builder->mSettings.mLimit==1) { // Allocate a pool of nodes mPool = new AABBTreeNode[builder->mNbPrimitives*2 - 1]; builder->mNodeBase = mPool; // ### ugly ! } // Build the hierarchy _BuildHierarchy(builder); // Get back total number of nodes mTotalNbNodes = builder->GetCount(); // For complete trees, check the correct number of nodes has been created [Opcode 1.3] if(mPool) ASSERT(mTotalNbNodes==builder->mNbPrimitives*2 - 1); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the depth of the tree. * A well-balanced tree should have a log(n) depth. A degenerate tree O(n) depth. * \return depth of the tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword AABBTree::ComputeDepth() const { return Walk(null, null); // Use the walking code without callback } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Walks the tree, calling the user back for each node. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword AABBTree::Walk(WalkingCallback callback, void* user_data) const { // Call it without callback to compute max depth udword MaxDepth = 0; udword CurrentDepth = 0; struct Local { static void _Walk(const AABBTreeNode* current_node, udword& max_depth, udword& current_depth, WalkingCallback callback, void* user_data) { // Checkings if(!current_node) return; // Entering a new node => increase depth current_depth++; // Keep track of max depth if(current_depth>max_depth) max_depth = current_depth; // Callback if(callback && !(callback)(current_node, current_depth, user_data)) return; // Recurse if(current_node->GetPos()) { _Walk(current_node->GetPos(), max_depth, current_depth, callback, user_data); current_depth--; } if(current_node->GetNeg()) { _Walk(current_node->GetNeg(), max_depth, current_depth, callback, user_data); current_depth--; } } }; Local::_Walk(this, MaxDepth, CurrentDepth, callback, user_data); return MaxDepth; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the tree in a top-down way. * \param builder [in] the tree builder */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTree::Refit(AABBTreeBuilder* builder) { if(!builder) return false; _Refit(builder); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the tree in a bottom-up way. * \param builder [in] the tree builder */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTree::Refit2(AABBTreeBuilder* builder) { // Checkings if(!builder) return false; ASSERT(mPool); // Bottom-up update Point Min,Max; Point Min_,Max_; udword Index = mTotalNbNodes; while(Index--) { AABBTreeNode& Current = mPool[Index]; if(Current.IsLeaf()) { builder->ComputeGlobalBox(Current.GetPrimitives(), Current.GetNbPrimitives(), *(AABB*)Current.GetAABB()); } else { Current.GetPos()->GetAABB()->GetMin(Min); Current.GetPos()->GetAABB()->GetMax(Max); Current.GetNeg()->GetAABB()->GetMin(Min_); Current.GetNeg()->GetAABB()->GetMax(Max_); Min.Min(Min_); Max.Max(Max_); ((AABB*)Current.GetAABB())->SetMinMax(Min, Max); } } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the number of bytes used by the tree. * \return number of bytes used */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword AABBTree::GetUsedBytes() const { udword TotalSize = mTotalNbNodes*GetNodeSize(); if(mIndices) TotalSize+=mNbPrimitives*sizeof(udword); return TotalSize; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the tree is a complete tree or not. * A complete tree is made of 2*N-1 nodes, where N is the number of primitives in the tree. * \return true for complete trees */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTree::IsComplete() const { return (GetNbNodes()==GetNbPrimitives()*2-1); } ode-0.14/OPCODE/OPC_AABBTree.h0000644000000000000000000001545712635011627014052 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a versatile AABB tree. * \file OPC_AABBTree.h * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_AABBTREE_H__ #define __OPC_AABBTREE_H__ #ifdef OPC_NO_NEG_VANILLA_TREE //! TO BE DOCUMENTED #define IMPLEMENT_TREE(base_class, volume) \ public: \ /* Constructor / Destructor */ \ base_class(); \ ~base_class(); \ /* Data access */ \ inline_ const volume* Get##volume() const { return &mBV; } \ /* Clear the last bit */ \ inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \ inline_ const base_class* GetNeg() const { const base_class* P = GetPos(); return P ? P+1 : null;} \ \ /* We don't need to test both nodes since we can't have one without the other */ \ inline_ bool IsLeaf() const { return !GetPos(); } \ \ /* Stats */ \ inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ protected: \ /* Tree-independent data */ \ /* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \ /* Whatever happens we need the two children and the enclosing volume.*/ \ volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \ size_t mPos; /* "Positive" & "Negative" children */ #else //! TO BE DOCUMENTED #define IMPLEMENT_TREE(base_class, volume) \ public: \ /* Constructor / Destructor */ \ base_class(); \ ~base_class(); \ /* Data access */ \ inline_ const volume* Get##volume() const { return &mBV; } \ /* Clear the last bit */ \ inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \ inline_ const base_class* GetNeg() const { return (const base_class*)(mNeg&~1); } \ \ /* inline_ bool IsLeaf() const { return (!GetPos() && !GetNeg()); } */ \ /* We don't need to test both nodes since we can't have one without the other */ \ inline_ bool IsLeaf() const { return !GetPos(); } \ \ /* Stats */ \ inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ protected: \ /* Tree-independent data */ \ /* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \ /* Whatever happens we need the two children and the enclosing volume.*/ \ volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \ size_t mPos; /* "Positive" child */ \ size_t mNeg; /* "Negative" child */ #endif typedef void (*CullingCallback) (udword nb_primitives, udword* node_primitives, BOOL need_clipping, void* user_data); class OPCODE_API AABBTreeNode { IMPLEMENT_TREE(AABBTreeNode, AABB) public: // Data access inline_ const dTriIndex* GetPrimitives() const { return mNodePrimitives; } inline_ udword GetNbPrimitives() const { return mNbPrimitives; } protected: // Tree-dependent data dTriIndex* mNodePrimitives; //!< Node-related primitives (shortcut to a position in mIndices below) udword mNbPrimitives; //!< Number of primitives for this node // Internal methods udword Split(udword axis, AABBTreeBuilder* builder); bool Subdivide(AABBTreeBuilder* builder); void _BuildHierarchy(AABBTreeBuilder* builder); void _Refit(AABBTreeBuilder* builder); }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * User-callback, called for each node by the walking code. * \param current [in] current node * \param depth [in] current node's depth * \param user_data [in] user-defined data * \return true to recurse through children, else false to bypass them */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// typedef bool (*WalkingCallback) (const AABBTreeNode* current, udword depth, void* user_data); class OPCODE_API AABBTree : public AABBTreeNode { public: // Constructor / Destructor AABBTree(); ~AABBTree(); // Build bool Build(AABBTreeBuilder* builder); void Release(); // Data access inline_ const dTriIndex* GetIndices() const { return mIndices; } //!< Catch the indices inline_ udword GetNbNodes() const { return mTotalNbNodes; } //!< Catch the number of nodes // Infos bool IsComplete() const; // Stats udword ComputeDepth() const; udword GetUsedBytes() const; udword Walk(WalkingCallback callback, void* user_data) const; bool Refit(AABBTreeBuilder* builder); bool Refit2(AABBTreeBuilder* builder); private: dTriIndex* mIndices; //!< Indices in the app list. Indices are reorganized during build (permutation). AABBTreeNode* mPool; //!< Linear pool of nodes for complete trees. Null otherwise. [Opcode 1.3] // Stats udword mTotalNbNodes; //!< Number of nodes in the tree. }; #endif // __OPC_AABBTREE_H__ ode-0.14/OPCODE/OPC_BaseModel.cpp0000644000000000000000000001413112635011627014717 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains base model interface. * \file OPC_BaseModel.cpp * \author Pierre Terdiman * \date May, 18, 2003 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * The base class for collision models. * * \class BaseModel * \author Pierre Terdiman * \version 1.3 * \date May, 18, 2003 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// OPCODECREATE::OPCODECREATE() { mIMesh = null; mSettings.mRules = SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER; mSettings.mLimit = 1; // Mandatory for complete trees mNoLeaf = true; mQuantized = true; #ifdef __MESHMERIZER_H__ mCollisionHull = false; #endif // __MESHMERIZER_H__ mKeepOriginal = false; mCanRemap = false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BaseModel::BaseModel() : mIMesh(null), mModelCode(0), mSource(null), mTree(null) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BaseModel::~BaseModel() { ReleaseBase(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Releases everything. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void BaseModel::ReleaseBase() { DELETESINGLE(mSource); DELETESINGLE(mTree); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Creates an optimized tree according to user-settings, and setups mModelCode. * \param no_leaf [in] true for "no leaf" tree * \param quantized [in] true for quantized tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool BaseModel::CreateTree(bool no_leaf, bool quantized) { DELETESINGLE(mTree); // Setup model code if(no_leaf) mModelCode |= OPC_NO_LEAF; else mModelCode &= ~OPC_NO_LEAF; if(quantized) mModelCode |= OPC_QUANTIZED; else mModelCode &= ~OPC_QUANTIZED; // Create the correct class if(mModelCode & OPC_NO_LEAF) { if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedNoLeafTree; else mTree = new AABBNoLeafTree; } else { if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedTree; else mTree = new AABBCollisionTree; } CHECKALLOC(mTree); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the collision model. This can be used to handle dynamic meshes. Usage is: * 1. modify your mesh vertices (keep the topology constant!) * 2. refit the tree (call this method) * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool BaseModel::Refit() { // Refit the optimized tree return mTree->Refit(mIMesh); // Old code kept for reference : refit the source tree then rebuild ! // if(!mSource) return false; // // Ouch... // mSource->Refit(&mTB); // // Ouch... // return mTree->Build(mSource); } ode-0.14/OPCODE/OPC_BaseModel.h0000644000000000000000000002445412635011627014375 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains base model interface. * \file OPC_BaseModel.h * \author Pierre Terdiman * \date May, 18, 2003 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_BASEMODEL_H__ #define __OPC_BASEMODEL_H__ //! Model creation structure struct OPCODE_API OPCODECREATE { //! Constructor OPCODECREATE(); MeshInterface* mIMesh; //!< Mesh interface (access to triangles & vertices) (*) BuildSettings mSettings; //!< Builder's settings bool mNoLeaf; //!< true => discard leaf nodes (else use a normal tree) bool mQuantized; //!< true => quantize the tree (else use a normal tree) #ifdef __MESHMERIZER_H__ bool mCollisionHull; //!< true => use convex hull + GJK #endif // __MESHMERIZER_H__ bool mKeepOriginal; //!< true => keep a copy of the original tree (debug purpose) bool mCanRemap; //!< true => allows OPCODE to reorganize client arrays // (*) This pointer is saved internally and used by OPCODE until collision structures are released, // so beware of the object's lifetime. }; enum ModelFlag { OPC_QUANTIZED = (1<<0), //!< Compressed/uncompressed tree OPC_NO_LEAF = (1<<1), //!< Leaf/NoLeaf tree OPC_SINGLE_NODE = (1<<2) //!< Special case for 1-node models }; class OPCODE_API BaseModel { public: // Constructor/Destructor BaseModel(); virtual ~BaseModel(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds a collision model. * \param create [in] model creation structure * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual bool Build(const OPCODECREATE& create) = 0; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of bytes used by the tree. * \return amount of bytes used */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual udword GetUsedBytes() const = 0; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the collision model. This can be used to handle dynamic meshes. Usage is: * 1. modify your mesh vertices (keep the topology constant!) * 2. refit the tree (call this method) * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual bool Refit(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the source tree. * \return generic tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const AABBTree* GetSourceTree() const { return mSource; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the tree. * \return the collision tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const AABBOptimizedTree* GetTree() const { return mTree; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the tree. * \return the collision tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ AABBOptimizedTree* GetTree() { return mTree; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of nodes in the tree. * Should be 2*N-1 for normal trees and N-1 for optimized ones. * \return number of nodes */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbNodes() const { return mTree->GetNbNodes(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks whether the tree has leaf nodes or not. * \return true if the tree has leaf nodes (normal tree), else false (optimized tree) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL HasLeafNodes() const { return !(mModelCode & OPC_NO_LEAF); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks whether the tree is quantized or not. * \return true if the tree is quantized */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL IsQuantized() const { return mModelCode & OPC_QUANTIZED; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks whether the model has a single node or not. This special case must be handled separately. * \return true if the model has only 1 node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL HasSingleNode() const { return mModelCode & OPC_SINGLE_NODE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the model's code. * \return model's code */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetModelCode() const { return mModelCode; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the mesh interface. * \return mesh interface */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const MeshInterface* GetMeshInterface() const { return mIMesh; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Sets the mesh interface. * \param imesh [in] mesh interface */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetMeshInterface(const MeshInterface* imesh) { mIMesh = imesh; } protected: const MeshInterface* mIMesh; //!< User-defined mesh interface udword mModelCode; //!< Model code = combination of ModelFlag(s) AABBTree* mSource; //!< Original source tree AABBOptimizedTree* mTree; //!< Optimized tree owned by the model // Internal methods void ReleaseBase(); bool CreateTree(bool no_leaf, bool quantized); }; #endif //__OPC_BASEMODEL_H__ ode-0.14/OPCODE/OPC_BoxBoxOverlap.h0000644000000000000000000001712012635011627015264 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * OBB-OBB overlap test using the separating axis theorem. * - original code by Gomez / Gamasutra (similar to Gottschalk's one in RAPID) * - optimized for AABB trees by computing the rotation matrix once (SOLID-fashion) * - the fabs matrix is precomputed as well and epsilon-tweaked (RAPID-style, we found this almost mandatory) * - Class III axes can be disabled... (SOLID & Intel fashion) * - ...or enabled to perform some profiling * - CPU comparisons used when appropriate * - lazy evaluation sometimes saves some work in case of early exits (unlike SOLID) * * \param ea [in] extents from box A * \param ca [in] center from box A * \param eb [in] extents from box B * \param cb [in] center from box B * \return true if boxes overlap */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL AABBTreeCollider::BoxBoxOverlap(const Point& ea, const Point& ca, const Point& eb, const Point& cb) { // Stats mNbBVBVTests++; float t,t2; // Class I : A's basis vectors float Tx = (mR1to0.m[0][0]*cb.x + mR1to0.m[1][0]*cb.y + mR1to0.m[2][0]*cb.z) + mT1to0.x - ca.x; t = ea.x + eb.x*mAR.m[0][0] + eb.y*mAR.m[1][0] + eb.z*mAR.m[2][0]; if(GREATER(Tx, t)) return FALSE; float Ty = (mR1to0.m[0][1]*cb.x + mR1to0.m[1][1]*cb.y + mR1to0.m[2][1]*cb.z) + mT1to0.y - ca.y; t = ea.y + eb.x*mAR.m[0][1] + eb.y*mAR.m[1][1] + eb.z*mAR.m[2][1]; if(GREATER(Ty, t)) return FALSE; float Tz = (mR1to0.m[0][2]*cb.x + mR1to0.m[1][2]*cb.y + mR1to0.m[2][2]*cb.z) + mT1to0.z - ca.z; t = ea.z + eb.x*mAR.m[0][2] + eb.y*mAR.m[1][2] + eb.z*mAR.m[2][2]; if(GREATER(Tz, t)) return FALSE; // Class II : B's basis vectors t = Tx*mR1to0.m[0][0] + Ty*mR1to0.m[0][1] + Tz*mR1to0.m[0][2]; t2 = ea.x*mAR.m[0][0] + ea.y*mAR.m[0][1] + ea.z*mAR.m[0][2] + eb.x; if(GREATER(t, t2)) return FALSE; t = Tx*mR1to0.m[1][0] + Ty*mR1to0.m[1][1] + Tz*mR1to0.m[1][2]; t2 = ea.x*mAR.m[1][0] + ea.y*mAR.m[1][1] + ea.z*mAR.m[1][2] + eb.y; if(GREATER(t, t2)) return FALSE; t = Tx*mR1to0.m[2][0] + Ty*mR1to0.m[2][1] + Tz*mR1to0.m[2][2]; t2 = ea.x*mAR.m[2][0] + ea.y*mAR.m[2][1] + ea.z*mAR.m[2][2] + eb.z; if(GREATER(t, t2)) return FALSE; // Class III : 9 cross products // Cool trick: always perform the full test for first level, regardless of settings. // That way pathological cases (such as the pencils scene) are quickly rejected anyway ! if(mFullBoxBoxTest || mNbBVBVTests==1) { t = Tz*mR1to0.m[0][1] - Ty*mR1to0.m[0][2]; t2 = ea.y*mAR.m[0][2] + ea.z*mAR.m[0][1] + eb.y*mAR.m[2][0] + eb.z*mAR.m[1][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B0 t = Tz*mR1to0.m[1][1] - Ty*mR1to0.m[1][2]; t2 = ea.y*mAR.m[1][2] + ea.z*mAR.m[1][1] + eb.x*mAR.m[2][0] + eb.z*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B1 t = Tz*mR1to0.m[2][1] - Ty*mR1to0.m[2][2]; t2 = ea.y*mAR.m[2][2] + ea.z*mAR.m[2][1] + eb.x*mAR.m[1][0] + eb.y*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B2 t = Tx*mR1to0.m[0][2] - Tz*mR1to0.m[0][0]; t2 = ea.x*mAR.m[0][2] + ea.z*mAR.m[0][0] + eb.y*mAR.m[2][1] + eb.z*mAR.m[1][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B0 t = Tx*mR1to0.m[1][2] - Tz*mR1to0.m[1][0]; t2 = ea.x*mAR.m[1][2] + ea.z*mAR.m[1][0] + eb.x*mAR.m[2][1] + eb.z*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B1 t = Tx*mR1to0.m[2][2] - Tz*mR1to0.m[2][0]; t2 = ea.x*mAR.m[2][2] + ea.z*mAR.m[2][0] + eb.x*mAR.m[1][1] + eb.y*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B2 t = Ty*mR1to0.m[0][0] - Tx*mR1to0.m[0][1]; t2 = ea.x*mAR.m[0][1] + ea.y*mAR.m[0][0] + eb.y*mAR.m[2][2] + eb.z*mAR.m[1][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B0 t = Ty*mR1to0.m[1][0] - Tx*mR1to0.m[1][1]; t2 = ea.x*mAR.m[1][1] + ea.y*mAR.m[1][0] + eb.x*mAR.m[2][2] + eb.z*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B1 t = Ty*mR1to0.m[2][0] - Tx*mR1to0.m[2][1]; t2 = ea.x*mAR.m[2][1] + ea.y*mAR.m[2][0] + eb.x*mAR.m[1][2] + eb.y*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B2 } return TRUE; } //! A dedicated version when one box is constant inline_ BOOL OBBCollider::BoxBoxOverlap(const Point& extents, const Point& center) { // Stats mNbVolumeBVTests++; float t,t2; // Class I : A's basis vectors float Tx = mTBoxToModel.x - center.x; t = extents.x + mBBx1; if(GREATER(Tx, t)) return FALSE; float Ty = mTBoxToModel.y - center.y; t = extents.y + mBBy1; if(GREATER(Ty, t)) return FALSE; float Tz = mTBoxToModel.z - center.z; t = extents.z + mBBz1; if(GREATER(Tz, t)) return FALSE; // Class II : B's basis vectors t = Tx*mRBoxToModel.m[0][0] + Ty*mRBoxToModel.m[0][1] + Tz*mRBoxToModel.m[0][2]; t2 = extents.x*mAR.m[0][0] + extents.y*mAR.m[0][1] + extents.z*mAR.m[0][2] + mBoxExtents.x; if(GREATER(t, t2)) return FALSE; t = Tx*mRBoxToModel.m[1][0] + Ty*mRBoxToModel.m[1][1] + Tz*mRBoxToModel.m[1][2]; t2 = extents.x*mAR.m[1][0] + extents.y*mAR.m[1][1] + extents.z*mAR.m[1][2] + mBoxExtents.y; if(GREATER(t, t2)) return FALSE; t = Tx*mRBoxToModel.m[2][0] + Ty*mRBoxToModel.m[2][1] + Tz*mRBoxToModel.m[2][2]; t2 = extents.x*mAR.m[2][0] + extents.y*mAR.m[2][1] + extents.z*mAR.m[2][2] + mBoxExtents.z; if(GREATER(t, t2)) return FALSE; // Class III : 9 cross products // Cool trick: always perform the full test for first level, regardless of settings. // That way pathological cases (such as the pencils scene) are quickly rejected anyway ! if(mFullBoxBoxTest || mNbVolumeBVTests==1) { t = Tz*mRBoxToModel.m[0][1] - Ty*mRBoxToModel.m[0][2]; t2 = extents.y*mAR.m[0][2] + extents.z*mAR.m[0][1] + mBB_1; if(GREATER(t, t2)) return FALSE; // L = A0 x B0 t = Tz*mRBoxToModel.m[1][1] - Ty*mRBoxToModel.m[1][2]; t2 = extents.y*mAR.m[1][2] + extents.z*mAR.m[1][1] + mBB_2; if(GREATER(t, t2)) return FALSE; // L = A0 x B1 t = Tz*mRBoxToModel.m[2][1] - Ty*mRBoxToModel.m[2][2]; t2 = extents.y*mAR.m[2][2] + extents.z*mAR.m[2][1] + mBB_3; if(GREATER(t, t2)) return FALSE; // L = A0 x B2 t = Tx*mRBoxToModel.m[0][2] - Tz*mRBoxToModel.m[0][0]; t2 = extents.x*mAR.m[0][2] + extents.z*mAR.m[0][0] + mBB_4; if(GREATER(t, t2)) return FALSE; // L = A1 x B0 t = Tx*mRBoxToModel.m[1][2] - Tz*mRBoxToModel.m[1][0]; t2 = extents.x*mAR.m[1][2] + extents.z*mAR.m[1][0] + mBB_5; if(GREATER(t, t2)) return FALSE; // L = A1 x B1 t = Tx*mRBoxToModel.m[2][2] - Tz*mRBoxToModel.m[2][0]; t2 = extents.x*mAR.m[2][2] + extents.z*mAR.m[2][0] + mBB_6; if(GREATER(t, t2)) return FALSE; // L = A1 x B2 t = Ty*mRBoxToModel.m[0][0] - Tx*mRBoxToModel.m[0][1]; t2 = extents.x*mAR.m[0][1] + extents.y*mAR.m[0][0] + mBB_7; if(GREATER(t, t2)) return FALSE; // L = A2 x B0 t = Ty*mRBoxToModel.m[1][0] - Tx*mRBoxToModel.m[1][1]; t2 = extents.x*mAR.m[1][1] + extents.y*mAR.m[1][0] + mBB_8; if(GREATER(t, t2)) return FALSE; // L = A2 x B1 t = Ty*mRBoxToModel.m[2][0] - Tx*mRBoxToModel.m[2][1]; t2 = extents.x*mAR.m[2][1] + extents.y*mAR.m[2][0] + mBB_9; if(GREATER(t, t2)) return FALSE; // L = A2 x B2 } return TRUE; } //! A special version for 2 axis-aligned boxes inline_ BOOL AABBCollider::AABBAABBOverlap(const Point& extents, const Point& center) { // Stats mNbVolumeBVTests++; float tx = mBox.mCenter.x - center.x; float ex = extents.x + mBox.mExtents.x; if(GREATER(tx, ex)) return FALSE; float ty = mBox.mCenter.y - center.y; float ey = extents.y + mBox.mExtents.y; if(GREATER(ty, ey)) return FALSE; float tz = mBox.mCenter.z - center.z; float ez = extents.z + mBox.mExtents.z; if(GREATER(tz, ez)) return FALSE; return TRUE; } ode-0.14/OPCODE/OPC_Collider.cpp0000644000000000000000000000541512635011627014626 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains base collider class. * \file OPC_Collider.cpp * \author Pierre Terdiman * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains the abstract class for colliders. * * \class Collider * \author Pierre Terdiman * \version 1.3 * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Collider::Collider() : mFlags (0), mCurrentModel (null), mIMesh (null) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Collider::~Collider() { } ode-0.14/OPCODE/OPC_Collider.h0000644000000000000000000002423512635011627014274 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains base collider class. * \file OPC_Collider.h * \author Pierre Terdiman * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_COLLIDER_H__ #define __OPC_COLLIDER_H__ enum CollisionFlag { OPC_FIRST_CONTACT = (1<<0), //!< Report all contacts (false) or only first one (true) OPC_TEMPORAL_COHERENCE = (1<<1), //!< Use temporal coherence or not OPC_CONTACT = (1<<2), //!< Final contact status after a collision query OPC_TEMPORAL_HIT = (1<<3), //!< There has been an early exit due to temporal coherence OPC_NO_PRIMITIVE_TESTS = (1<<4), //!< Keep or discard primitive-bv tests in leaf nodes (volume-mesh queries) OPC_CONTACT_FOUND = OPC_FIRST_CONTACT | OPC_CONTACT, OPC_TEMPORAL_CONTACT = OPC_TEMPORAL_HIT | OPC_CONTACT, OPC_FORCE_DWORD = 0x7fffffff }; class OPCODE_API Collider { public: // Constructor / Destructor Collider(); virtual ~Collider(); // Collision report /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the last collision status after a collision query. * \return true if a collision occured */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL GetContactStatus() const { return mFlags & OPC_CONTACT; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the "first contact" mode. * \return true if "first contact" mode is on */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL FirstContactEnabled() const { return mFlags & OPC_FIRST_CONTACT; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the temporal coherence mode. * \return true if temporal coherence is on */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL TemporalCoherenceEnabled() const { return mFlags & OPC_TEMPORAL_COHERENCE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks a first contact has already been found. * \return true if a first contact has been found and we can stop a query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL ContactFound() const { return (mFlags&OPC_CONTACT_FOUND)==OPC_CONTACT_FOUND; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks there's been an early exit due to temporal coherence; * \return true if a temporal hit has occured */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL TemporalHit() const { return mFlags & OPC_TEMPORAL_HIT; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks primitive tests are enabled; * \return true if primitive tests must be skipped */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL SkipPrimitiveTests() const { return mFlags & OPC_NO_PRIMITIVE_TESTS; } // Settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Reports all contacts (false) or first contact only (true) * \param flag [in] true for first contact, false for all contacts * \see SetTemporalCoherence(bool flag) * \see ValidateSettings() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetFirstContact(bool flag) { if(flag) mFlags |= OPC_FIRST_CONTACT; else mFlags &= ~OPC_FIRST_CONTACT; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Enable/disable temporal coherence. * \param flag [in] true to enable temporal coherence, false to discard it * \see SetFirstContact(bool flag) * \see ValidateSettings() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetTemporalCoherence(bool flag) { if(flag) mFlags |= OPC_TEMPORAL_COHERENCE; else mFlags &= ~OPC_TEMPORAL_COHERENCE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Enable/disable primitive tests. * \param flag [in] true to enable primitive tests, false to discard them */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetPrimitiveTests(bool flag) { if(!flag) mFlags |= OPC_NO_PRIMITIVE_TESTS; else mFlags &= ~OPC_NO_PRIMITIVE_TESTS; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual const char* ValidateSettings() = 0; protected: udword mFlags; //!< Bit flags const BaseModel* mCurrentModel; //!< Current model for collision query (owner of touched faces) // User mesh interface const MeshInterface* mIMesh; //!< User-defined mesh interface // Internal methods /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups current collision model * \param model [in] current collision model * \return TRUE if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL Setup(const BaseModel* model) { // Keep track of current model mCurrentModel = model; if(!mCurrentModel) return FALSE; mIMesh = model->GetMeshInterface(); return mIMesh!=null; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual inline_ void InitQuery() { mFlags &= ~OPC_TEMPORAL_CONTACT; } }; #endif // __OPC_COLLIDER_H__ ode-0.14/OPCODE/OPC_Common.cpp0000644000000000000000000000525212635011627014320 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains common classes & defs used in OPCODE. * \file OPC_Common.cpp * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * An AABB dedicated to collision detection. * We don't use the generic AABB class included in ICE, since it can be a Min/Max or a Center/Extents one (depends * on compilation flags). Since the Center/Extents model is more efficient in collision detection, it was worth * using an extra special class. * * \class CollisionAABB * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A quantized AABB. * Center/Extent model, using 16-bits integers. * * \class QuantizedAABB * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; ode-0.14/OPCODE/OPC_Common.h0000644000000000000000000001113612635011627013763 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains common classes & defs used in OPCODE. * \file OPC_Common.h * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_COMMON_H__ #define __OPC_COMMON_H__ // [GOTTFRIED]: Just a small change for readability. #ifdef OPC_CPU_COMPARE #define GREATER(x, y) AIR(x) > IR(y) #else #define GREATER(x, y) fabsf(x) > (y) #endif class OPCODE_API CollisionAABB { public: //! Constructor inline_ CollisionAABB() {} //! Constructor inline_ CollisionAABB(const AABB& b) { b.GetCenter(mCenter); b.GetExtents(mExtents); } //! Destructor inline_ ~CollisionAABB() {} //! Get min point of the box inline_ void GetMin(Point& min) const { min = mCenter - mExtents; } //! Get max point of the box inline_ void GetMax(Point& max) const { max = mCenter + mExtents; } //! Get component of the box's min point along a given axis inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; } //! Get component of the box's max point along a given axis inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Setups an AABB from min & max vectors. * \param min [in] the min point * \param max [in] the max point */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks a box is inside another box. * \param box [in] the other box * \return true if current box is inside input box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL IsInside(const CollisionAABB& box) const { if(box.GetMin(0)>GetMin(0)) return FALSE; if(box.GetMin(1)>GetMin(1)) return FALSE; if(box.GetMin(2)>GetMin(2)) return FALSE; if(box.GetMax(0)IsValid()) return false; // Look for degenerate faces. //udword NbDegenerate = create.mIMesh->CheckTopology(); //if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate); // We continue nonetheless.... Release(); // Make sure previous tree has been discarded // 1-1) Setup mesh interface automatically SetMeshInterface(create.mIMesh); bool Status = false; AABBTree* LeafTree = null; Internal Data; // 2) Build a generic AABB Tree. mSource = new AABBTree; CHECKALLOC(mSource); // 2-1) Setup a builder. Our primitives here are triangles from input mesh, // so we use an AABBTreeOfTrianglesBuilder..... { AABBTreeOfTrianglesBuilder TB; TB.mIMesh = create.mIMesh; TB.mNbPrimitives = create.mIMesh->GetNbTriangles(); TB.mSettings = create.mSettings; TB.mSettings.mLimit = 16; // ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ... if(!mSource->Build(&TB)) goto FreeAndExit; } // 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time) struct Local { // A callback to count leaf nodes static bool CountLeaves(const AABBTreeNode* current, udword /*depth*/, void* user_data) { if(current->IsLeaf()) { Internal* Data = (Internal*)user_data; Data->mNbLeaves++; } return true; } // A callback to setup leaf nodes in our internal structures static bool SetupLeafData(const AABBTreeNode* current, udword /*depth*/, void* user_data) { if(current->IsLeaf()) { Internal* Data = (Internal*)user_data; // Get current leaf's box Data->mLeaves[Data->mNbLeaves] = *current->GetAABB(); // Setup leaf data udword Index = udword((size_t(current->GetPrimitives()) - size_t(Data->mBase)) / sizeof(udword)); Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index); Data->mNbLeaves++; } return true; } }; // Walk the tree & count number of leaves Data.mNbLeaves = 0; mSource->Walk(Local::CountLeaves, &Data); mNbLeaves = Data.mNbLeaves; // Keep track of it // Special case for 1-leaf meshes if(mNbLeaves==1) { mModelCode |= OPC_SINGLE_NODE; Status = true; goto FreeAndExit; } // Allocate our structures Data.mLeaves = new AABB[Data.mNbLeaves]; CHECKALLOC(Data.mLeaves); mTriangles = new LeafTriangles[Data.mNbLeaves]; CHECKALLOC(mTriangles); // Walk the tree again & setup leaf data Data.mTriangles = mTriangles; Data.mBase = mSource->GetIndices(); Data.mNbLeaves = 0; // Reset for incoming walk mSource->Walk(Local::SetupLeafData, &Data); // Handle source indices { bool MustKeepIndices = true; if(create.mCanRemap) { // We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays... // Remap can fail when we use callbacks => keep track of indices in that case (it still // works, only using more memory) if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices())) { MustKeepIndices = false; } } if(MustKeepIndices) { // Keep track of source indices (from vanilla tree) mNbPrimitives = mSource->GetNbPrimitives(); mIndices = new udword[mNbPrimitives]; CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword)); } } // Now, create our optimized tree using previous leaf nodes LeafTree = new AABBTree; CHECKALLOC(LeafTree); { AABBTreeOfAABBsBuilder TB; // Now using boxes ! TB.mSettings = create.mSettings; TB.mSettings.mLimit = 1; // We now want a complete tree so that we can "optimize" it TB.mNbPrimitives = Data.mNbLeaves; TB.mAABBArray = Data.mLeaves; if(!LeafTree->Build(&TB)) goto FreeAndExit; } // 3) Create an optimized tree according to user-settings if(!CreateTree(create.mNoLeaf, create.mQuantized)) goto FreeAndExit; // 3-2) Create optimized tree if(!mTree->Build(LeafTree)) goto FreeAndExit; // Finally ok... Status = true; FreeAndExit: // Allow me this one... DELETESINGLE(LeafTree); // 3-3) Delete generic tree if needed if(!create.mKeepOriginal) DELETESINGLE(mSource); return Status; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of bytes used by the tree. * \return amount of bytes used */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword HybridModel::GetUsedBytes() const { udword UsedBytes = 0; if(mTree) UsedBytes += mTree->GetUsedBytes(); if(mIndices) UsedBytes += mNbPrimitives * sizeof(udword); // mIndices if(mTriangles) UsedBytes += mNbLeaves * sizeof(LeafTriangles); // mTriangles return UsedBytes; } inline_ void ComputeMinMax(Point& min, Point& max, const VertexPointers& vp) { // Compute triangle's AABB = a leaf box #ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); #else min = *vp.Vertex[0]; max = *vp.Vertex[0]; min.Min(*vp.Vertex[1]); max.Max(*vp.Vertex[1]); min.Min(*vp.Vertex[2]); max.Max(*vp.Vertex[2]); #endif } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the collision model. This can be used to handle dynamic meshes. Usage is: * 1. modify your mesh vertices (keep the topology constant!) * 2. refit the tree (call this method) * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool HybridModel::Refit() { if(!mIMesh) return false; if(!mTree) return false; if(IsQuantized()) return false; if(HasLeafNodes()) return false; const LeafTriangles* LT = GetLeafTriangles(); const udword* Indices = GetIndices(); // Bottom-up update VertexPointers VP; ConversionArea VC; Point Min,Max; Point Min_,Max_; udword Index = mTree->GetNbNodes(); AABBNoLeafNode* Nodes = (AABBNoLeafNode*)((AABBNoLeafTree*)mTree)->GetNodes(); while(Index--) { AABBNoLeafNode& Current = Nodes[Index]; if(Current.HasPosLeaf()) { const LeafTriangles& CurrentLeaf = LT[Current.GetPosPrimitive()]; Min.SetPlusInfinity(); Max.SetMinusInfinity(); Point TmpMin, TmpMax; // Each leaf box has a set of triangles udword NbTris = CurrentLeaf.GetNbTriangles(); if(Indices) { const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; // Loop through triangles and test each of them while(NbTris--) { mIMesh->GetTriangle(VP, *T++, VC); ComputeMinMax(TmpMin, TmpMax, VP); Min.Min(TmpMin); Max.Max(TmpMax); } } else { udword BaseIndex = CurrentLeaf.GetTriangleIndex(); // Loop through triangles and test each of them while(NbTris--) { mIMesh->GetTriangle(VP, BaseIndex++, VC); ComputeMinMax(TmpMin, TmpMax, VP); Min.Min(TmpMin); Max.Max(TmpMax); } } } else { const CollisionAABB& CurrentBox = Current.GetPos()->mAABB; CurrentBox.GetMin(Min); CurrentBox.GetMax(Max); } if(Current.HasNegLeaf()) { const LeafTriangles& CurrentLeaf = LT[Current.GetNegPrimitive()]; Min_.SetPlusInfinity(); Max_.SetMinusInfinity(); Point TmpMin, TmpMax; // Each leaf box has a set of triangles udword NbTris = CurrentLeaf.GetNbTriangles(); if(Indices) { const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; // Loop through triangles and test each of them while(NbTris--) { mIMesh->GetTriangle(VP, *T++, VC); ComputeMinMax(TmpMin, TmpMax, VP); Min_.Min(TmpMin); Max_.Max(TmpMax); } } else { udword BaseIndex = CurrentLeaf.GetTriangleIndex(); // Loop through triangles and test each of them while(NbTris--) { mIMesh->GetTriangle(VP, BaseIndex++, VC); ComputeMinMax(TmpMin, TmpMax, VP); Min_.Min(TmpMin); Max_.Max(TmpMax); } } } else { const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB; CurrentBox.GetMin(Min_); CurrentBox.GetMax(Max_); } #ifdef OPC_USE_FCOMI Min.x = FCMin2(Min.x, Min_.x); Max.x = FCMax2(Max.x, Max_.x); Min.y = FCMin2(Min.y, Min_.y); Max.y = FCMax2(Max.y, Max_.y); Min.z = FCMin2(Min.z, Min_.z); Max.z = FCMax2(Max.z, Max_.z); #else Min.Min(Min_); Max.Max(Max_); #endif Current.mAABB.SetMinMax(Min, Max); } return true; } ode-0.14/OPCODE/OPC_HybridModel.h0000644000000000000000000001413712635011627014741 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for hybrid models. * \file OPC_HybridModel.h * \author Pierre Terdiman * \date May, 18, 2003 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_HYBRIDMODEL_H__ #define __OPC_HYBRIDMODEL_H__ //! Leaf descriptor struct LeafTriangles { udword Data; //!< Packed data /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets number of triangles in the leaf. * \return number of triangles N, with 0 < N <= 16 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbTriangles() const { return (Data & 15)+1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets triangle index for this leaf. Indexed model's array of indices retrieved with HybridModel::GetIndices() * \return triangle index */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetTriangleIndex() const { return Data>>4; } inline_ void SetData(udword nb, udword index) { ASSERT(nb>0 && nb<=16); nb--; Data = (index<<4)|(nb&15); } }; class OPCODE_API HybridModel : public BaseModel { public: // Constructor/Destructor HybridModel(); virtual ~HybridModel(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds a collision model. * \param create [in] model creation structure * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(BaseModel) bool Build(const OPCODECREATE& create); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of bytes used by the tree. * \return amount of bytes used */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(BaseModel) udword GetUsedBytes() const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the collision model. This can be used to handle dynamic meshes. Usage is: * 1. modify your mesh vertices (keep the topology constant!) * 2. refit the tree (call this method) * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(BaseModel) bool Refit(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets array of triangles. * \return array of triangles */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const LeafTriangles* GetLeafTriangles() const { return mTriangles; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets array of indices. * \return array of indices */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const udword* GetIndices() const { return mIndices; } private: udword mNbLeaves; //!< Number of leaf nodes in the model LeafTriangles* mTriangles; //!< Array of mNbLeaves leaf descriptors udword mNbPrimitives; //!< Number of primitives in the model udword* mIndices; //!< Array of primitive indices // Internal methods void Release(); }; #endif // __OPC_HYBRIDMODEL_H__ ode-0.14/OPCODE/OPC_IceHook.h0000644000000000000000000000274512635011627014062 0ustar rootroot // Should be included by Opcode.h if needed #define ICE_DONT_CHECK_COMPILER_OPTIONS // From Windows... typedef int BOOL; #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #include #include #include #include #include #include #ifndef ASSERT #define ASSERT(exp) {} #endif #define ICE_COMPILE_TIME_ASSERT(exp) extern char ICE_Dummy[ (exp) ? 1 : -1 ] #define Log {} #define SetIceError(a,b) false #define EC_OUTOFMEMORY "Out of memory" #include "Ice/IcePreprocessor.h" #undef ICECORE_API #define ICECORE_API OPCODE_API #include "Ice/IceTypes.h" #include "Ice/IceFPU.h" #include "Ice/IceMemoryMacros.h" namespace IceCore { #include "Ice/IceUtils.h" #include "Ice/IceContainer.h" #include "Ice/IcePairs.h" #include "Ice/IceRevisitedRadix.h" #include "Ice/IceRandom.h" } using namespace IceCore; #define ICEMATHS_API OPCODE_API namespace IceMaths { #include "Ice/IceAxes.h" #include "Ice/IcePoint.h" #include "Ice/IceHPoint.h" #include "Ice/IceMatrix3x3.h" #include "Ice/IceMatrix4x4.h" #include "Ice/IcePlane.h" #include "Ice/IceRay.h" #include "Ice/IceIndexedTriangle.h" #include "Ice/IceTriangle.h" #include "Ice/IceTriList.h" #include "Ice/IceAABB.h" #include "Ice/IceOBB.h" #include "Ice/IceBoundingSphere.h" #include "Ice/IceSegment.h" #include "Ice/IceLSS.h" } using namespace IceMaths; ode-0.14/OPCODE/OPC_LSSAABBOverlap.h0000644000000000000000000003760512635011627015144 0ustar rootroot // Following code from Magic-Software (http://www.magic-software.com/) // A bit modified for Opcode inline_ float OPC_PointAABBSqrDist(const Point& point, const Point& center, const Point& extents) { // Compute coordinates of point in box coordinate system Point Closest = point - center; float SqrDistance = 0.0f; if(Closest.x < -extents.x) { float Delta = Closest.x + extents.x; SqrDistance += Delta*Delta; } else if(Closest.x > extents.x) { float Delta = Closest.x - extents.x; SqrDistance += Delta*Delta; } if(Closest.y < -extents.y) { float Delta = Closest.y + extents.y; SqrDistance += Delta*Delta; } else if(Closest.y > extents.y) { float Delta = Closest.y - extents.y; SqrDistance += Delta*Delta; } if(Closest.z < -extents.z) { float Delta = Closest.z + extents.z; SqrDistance += Delta*Delta; } else if(Closest.z > extents.z) { float Delta = Closest.z - extents.z; SqrDistance += Delta*Delta; } return SqrDistance; } static void Face(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, const Point& rkPmE, float* pfLParam, float& rfSqrDistance) { Point kPpE; float fLSqr, fInv, fTmp, fParam, fT, fDelta; kPpE[i1] = rkPnt[i1] + extents[i1]; kPpE[i2] = rkPnt[i2] + extents[i2]; if(rkDir[i0]*kPpE[i1] >= rkDir[i1]*rkPmE[i0]) { if(rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0]) { // v[i1] >= -e[i1], v[i2] >= -e[i2] (distance = 0) if(pfLParam) { rkPnt[i0] = extents[i0]; fInv = 1.0f/rkDir[i0]; rkPnt[i1] -= rkDir[i1]*rkPmE[i0]*fInv; rkPnt[i2] -= rkDir[i2]*rkPmE[i0]*fInv; *pfLParam = -rkPmE[i0]*fInv; } } else { // v[i1] >= -e[i1], v[i2] < -e[i2] fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i2]*rkDir[i2]; fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]); if(fTmp <= 2.0f*fLSqr*extents[i1]) { fT = fTmp/fLSqr; fLSqr += rkDir[i1]*rkDir[i1]; fTmp = kPpE[i1] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = fT - extents[i1]; rkPnt[i2] = -extents[i2]; } } else { fLSqr += rkDir[i1]*rkDir[i1]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = extents[i1]; rkPnt[i2] = -extents[i2]; } } } } else { if ( rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0] ) { // v[i1] < -e[i1], v[i2] >= -e[i2] fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]; fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]); if(fTmp <= 2.0f*fLSqr*extents[i2]) { fT = fTmp/fLSqr; fLSqr += rkDir[i2]*rkDir[i2]; fTmp = kPpE[i2] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = -extents[i1]; rkPnt[i2] = fT - extents[i2]; } } else { fLSqr += rkDir[i2]*rkDir[i2]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = -extents[i1]; rkPnt[i2] = extents[i2]; } } } else { // v[i1] < -e[i1], v[i2] < -e[i2] fLSqr = rkDir[i0]*rkDir[i0]+rkDir[i2]*rkDir[i2]; fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]); if(fTmp >= 0.0f) { // v[i1]-edge is closest if ( fTmp <= 2.0f*fLSqr*extents[i1] ) { fT = fTmp/fLSqr; fLSqr += rkDir[i1]*rkDir[i1]; fTmp = kPpE[i1] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = fT - extents[i1]; rkPnt[i2] = -extents[i2]; } } else { fLSqr += rkDir[i1]*rkDir[i1]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = extents[i1]; rkPnt[i2] = -extents[i2]; } } return; } fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]; fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]); if(fTmp >= 0.0f) { // v[i2]-edge is closest if(fTmp <= 2.0f*fLSqr*extents[i2]) { fT = fTmp/fLSqr; fLSqr += rkDir[i2]*rkDir[i2]; fTmp = kPpE[i2] - fT; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = -extents[i1]; rkPnt[i2] = fT - extents[i2]; } } else { fLSqr += rkDir[i2]*rkDir[i2]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = -extents[i1]; rkPnt[i2] = extents[i2]; } } return; } // (v[i1],v[i2])-corner is closest fLSqr += rkDir[i2]*rkDir[i2]; fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*kPpE[i2]; fParam = -fDelta/fLSqr; rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; if(pfLParam) { *pfLParam = fParam; rkPnt[i0] = extents[i0]; rkPnt[i1] = -extents[i1]; rkPnt[i2] = -extents[i2]; } } } } static void CaseNoZeros(Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance) { Point kPmE(rkPnt.x - extents.x, rkPnt.y - extents.y, rkPnt.z - extents.z); float fProdDxPy, fProdDyPx, fProdDzPx, fProdDxPz, fProdDzPy, fProdDyPz; fProdDxPy = rkDir.x*kPmE.y; fProdDyPx = rkDir.y*kPmE.x; if(fProdDyPx >= fProdDxPy) { fProdDzPx = rkDir.z*kPmE.x; fProdDxPz = rkDir.x*kPmE.z; if(fProdDzPx >= fProdDxPz) { // line intersects x = e0 Face(0, 1, 2, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); } else { // line intersects z = e2 Face(2, 0, 1, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); } } else { fProdDzPy = rkDir.z*kPmE.y; fProdDyPz = rkDir.y*kPmE.z; if(fProdDzPy >= fProdDyPz) { // line intersects y = e1 Face(1, 2, 0, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); } else { // line intersects z = e2 Face(2, 0, 1, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); } } } static void Case0(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance) { float fPmE0 = rkPnt[i0] - extents[i0]; float fPmE1 = rkPnt[i1] - extents[i1]; float fProd0 = rkDir[i1]*fPmE0; float fProd1 = rkDir[i0]*fPmE1; float fDelta, fInvLSqr, fInv; if(fProd0 >= fProd1) { // line intersects P[i0] = e[i0] rkPnt[i0] = extents[i0]; float fPpE1 = rkPnt[i1] + extents[i1]; fDelta = fProd0 - rkDir[i0]*fPpE1; if(fDelta >= 0.0f) { fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]); rfSqrDistance += fDelta*fDelta*fInvLSqr; if(pfLParam) { rkPnt[i1] = -extents[i1]; *pfLParam = -(rkDir[i0]*fPmE0+rkDir[i1]*fPpE1)*fInvLSqr; } } else { if(pfLParam) { fInv = 1.0f/rkDir[i0]; rkPnt[i1] -= fProd0*fInv; *pfLParam = -fPmE0*fInv; } } } else { // line intersects P[i1] = e[i1] rkPnt[i1] = extents[i1]; float fPpE0 = rkPnt[i0] + extents[i0]; fDelta = fProd1 - rkDir[i1]*fPpE0; if(fDelta >= 0.0f) { fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]); rfSqrDistance += fDelta*fDelta*fInvLSqr; if(pfLParam) { rkPnt[i0] = -extents[i0]; *pfLParam = -(rkDir[i0]*fPpE0+rkDir[i1]*fPmE1)*fInvLSqr; } } else { if(pfLParam) { fInv = 1.0f/rkDir[i1]; rkPnt[i0] -= fProd1*fInv; *pfLParam = -fPmE1*fInv; } } } if(rkPnt[i2] < -extents[i2]) { fDelta = rkPnt[i2] + extents[i2]; rfSqrDistance += fDelta*fDelta; rkPnt[i2] = -extents[i2]; } else if ( rkPnt[i2] > extents[i2] ) { fDelta = rkPnt[i2] - extents[i2]; rfSqrDistance += fDelta*fDelta; rkPnt[i2] = extents[i2]; } } static void Case00(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance) { float fDelta; if(pfLParam) *pfLParam = (extents[i0] - rkPnt[i0])/rkDir[i0]; rkPnt[i0] = extents[i0]; if(rkPnt[i1] < -extents[i1]) { fDelta = rkPnt[i1] + extents[i1]; rfSqrDistance += fDelta*fDelta; rkPnt[i1] = -extents[i1]; } else if(rkPnt[i1] > extents[i1]) { fDelta = rkPnt[i1] - extents[i1]; rfSqrDistance += fDelta*fDelta; rkPnt[i1] = extents[i1]; } if(rkPnt[i2] < -extents[i2]) { fDelta = rkPnt[i2] + extents[i2]; rfSqrDistance += fDelta*fDelta; rkPnt[i1] = -extents[i2]; } else if(rkPnt[i2] > extents[i2]) { fDelta = rkPnt[i2] - extents[i2]; rfSqrDistance += fDelta*fDelta; rkPnt[i2] = extents[i2]; } } static void Case000(Point& rkPnt, const Point& extents, float& rfSqrDistance) { float fDelta; if(rkPnt.x < -extents.x) { fDelta = rkPnt.x + extents.x; rfSqrDistance += fDelta*fDelta; rkPnt.x = -extents.x; } else if(rkPnt.x > extents.x) { fDelta = rkPnt.x - extents.x; rfSqrDistance += fDelta*fDelta; rkPnt.x = extents.x; } if(rkPnt.y < -extents.y) { fDelta = rkPnt.y + extents.y; rfSqrDistance += fDelta*fDelta; rkPnt.y = -extents.y; } else if(rkPnt.y > extents.y) { fDelta = rkPnt.y - extents.y; rfSqrDistance += fDelta*fDelta; rkPnt.y = extents.y; } if(rkPnt.z < -extents.z) { fDelta = rkPnt.z + extents.z; rfSqrDistance += fDelta*fDelta; rkPnt.z = -extents.z; } else if(rkPnt.z > extents.z) { fDelta = rkPnt.z - extents.z; rfSqrDistance += fDelta*fDelta; rkPnt.z = extents.z; } } static float SqrDistance(const Ray& rkLine, const Point& center, const Point& extents, float* pfLParam) { // compute coordinates of line in box coordinate system Point kDiff = rkLine.mOrig - center; Point kPnt = kDiff; Point kDir = rkLine.mDir; #if 0 // Apply reflections so that direction vector has nonnegative components. bool bReflect[3]; for(int i=0;i<3;i++) { if(kDir[i]<0.0f) { kPnt[i] = -kPnt[i]; kDir[i] = -kDir[i]; bReflect[i] = true; } else { bReflect[i] = false; } } #endif float fSqrDistance = 0.0f; if(kDir.x>0.0f) { if(kDir.y>0.0f) { if(kDir.z>0.0f) CaseNoZeros(kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,+,+) else Case0(0, 1, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,+,0) } else { if(kDir.z>0.0f) Case0(0, 2, 1, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,0,+) else Case00(0, 1, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,0,0) } } else { if(kDir.y>0.0f) { if(kDir.z>0.0f) Case0(1, 2, 0, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,+,+) else Case00(1, 0, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,+,0) } else { if(kDir.z>0.0f) Case00(2, 0, 1, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,0,+) else { Case000(kPnt, extents, fSqrDistance); // (0,0,0) if(pfLParam) *pfLParam = 0.0f; } } } return fSqrDistance; } inline_ float OPC_SegmentOBBSqrDist(const Segment& segment, const Point& c0, const Point& e0) { float fLP; float fSqrDistance = SqrDistance(Ray(segment.GetOrigin(), segment.ComputeDirection()), c0, e0, &fLP); if(fLP>=0.0f) { if(fLP<=1.0f) return fSqrDistance; else return OPC_PointAABBSqrDist(segment.mP1, c0, e0); } else return OPC_PointAABBSqrDist(segment.mP0, c0, e0); } inline_ BOOL LSSCollider::LSSAABBOverlap(const Point& center, const Point& extents) { // Stats mNbVolumeBVTests++; float s2 = OPC_SegmentOBBSqrDist(mSeg, center, extents); if(s2Add(udword(prim_index)); //! LSS-triangle overlap test #define LSS_PRIM(prim_index, flag) \ /* Request vertices from the app */ \ VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \ \ /* Perform LSS-tri overlap test */ \ if(LSSTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ { \ SET_CONTACT(prim_index, flag) \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LSSCollider::LSSCollider() { // mCenter.Zero(); // mRadius2 = 0.0f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// LSSCollider::~LSSCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] an lss cache * \param lss [in] collision lss in local space * \param model [in] Opcode model to collide with * \param worldl [in] lss world matrix, or null * \param worldm [in] model's world matrix, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl, const Matrix4x4* worldm) { // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, lss, worldl, worldm)) return true; if(!model.HasLeafNodes()) { if(model.IsQuantized()) { const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a collision query : * - reset stats & contact status * - setup matrices * - check temporal coherence * * \param cache [in/out] an lss cache * \param lss [in] lss in local space * \param worldl [in] lss world matrix, or null * \param worldm [in] model's world matrix, or null * \return TRUE if we can return immediately * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL LSSCollider::InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl, const Matrix4x4* worldm) { // 1) Call the base method VolumeCollider::InitQuery(); // 2) Compute LSS in model space: // - Precompute R^2 mRadius2 = lss.mRadius * lss.mRadius; // - Compute segment mSeg.mP0 = lss.mP0; mSeg.mP1 = lss.mP1; // -> to world space if(worldl) { mSeg.mP0 *= *worldl; mSeg.mP1 *= *worldl; } // -> to model space if(worldm) { // Invert model matrix Matrix4x4 InvWorldM; InvertPRMatrix(InvWorldM, *worldm); mSeg.mP0 *= InvWorldM; mSeg.mP1 *= InvWorldM; } // 3) Setup destination pointer mTouchedPrimitives = &cache.TouchedPrimitives; // 4) Special case: 1-triangle meshes [Opcode 1.3] if(mCurrentModel && mCurrentModel->HasSingleNode()) { if(!SkipPrimitiveTests()) { // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. mTouchedPrimitives->Reset(); // Perform overlap test between the unique triangle and the LSS (and set contact status if needed) LSS_PRIM(udword(0), OPC_CONTACT) // Return immediately regardless of status return TRUE; } } // 5) Check temporal coherence : if(TemporalCoherenceEnabled()) { // Here we use temporal coherence // => check results from previous frame before performing the collision query if(FirstContactEnabled()) { // We're only interested in the first contact found => test the unique previously touched face if(mTouchedPrimitives->GetNbEntries()) { // Get index of previously touched face = the first entry in the array udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); // Then reset the array: // - if the overlap test below is successful, the index we'll get added back anyway // - if it isn't, then the array should be reset anyway for the normal query mTouchedPrimitives->Reset(); // Perform overlap test between the cached triangle and the LSS (and set contact status if needed) LSS_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) // Return immediately if possible if(GetContactStatus()) return TRUE; } // else no face has been touched during previous query // => we'll have to perform a normal query } else { // We're interested in all contacts =>test the new real LSS N(ew) against the previous fat LSS P(revious): // ### rewrite this LSS Test(mSeg, lss.mRadius); // in model space LSS Previous(cache.Previous, sqrtf(cache.Previous.mRadius)); // if(cache.Previous.Contains(Test)) if(IsCacheValid(cache) && Previous.Contains(Test)) { // - if N is included in P, return previous list // => we simply leave the list (mTouchedFaces) unchanged // Set contact status if needed if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; // In any case we don't need to do a query return TRUE; } else { // - else do the query using a fat N // Reset cache since we'll about to perform a real query mTouchedPrimitives->Reset(); // Make a fat sphere so that coherence will work for subsequent frames mRadius2 *= cache.FatCoeff; // mRadius2 = (lss.mRadius * cache.FatCoeff)*(lss.mRadius * cache.FatCoeff); // Update cache with query data (signature for cached faces) cache.Previous.mP0 = mSeg.mP0; cache.Previous.mP1 = mSeg.mP1; cache.Previous.mRadius = mRadius2; } } } else { // Here we don't use temporal coherence => do a normal query mTouchedPrimitives->Reset(); } return FALSE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Collision query for vanilla AABB trees. * \param cache [in/out] an lss cache * \param lss [in] collision lss in world space * \param tree [in] AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree) { // This is typically called for a scene tree, full of -AABBs-, not full of triangles. // So we don't really have "primitives" to deal with. Hence it doesn't work with // "FirstContact" + "TemporalCoherence". ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); // Checkings if(!tree) return false; // Init collision query if(InitQuery(cache, lss)) return true; // Perform collision query _Collide(tree); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the LSS completely contains the box. In which case we can end the query sooner. * \param bc [in] box center * \param be [in] box extents * \return true if the LSS contains the whole box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL LSSCollider::LSSContainsBox(const Point& bc, const Point& be) { // Not implemented return FALSE; } #define TEST_BOX_IN_LSS(center, extents) \ if(LSSContainsBox(center, extents)) \ { \ /* Set contact status */ \ mFlags |= OPC_CONTACT; \ _Dump(node); \ return; \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_Collide(const AABBCollisionNode* node) { // Perform LSS-AABB overlap test if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { LSS_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) { // Perform LSS-AABB overlap test if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_Collide(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform LSS-AABB overlap test if(!LSSAABBOverlap(Center, Extents)) return; TEST_BOX_IN_LSS(Center, Extents) if(node->IsLeaf()) { LSS_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform LSS-AABB overlap test if(!LSSAABBOverlap(Center, Extents)) return; TEST_BOX_IN_LSS(Center, Extents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_Collide(const AABBNoLeafNode* node) { // Perform LSS-AABB overlap test if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) { // Perform LSS-AABB overlap test if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_Collide(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform LSS-AABB overlap test if(!LSSAABBOverlap(Center, Extents)) return; TEST_BOX_IN_LSS(Center, Extents) if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform LSS-AABB overlap test if(!LSSAABBOverlap(Center, Extents)) return; TEST_BOX_IN_LSS(Center, Extents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for vanilla AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void LSSCollider::_Collide(const AABBTreeNode* node) { // Perform LSS-AABB overlap test Point Center, Extents; node->GetAABB()->GetCenter(Center); node->GetAABB()->GetExtents(Extents); if(!LSSAABBOverlap(Center, Extents)) return; if(node->IsLeaf() || LSSContainsBox(Center, Extents)) { mFlags |= OPC_CONTACT; mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives()); } else { _Collide(node->GetPos()); _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridLSSCollider::HybridLSSCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridLSSCollider::~HybridLSSCollider() { } bool HybridLSSCollider::Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl, const Matrix4x4* worldm) { // We don't want primitive tests here! mFlags |= OPC_NO_PRIMITIVE_TESTS; // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, lss, worldl, worldm)) return true; // Special case for 1-leaf trees if(mCurrentModel && mCurrentModel->HasSingleNode()) { // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles udword Nb = mIMesh->GetNbTriangles(); // Loop through all triangles for(udword i=0;imCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } // We only have a list of boxes so far if(GetContactStatus()) { // Reset contact status, since it currently only reflects collisions with leaf boxes Collider::InitQuery(); // Change dest container so that we can use built-in overlap tests and get collided primitives cache.TouchedPrimitives.Reset(); mTouchedPrimitives = &cache.TouchedPrimitives; // Read touched leaf boxes udword Nb = mTouchedBoxes.GetNbEntries(); const udword* Touched = mTouchedBoxes.GetEntries(); const LeafTriangles* LT = model.GetLeafTriangles(); const udword* Indices = model.GetIndices(); // Loop through touched leaves while(Nb--) { const LeafTriangles& CurrentLeaf = LT[*Touched++]; // Each leaf box has a set of triangles udword NbTris = CurrentLeaf.GetNbTriangles(); if(Indices) { const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = *T++; LSS_PRIM(TriangleIndex, OPC_CONTACT) } } else { udword BaseIndex = CurrentLeaf.GetTriangleIndex(); // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = BaseIndex++; LSS_PRIM(TriangleIndex, OPC_CONTACT) } } } } return true; } ode-0.14/OPCODE/OPC_LSSCollider.h0000644000000000000000000001106712635011627014655 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for an LSS collider. * \file OPC_LSSCollider.h * \author Pierre Terdiman * \date December, 28, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_LSSCOLLIDER_H__ #define __OPC_LSSCOLLIDER_H__ struct OPCODE_API LSSCache : VolumeCache { LSSCache() { Previous.mP0 = Point(0.0f, 0.0f, 0.0f); Previous.mP1 = Point(0.0f, 0.0f, 0.0f); Previous.mRadius = 0.0f; FatCoeff = 1.1f; } // Cached faces signature LSS Previous; //!< LSS used when performing the query resulting in cached faces // User settings float FatCoeff; //!< mRadius2 multiplier used to create a fat LSS }; class OPCODE_API LSSCollider : public VolumeCollider { public: // Constructor / Destructor LSSCollider(); virtual ~LSSCollider(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] an lss cache * \param lss [in] collision lss in local space * \param model [in] Opcode model to collide with * \param worldl [in] lss world matrix, or null * \param worldm [in] model's world matrix, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); // bool Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree); protected: // LSS in model space Segment mSeg; //!< Segment float mRadius2; //!< LSS radius squared // Internal methods void _Collide(const AABBCollisionNode* node); void _Collide(const AABBNoLeafNode* node); void _Collide(const AABBQuantizedNode* node); void _Collide(const AABBQuantizedNoLeafNode* node); void _Collide(const AABBTreeNode* node); void _CollideNoPrimitiveTest(const AABBCollisionNode* node); void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); // Overlap tests inline_ BOOL LSSContainsBox(const Point& bc, const Point& be); inline_ BOOL LSSAABBOverlap(const Point& center, const Point& extents); inline_ BOOL LSSTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2); // Init methods BOOL InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); }; class OPCODE_API HybridLSSCollider : public LSSCollider { public: // Constructor / Destructor HybridLSSCollider(); virtual ~HybridLSSCollider(); bool Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); protected: Container mTouchedBoxes; }; #endif // __OPC_LSSCOLLIDER_H__ ode-0.14/OPCODE/OPC_LSSTriOverlap.h0000644000000000000000000005130212635011627015203 0ustar rootroot// Following code from Magic-Software (http://www.magic-software.com/) // A bit modified for Opcode static const float gs_fTolerance = 1e-05f; static float OPC_PointTriangleSqrDist(const Point& point, const Point& p0, const Point& p1, const Point& p2) { // Hook Point TriEdge0 = p1 - p0; Point TriEdge1 = p2 - p0; Point kDiff = p0 - point; float fA00 = TriEdge0.SquareMagnitude(); float fA01 = TriEdge0 | TriEdge1; float fA11 = TriEdge1.SquareMagnitude(); float fB0 = kDiff | TriEdge0; float fB1 = kDiff | TriEdge1; float fC = kDiff.SquareMagnitude(); float fDet = fabsf(fA00*fA11 - fA01*fA01); float fS = fA01*fB1-fA11*fB0; float fT = fA01*fB0-fA00*fB1; float fSqrDist; if(fS + fT <= fDet) { if(fS < 0.0f) { if(fT < 0.0f) // region 4 { if(fB0 < 0.0f) { if(-fB0 >= fA00) fSqrDist = fA00+2.0f*fB0+fC; else fSqrDist = fB0*(-fB0/fA00)+fC; } else { if(fB1 >= 0.0f) fSqrDist = fC; else if(-fB1 >= fA11) fSqrDist = fA11+2.0f*fB1+fC; else fSqrDist = fB1*(-fB1/fA11)+fC; } } else // region 3 { if(fB1 >= 0.0f) fSqrDist = fC; else if(-fB1 >= fA11) fSqrDist = fA11+2.0f*fB1+fC; else fSqrDist = fB1*(-fB1/fA11)+fC; } } else if(fT < 0.0f) // region 5 { if(fB0 >= 0.0f) fSqrDist = fC; else if(-fB0 >= fA00) fSqrDist = fA00+2.0f*fB0+fC; else fSqrDist = fB0*(-fB0/fA00)+fC; } else // region 0 { // minimum at interior point if(fDet==0.0f) { fSqrDist = MAX_FLOAT; } else { float fInvDet = 1.0f/fDet; fS *= fInvDet; fT *= fInvDet; fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; } } } else { float fTmp0, fTmp1, fNumer, fDenom; if(fS < 0.0f) // region 2 { fTmp0 = fA01 + fB0; fTmp1 = fA11 + fB1; if(fTmp1 > fTmp0) { fNumer = fTmp1 - fTmp0; fDenom = fA00-2.0f*fA01+fA11; if(fNumer >= fDenom) { fSqrDist = fA00+2.0f*fB0+fC; } else { fS = fNumer/fDenom; fT = 1.0f - fS; fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; } } else { if(fTmp1 <= 0.0f) fSqrDist = fA11+2.0f*fB1+fC; else if(fB1 >= 0.0f) fSqrDist = fC; else fSqrDist = fB1*(-fB1/fA11)+fC; } } else if(fT < 0.0f) // region 6 { fTmp0 = fA01 + fB1; fTmp1 = fA00 + fB0; if(fTmp1 > fTmp0) { fNumer = fTmp1 - fTmp0; fDenom = fA00-2.0f*fA01+fA11; if(fNumer >= fDenom) { fSqrDist = fA11+2.0f*fB1+fC; } else { fT = fNumer/fDenom; fS = 1.0f - fT; fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; } } else { if(fTmp1 <= 0.0f) fSqrDist = fA00+2.0f*fB0+fC; else if(fB0 >= 0.0f) fSqrDist = fC; else fSqrDist = fB0*(-fB0/fA00)+fC; } } else // region 1 { fNumer = fA11 + fB1 - fA01 - fB0; if(fNumer <= 0.0f) { fSqrDist = fA11+2.0f*fB1+fC; } else { fDenom = fA00-2.0f*fA01+fA11; if(fNumer >= fDenom) { fSqrDist = fA00+2.0f*fB0+fC; } else { fS = fNumer/fDenom; fT = 1.0f - fS; fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; } } } } return fabsf(fSqrDist); } static float OPC_SegmentSegmentSqrDist(const Segment& rkSeg0, const Segment& rkSeg1) { // Hook Point rkSeg0Direction = rkSeg0.ComputeDirection(); Point rkSeg1Direction = rkSeg1.ComputeDirection(); Point kDiff = rkSeg0.mP0 - rkSeg1.mP0; float fA00 = rkSeg0Direction.SquareMagnitude(); float fA01 = -rkSeg0Direction.Dot(rkSeg1Direction); float fA11 = rkSeg1Direction.SquareMagnitude(); float fB0 = kDiff.Dot(rkSeg0Direction); float fC = kDiff.SquareMagnitude(); float fDet = fabsf(fA00*fA11-fA01*fA01); float fB1, fS, fT, fSqrDist, fTmp; if(fDet>=gs_fTolerance) { // line segments are not parallel fB1 = -kDiff.Dot(rkSeg1Direction); fS = fA01*fB1-fA11*fB0; fT = fA01*fB0-fA00*fB1; if(fS >= 0.0f) { if(fS <= fDet) { if(fT >= 0.0f) { if(fT <= fDet) // region 0 (interior) { // minimum at two interior points of 3D lines float fInvDet = 1.0f/fDet; fS *= fInvDet; fT *= fInvDet; fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; } else // region 3 (side) { fTmp = fA01+fB0; if(fTmp>=0.0f) fSqrDist = fA11+2.0f*fB1+fC; else if(-fTmp>=fA00) fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp); else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC; } } else // region 7 (side) { if(fB0>=0.0f) fSqrDist = fC; else if(-fB0>=fA00) fSqrDist = fA00+2.0f*fB0+fC; else fSqrDist = fB0*(-fB0/fA00)+fC; } } else { if ( fT >= 0.0 ) { if ( fT <= fDet ) // region 1 (side) { fTmp = fA01+fB1; if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC; else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp); else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC; } else // region 2 (corner) { fTmp = fA01+fB0; if ( -fTmp <= fA00 ) { if(fTmp>=0.0f) fSqrDist = fA11+2.0f*fB1+fC; else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC; } else { fTmp = fA01+fB1; if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC; else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp); else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC; } } } else // region 8 (corner) { if ( -fB0 < fA00 ) { if(fB0>=0.0f) fSqrDist = fC; else fSqrDist = fB0*(-fB0/fA00)+fC; } else { fTmp = fA01+fB1; if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC; else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp); else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC; } } } } else { if ( fT >= 0.0f ) { if ( fT <= fDet ) // region 5 (side) { if(fB1>=0.0f) fSqrDist = fC; else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC; else fSqrDist = fB1*(-fB1/fA11)+fC; } else // region 4 (corner) { fTmp = fA01+fB0; if ( fTmp < 0.0f ) { if(-fTmp>=fA00) fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp); else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC; } else { if(fB1>=0.0f) fSqrDist = fC; else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC; else fSqrDist = fB1*(-fB1/fA11)+fC; } } } else // region 6 (corner) { if ( fB0 < 0.0f ) { if(-fB0>=fA00) fSqrDist = fA00+2.0f*fB0+fC; else fSqrDist = fB0*(-fB0/fA00)+fC; } else { if(fB1>=0.0f) fSqrDist = fC; else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC; else fSqrDist = fB1*(-fB1/fA11)+fC; } } } } else { // line segments are parallel if ( fA01 > 0.0f ) { // direction vectors form an obtuse angle if ( fB0 >= 0.0f ) { fSqrDist = fC; } else if ( -fB0 <= fA00 ) { fSqrDist = fB0*(-fB0/fA00)+fC; } else { fB1 = -kDiff.Dot(rkSeg1Direction); fTmp = fA00+fB0; if ( -fTmp >= fA01 ) { fSqrDist = fA00+fA11+fC+2.0f*(fA01+fB0+fB1); } else { fT = -fTmp/fA01; fSqrDist = fA00+2.0f*fB0+fC+fT*(fA11*fT+2.0f*(fA01+fB1)); } } } else { // direction vectors form an acute angle if ( -fB0 >= fA00 ) { fSqrDist = fA00+2.0f*fB0+fC; } else if ( fB0 <= 0.0f ) { fSqrDist = fB0*(-fB0/fA00)+fC; } else { fB1 = -kDiff.Dot(rkSeg1Direction); if ( fB0 >= -fA01 ) { fSqrDist = fA11+2.0f*fB1+fC; } else { fT = -fB0/fA01; fSqrDist = fC+fT*(2.0f*fB1+fA11*fT); } } } } return fabsf(fSqrDist); } inline_ float OPC_SegmentRaySqrDist(const Segment& rkSeg0, const Ray& rkSeg1) { return OPC_SegmentSegmentSqrDist(rkSeg0, Segment(rkSeg1.mOrig, rkSeg1.mOrig + rkSeg1.mDir)); } static float OPC_SegmentTriangleSqrDist(const Segment& segment, const Point& p0, const Point& p1, const Point& p2) { // Hook const Point TriEdge0 = p1 - p0; const Point TriEdge1 = p2 - p0; const Point& rkSegOrigin = segment.GetOrigin(); Point rkSegDirection = segment.ComputeDirection(); Point kDiff = p0 - rkSegOrigin; float fA00 = rkSegDirection.SquareMagnitude(); float fA01 = -rkSegDirection.Dot(TriEdge0); float fA02 = -rkSegDirection.Dot(TriEdge1); float fA11 = TriEdge0.SquareMagnitude(); float fA12 = TriEdge0.Dot(TriEdge1); float fA22 = TriEdge1.Dot(TriEdge1); float fB0 = -kDiff.Dot(rkSegDirection); float fB1 = kDiff.Dot(TriEdge0); float fB2 = kDiff.Dot(TriEdge1); float fCof00 = fA11*fA22-fA12*fA12; float fCof01 = fA02*fA12-fA01*fA22; float fCof02 = fA01*fA12-fA02*fA11; float fDet = fA00*fCof00+fA01*fCof01+fA02*fCof02; Ray kTriSeg; Point kPt; float fSqrDist, fSqrDist0; if(fabsf(fDet)>=gs_fTolerance) { float fCof11 = fA00*fA22-fA02*fA02; float fCof12 = fA02*fA01-fA00*fA12; float fCof22 = fA00*fA11-fA01*fA01; float fInvDet = 1.0f/fDet; float fRhs0 = -fB0*fInvDet; float fRhs1 = -fB1*fInvDet; float fRhs2 = -fB2*fInvDet; float fR = fCof00*fRhs0+fCof01*fRhs1+fCof02*fRhs2; float fS = fCof01*fRhs0+fCof11*fRhs1+fCof12*fRhs2; float fT = fCof02*fRhs0+fCof12*fRhs1+fCof22*fRhs2; if ( fR < 0.0f ) { if ( fS+fT <= 1.0f ) { if ( fS < 0.0f ) { if ( fT < 0.0f ) // region 4m { // min on face s=0 or t=0 or r=0 kTriSeg.mOrig = p0; kTriSeg.mDir = TriEdge1; fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg); kTriSeg.mOrig = p0; kTriSeg.mDir = TriEdge0; fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg); if(fSqrDist0 1 { if ( fS+fT <= 1.0f ) { if ( fS < 0.0f ) { if ( fT < 0.0f ) // region 4p { // min on face s=0 or t=0 or r=1 kTriSeg.mOrig = p0; kTriSeg.mDir = TriEdge1; fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg); kTriSeg.mOrig = p0; kTriSeg.mDir = TriEdge0; fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg); if(fSqrDist0GetTriangle(triangle_index); * // Setup pointers to vertices for the collision system * triangle.Vertex[0] = MyMesh->GetVertex(Tri->mVRef[0]); * triangle.Vertex[1] = MyMesh->GetVertex(Tri->mVRef[1]); * triangle.Vertex[2] = MyMesh->GetVertex(Tri->mVRef[2]); * } * * // Setup callbacks * MeshInterface0->SetCallback(ColCallback, udword(Mesh0)); * MeshInterface1->SetCallback(ColCallback, udword(Mesh1)); * \endcode * * Of course, you should make this callback as fast as possible. And you're also not supposed * to modify the geometry *after* the collision trees have been built. The alternative was to * store the geometry & topology in the collision system as well (as in RAPID) but we have found * this approach to waste a lot of ram in many cases. * * * POINTERS: * * If you're internally using the following canonical structures: * - a vertex made of three 32-bits floating point values * - a triangle made of three 32-bits integer vertex references * ...then you may want to use pointers instead of callbacks. This is the same, except OPCODE will directly * use provided pointers to access the topology and geometry, without using a callback. It might be faster, * but probably not as safe. Pointers have been introduced in OPCODE 1.2. * * Ex: * * \code * // Setup pointers * MeshInterface0->SetPointers(Mesh0->GetFaces(), Mesh0->GetVerts()); * MeshInterface1->SetPointers(Mesh1->GetFaces(), Mesh1->GetVerts()); * \endcode * * * STRIDES: * * If your vertices are D3D-like entities interleaving a position, a normal and/or texture coordinates * (i.e. if your vertices are FVFs), you might want to use a vertex stride to skip extra data OPCODE * doesn't need. Using a stride shouldn't be notably slower than not using it, but it might increase * cache misses. Please also note that you *shouldn't* read from AGP or video-memory buffers ! * * * In any case, compilation flags are here to select callbacks/pointers/strides at compile time, so * choose what's best for your application. All of this has been wrapped into this MeshInterface. * * \class MeshInterface * \author Pierre Terdiman * \version 1.3 * \date November, 27, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MeshInterface::MeshInterface() : mNbTris (0), mNbVerts (0), #ifdef OPC_USE_CALLBACKS mUserData (null), mObjCallback (null), mExUserData (null), mObjExCallback (null), #else #ifdef OPC_USE_STRIDE mTriStride (sizeof(IndexedTriangle)), mVertexStride (sizeof(Point)), mFetchTriangle (&MeshInterface::FetchTriangleFromSingles), mFetchExTriangle (&MeshInterface::FetchExTriangleFromSingles), #endif mTris (null), mVerts (null) #endif { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// MeshInterface::~MeshInterface() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the mesh interface is valid, i.e. things have been setup correctly. * \return true if valid */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MeshInterface::IsValid() const { if(!mNbTris || !mNbVerts) return false; #ifdef OPC_USE_CALLBACKS if(!mObjCallback) return false; #else if(!mTris || !mVerts) return false; #endif return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the mesh itself is valid. * Currently we only look for degenerate faces. * \return number of degenerate faces */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword MeshInterface::CheckTopology() const { // Check topology. If the model contains degenerate faces, collision report can be wrong in some cases. // e.g. it happens with the standard MAX teapot. So clean your meshes first... If you don't have a mesh cleaner // you can try this: www.codercorner.com/Consolidation.zip udword NbDegenerate = 0; VertexPointers VP; ConversionArea VC; // Using callbacks, we don't have access to vertex indices. Nevertheless we still can check for // redundant vertex pointers, which cover all possibilities (callbacks/pointers/strides). for(udword i=0;imVRef[0] * VertexStride); vp.Vertex[1] = (const Point*)(((ubyte*)Verts) + T->mVRef[1] * VertexStride); vp.Vertex[2] = (const Point*)(((ubyte*)Verts) + T->mVRef[2] * VertexStride); } void MeshInterface::FetchTriangleFromDoubles(VertexPointers& vp, udword index, ConversionArea vc) const { const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); const Point* Verts = GetVerts(); udword VertexStride = GetVertexStride(); for (int i = 0; i < 3; i++){ const double* v = (const double*)(((ubyte*)Verts) + T->mVRef[i] * VertexStride); vc[i].x = (float)v[0]; vc[i].y = (float)v[1]; vc[i].z = (float)v[2]; vp.Vertex[i] = &vc[i]; } } void MeshInterface::FetchExTriangleFromSingles(VertexPointersEx& vpe, udword index, ConversionArea vc) const { const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); const Point* Verts = GetVerts(); udword VertexStride = GetVertexStride(); dTriIndex VertIndex0 = T->mVRef[0]; vpe.Index[0] = VertIndex0; vpe.vp.Vertex[0] = (const Point*)(((ubyte*)Verts) + VertIndex0 * VertexStride); dTriIndex VertIndex1 = T->mVRef[1]; vpe.Index[1] = VertIndex1; vpe.vp.Vertex[1] = (const Point*)(((ubyte*)Verts) + VertIndex1 * VertexStride); dTriIndex VertIndex2 = T->mVRef[2]; vpe.Index[2] = VertIndex2; vpe.vp.Vertex[2] = (const Point*)(((ubyte*)Verts) + VertIndex2 * VertexStride); } void MeshInterface::FetchExTriangleFromDoubles(VertexPointersEx& vpe, udword index, ConversionArea vc) const { const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); const Point* Verts = GetVerts(); udword VertexStride = GetVertexStride(); for (int i = 0; i < 3; i++){ dTriIndex VertIndex = T->mVRef[i]; vpe.Index[i] = VertIndex; const double* v = (const double*)(((ubyte*)Verts) + VertIndex * VertexStride); vc[i].x = (float)v[0]; vc[i].y = (float)v[1]; vc[i].z = (float)v[2]; vpe.vp.Vertex[i] = &vc[i]; } } #endif #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Remaps client's mesh according to a permutation. * \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles) * \param permutation [in] list of triangle indices * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool MeshInterface::RemapClient(udword nb_indices, const dTriIndex* permutation) const { // Checkings if(!nb_indices || !permutation) return false; if(nb_indices!=mNbTris) return false; #ifdef OPC_USE_CALLBACKS // We can't really do that using callbacks return false; #else IndexedTriangle* Tmp = new IndexedTriangle[mNbTris]; CHECKALLOC(Tmp); #ifdef OPC_USE_STRIDE udword Stride = mTriStride; #else udword Stride = sizeof(IndexedTriangle); #endif for(udword i=0;i= 0.0f; } }; struct VertexPointersEx { VertexPointers vp; dTriIndex Index[3]; }; typedef Point ConversionArea[3]; #ifdef OPC_USE_CALLBACKS /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * User-callback, called by OPCODE to request vertices from the app. * \param triangle_index [in] face index for which the system is requesting the vertices * \param triangle [out] triangle's vertices (must be provided by the user) * \param user_data [in] user-defined data from SetCallback() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// typedef void (*RequestCallback) (udword triangle_index, VertexPointers& triangle, void* user_data); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * User-callback, called by OPCODE to request vertex indices from the app. * \param triangle_index [in] face index for which the system is requesting the vertices * \param triangle [out] triangle's vertices with indices (must be provided by the user) * \param user_data [in] user-defined data from SetExCallback() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// typedef void (*RequestExCallback) (udword triangle_index, VertexPointersEx& triangle, void* user_data); #endif class OPCODE_API MeshInterface { public: // Constructor / Destructor MeshInterface(); ~MeshInterface(); // Common settings inline_ udword GetNbTriangles() const { return mNbTris; } inline_ udword GetNbVertices() const { return mNbVerts; } inline_ void SetNbTriangles(udword nb) { mNbTris = nb; } inline_ void SetNbVertices(udword nb) { mNbVerts = nb; } #ifdef OPC_USE_CALLBACKS // Callback settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Callback control: setups object callback. Must provide triangle-vertices for a given triangle index. * \param callback [in] user-defined callback * \param user_data [in] user-defined data * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SetCallback(RequestCallback callback, void* user_data); inline_ void* GetUserData() const { return mUserData; } inline_ RequestCallback GetCallback() const { return mObjCallback; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Callback control: setups object callback. Must provide triangle-vertices for a given triangle index. * \param callback [in] user-defined callback * \param user_data [in] user-defined data * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SetExCallback(RequestExCallback callback, void* user_data); inline_ void* GetExUserData() const { return mExUserData; } inline_ RequestExCallback GetExCallback() const { return mObjExCallback; } #else // Pointers settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Pointers control: setups object pointers. Must provide access to faces and vertices for a given object. * \param tris [in] pointer to triangles * \param verts [in] pointer to vertices * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SetPointers(const IndexedTriangle* tris, const Point* verts); inline_ const IndexedTriangle* GetTris() const { return mTris; } inline_ const Point* GetVerts() const { return mVerts; } #ifdef OPC_USE_STRIDE // Strides settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Strides control * \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices. * \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position. * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point)); inline_ udword GetTriStride() const { return mTriStride; } inline_ udword GetVertexStride() const { return mVertexStride; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Single/Double control * \param value [in] Indicates if mesh data is provided as array of \c single values. If \c false, data is expected to contain \c double elements. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetSingle(bool value) { mFetchTriangle = (value ? &MeshInterface::FetchTriangleFromSingles : &MeshInterface::FetchTriangleFromDoubles); mFetchExTriangle = (value ? &MeshInterface::FetchExTriangleFromSingles : &MeshInterface::FetchExTriangleFromDoubles); } #else inline_ bool SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point)) { return true; } inline_ void SetSingle(bool value) {} inline_ udword GetTriStride() const { return sizeof(IndexedTriangle); } inline_ udword GetVertexStride() const { return sizeof(Point); } #endif #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Fetches a triangle given a triangle index. * \param vp [out] required triangle's vertex pointers * \param index [in] triangle index * \param vc [in,out] storage required for data conversion (pass local variable with same scope as \a vp, as \a vp may point to this memory on return) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void GetTriangle(VertexPointers& vp, udword index, ConversionArea vc) const { #ifdef OPC_USE_CALLBACKS (mObjCallback)(index, vp, mUserData); #else #ifdef OPC_USE_STRIDE // Since there was conditional statement "if (Single)" which was unpredictable for compiler // and required both branches to be always generated what made inlining a questionable // benefit, I consider it better to introduce a forced call // but get rig of branching and dead code injection. ((*this).*mFetchTriangle)(vp, index, vc); #else const Point* Verts = GetVerts(); const IndexedTriangle* T = &mTris[index]; vp.Vertex[0] = &Verts[T->mVRef[0]]; vp.Vertex[1] = &Verts[T->mVRef[1]]; vp.Vertex[2] = &Verts[T->mVRef[2]]; #endif #endif } inline_ bool GetExTriangle(VertexPointersEx& vpe, udword index, ConversionArea vc) const { #ifdef OPC_USE_CALLBACKS if (mObjExCallback) { (mObjExCallback)(index, vpe, mUserData); return true; } else { (mObjCallback)(index, vpe.vp, mUserData); return false; } #else #ifdef OPC_USE_STRIDE // Since there was conditional statement "if (Single)" which was unpredictable for compiler // and required both branches to be always generated what made inlining a questionable // benefit, I consider it better to introduce a forced call // but get rig of branching and dead code injection. ((*this).*mFetchExTriangle)(vpe, index, vc); return true; #else const Point* Verts = GetVerts(); const IndexedTriangle* T = &mTris[index]; dTriIndex VertIndex0 = T->mVRef[0]; vpe.Index[0] = VertIndex0; vpe.vp.Vertex[0] = &Verts[VertIndex0]; dTriIndex VertIndex1 = T->mVRef[1]; vpe.Index[1] = VertIndex1; vpe.vp.Vertex[1] = &Verts[VertIndex1]; dTriIndex VertIndex2 = T->mVRef[2]; vpe.Index[2] = VertIndex2; vpe.vp.Vertex[2] = &Verts[VertIndex2]; return true; #endif #endif } private: #ifndef OPC_USE_CALLBACKS #ifdef OPC_USE_STRIDE void FetchTriangleFromSingles(VertexPointers& vp, udword index, ConversionArea vc) const; void FetchTriangleFromDoubles(VertexPointers& vp, udword index, ConversionArea vc) const; void FetchExTriangleFromSingles(VertexPointersEx& vpe, udword index, ConversionArea vc) const; void FetchExTriangleFromDoubles(VertexPointersEx& vpe, udword index, ConversionArea vc) const; #endif #endif public: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Remaps client's mesh according to a permutation. * \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles) * \param permutation [in] list of triangle indices * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool RemapClient(udword nb_indices, const dTriIndex* permutation) const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the mesh interface is valid, i.e. things have been setup correctly. * \return true if valid */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool IsValid() const; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the mesh itself is valid. * Currently we only look for degenerate faces. * \return number of degenerate faces */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword CheckTopology() const; private: udword mNbTris; //!< Number of triangles in the input model udword mNbVerts; //!< Number of vertices in the input model #ifdef OPC_USE_CALLBACKS // User callback void* mUserData; //!< User-defined data sent to callback RequestCallback mObjCallback; //!< Object callback void* mExUserData; //!< User-defined data sent to ex-callback RequestExCallback mObjExCallback; //!< Object ex-callback #else // User pointers #ifdef OPC_USE_STRIDE udword mTriStride; //!< Possible triangle stride in bytes [Opcode 1.3] udword mVertexStride; //!< Possible vertex stride in bytes [Opcode 1.3] typedef void (MeshInterface:: *TriangleFetchProc)(VertexPointers& vp, udword index, ConversionArea vc) const; TriangleFetchProc mFetchTriangle; typedef void (MeshInterface:: *ExTriangleFetchProc)(VertexPointersEx& vpe, udword index, ConversionArea vc) const; ExTriangleFetchProc mFetchExTriangle; #endif const IndexedTriangle* mTris; //!< Array of indexed triangles const Point* mVerts; //!< Array of vertices #endif }; #endif //__OPC_MESHINTERFACE_H__ ode-0.14/OPCODE/OPC_Model.cpp0000644000000000000000000002066212635011627014132 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for OPCODE models. * \file OPC_Model.cpp * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * The main collision wrapper, for all trees. Supported trees are: * - Normal trees (2*N-1 nodes, full size) * - No-leaf trees (N-1 nodes, full size) * - Quantized trees (2*N-1 nodes, half size) * - Quantized no-leaf trees (N-1 nodes, half size) * * Usage: * * 1) Create a static mesh interface using callbacks or pointers. (see OPC_MeshInterface.cpp). * Keep it around in your app, since a pointer to this interface is saved internally and * used until you release the collision structures. * * 2) Build a Model using a creation structure: * * \code * Model Sample; * * OPCODECREATE OPCC; * OPCC.IMesh = ...; * OPCC.Rules = ...; * OPCC.NoLeaf = ...; * OPCC.Quantized = ...; * OPCC.KeepOriginal = ...; * bool Status = Sample.Build(OPCC); * \endcode * * 3) Create a tree collider and set it up: * * \code * AABBTreeCollider TC; * TC.SetFirstContact(...); * TC.SetFullBoxBoxTest(...); * TC.SetFullPrimBoxTest(...); * TC.SetTemporalCoherence(...); * \endcode * * 4) Perform a collision query * * \code * // Setup cache * static BVTCache ColCache; * ColCache.Model0 = &Model0; * ColCache.Model1 = &Model1; * * // Collision query * bool IsOk = TC.Collide(ColCache, World0, World1); * * // Get collision status => if true, objects overlap * BOOL Status = TC.GetContactStatus(); * * // Number of colliding pairs and list of pairs * udword NbPairs = TC.GetNbPairs(); * const Pair* p = TC.GetPairs() * \endcode * * 5) Stats * * \code * Model0.GetUsedBytes() = number of bytes used for this collision tree * TC.GetNbBVBVTests() = number of BV-BV overlap tests performed during last query * TC.GetNbPrimPrimTests() = number of Triangle-Triangle overlap tests performed during last query * TC.GetNbBVPrimTests() = number of Triangle-BV overlap tests performed during last query * \endcode * * \class Model * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Model::Model() { #ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! mHull = null; #endif // __MESHMERIZER_H__ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Model::~Model() { Release(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Releases the model. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Model::Release() { ReleaseBase(); #ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! DELETESINGLE(mHull); #endif // __MESHMERIZER_H__ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds a collision model. * \param create [in] model creation structure * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Model::Build(const OPCODECREATE& create) { // 1) Checkings if(!create.mIMesh || !create.mIMesh->IsValid()) return false; // For this model, we only support complete trees if(create.mSettings.mLimit!=1) return SetIceError("OPCODE WARNING: supports complete trees only! Use mLimit = 1.\n", null); // Look for degenerate faces. //udword NbDegenerate = create.mIMesh->CheckTopology(); //if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate); // We continue nonetheless.... Release(); // Make sure previous tree has been discarded [Opcode 1.3, thanks Adam] // 1-1) Setup mesh interface automatically [Opcode 1.3] SetMeshInterface(create.mIMesh); // Special case for 1-triangle meshes [Opcode 1.3] udword NbTris = create.mIMesh->GetNbTriangles(); if(NbTris==1) { // We don't need to actually create a tree here, since we'll only have a single triangle to deal with anyway. // It's a waste to use a "model" for this but at least it will work. mModelCode |= OPC_SINGLE_NODE; return true; } // 2) Build a generic AABB Tree. mSource = new AABBTree; CHECKALLOC(mSource); // 2-1) Setup a builder. Our primitives here are triangles from input mesh, // so we use an AABBTreeOfTrianglesBuilder..... { AABBTreeOfTrianglesBuilder TB; TB.mIMesh = create.mIMesh; TB.mSettings = create.mSettings; TB.mNbPrimitives = NbTris; if(!mSource->Build(&TB)) return false; } // 3) Create an optimized tree according to user-settings if(!CreateTree(create.mNoLeaf, create.mQuantized)) return false; // 3-2) Create optimized tree if(!mTree->Build(mSource)) return false; // 3-3) Delete generic tree if needed if(!create.mKeepOriginal) DELETESINGLE(mSource); #ifdef __MESHMERIZER_H__ // 4) Convex hull if(create.mCollisionHull) { // Create hull mHull = new CollisionHull; CHECKALLOC(mHull); CONVEXHULLCREATE CHC; // ### doesn't work with strides CHC.NbVerts = create.mIMesh->GetNbVertices(); CHC.Vertices = create.mIMesh->GetVerts(); CHC.UnifyNormals = true; CHC.ReduceVertices = true; CHC.WordFaces = false; mHull->Compute(CHC); } #endif // __MESHMERIZER_H__ return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of bytes used by the tree. * \return amount of bytes used */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// udword Model::GetUsedBytes() const { if(!mTree) return 0; return mTree->GetUsedBytes(); } ode-0.14/OPCODE/OPC_Model.h0000644000000000000000000000653712635011627013604 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for OPCODE models. * \file OPC_Model.h * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_MODEL_H__ #define __OPC_MODEL_H__ class OPCODE_API Model : public BaseModel { public: // Constructor/Destructor Model(); virtual ~Model(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds a collision model. * \param create [in] model creation structure * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(BaseModel) bool Build(const OPCODECREATE& create); #ifdef __MESHMERIZER_H__ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the collision hull. * \return the collision hull if it exists */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const CollisionHull* GetHull() const { return mHull; } #endif // __MESHMERIZER_H__ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of bytes used by the tree. * \return amount of bytes used */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(BaseModel) udword GetUsedBytes() const; private: #ifdef __MESHMERIZER_H__ CollisionHull* mHull; //!< Possible convex hull #endif // __MESHMERIZER_H__ // Internal methods void Release(); }; #endif //__OPC_MODEL_H__ ode-0.14/OPCODE/OPC_OBBCollider.cpp0000644000000000000000000007056712635011627015163 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for an OBB collider. * \file OPC_OBBCollider.cpp * \author Pierre Terdiman * \date January, 1st, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains an OBB-vs-tree collider. * * \class OBBCollider * \author Pierre Terdiman * \version 1.3 * \date January, 1st, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; #include "OPC_BoxBoxOverlap.h" #include "OPC_TriBoxOverlap.h" #define SET_CONTACT(prim_index, flag) \ /* Set contact status */ \ mFlags |= flag; \ mTouchedPrimitives->Add(udword(prim_index)); //! OBB-triangle test #define OBB_PRIM(prim_index, flag) \ /* Request vertices from the app */ \ VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \ /* Transform them in a common space */ \ TransformPoint(mLeafVerts[0], *VP.Vertex[0], mRModelToBox, mTModelToBox); \ TransformPoint(mLeafVerts[1], *VP.Vertex[1], mRModelToBox, mTModelToBox); \ TransformPoint(mLeafVerts[2], *VP.Vertex[2], mRModelToBox, mTModelToBox); \ /* Perform triangle-box overlap test */ \ if(TriBoxOverlap()) \ { \ SET_CONTACT(prim_index, flag) \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// OBBCollider::OBBCollider() : mFullBoxBoxTest(true) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// OBBCollider::~OBBCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings and callbacks have been defined. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const char* OBBCollider::ValidateSettings() { if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!"; return VolumeCollider::ValidateSettings(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] a box cache * \param box [in] collision OBB in local space * \param model [in] Opcode model to collide with * \param worldb [in] OBB's world matrix, or null * \param worldm [in] model's world matrix, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool OBBCollider::Collide(OBBCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb, const Matrix4x4* worldm) { // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, box, worldb, worldm)) return true; if(!model.HasLeafNodes()) { if(model.IsQuantized()) { const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a collision query : * - reset stats & contact status * - setup matrices * - check temporal coherence * * \param cache [in/out] a box cache * \param box [in] obb in local space * \param worldb [in] obb's world matrix, or null * \param worldm [in] model's world matrix, or null * \return TRUE if we can return immediately * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL OBBCollider::InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb, const Matrix4x4* worldm) { // 1) Call the base method VolumeCollider::InitQuery(); // 2) Compute obb in world space mBoxExtents = box.mExtents; Matrix4x4 WorldB; if(worldb) { WorldB = Matrix4x4( box.mRot * Matrix3x3(*worldb) ); WorldB.SetTrans(box.mCenter * *worldb); } else { WorldB = box.mRot; WorldB.SetTrans(box.mCenter); } // Setup matrices Matrix4x4 InvWorldB; InvertPRMatrix(InvWorldB, WorldB); if(worldm) { Matrix4x4 InvWorldM; InvertPRMatrix(InvWorldM, *worldm); Matrix4x4 WorldBtoM = WorldB * InvWorldM; Matrix4x4 WorldMtoB = *worldm * InvWorldB; mRModelToBox = WorldMtoB; WorldMtoB.GetTrans(mTModelToBox); mRBoxToModel = WorldBtoM; WorldBtoM.GetTrans(mTBoxToModel); } else { mRModelToBox = InvWorldB; InvWorldB.GetTrans(mTModelToBox); mRBoxToModel = WorldB; WorldB.GetTrans(mTBoxToModel); } // 3) Setup destination pointer mTouchedPrimitives = &cache.TouchedPrimitives; // 4) Special case: 1-triangle meshes [Opcode 1.3] if(mCurrentModel && mCurrentModel->HasSingleNode()) { if(!SkipPrimitiveTests()) { // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. mTouchedPrimitives->Reset(); // Perform overlap test between the unique triangle and the box (and set contact status if needed) OBB_PRIM(udword(0), OPC_CONTACT) // Return immediately regardless of status return TRUE; } } // 5) Check temporal coherence: if(TemporalCoherenceEnabled()) { // Here we use temporal coherence // => check results from previous frame before performing the collision query if(FirstContactEnabled()) { // We're only interested in the first contact found => test the unique previously touched face if(mTouchedPrimitives->GetNbEntries()) { // Get index of previously touched face = the first entry in the array udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); // Then reset the array: // - if the overlap test below is successful, the index we'll get added back anyway // - if it isn't, then the array should be reset anyway for the normal query mTouchedPrimitives->Reset(); // Perform overlap test between the cached triangle and the box (and set contact status if needed) OBB_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) // Return immediately if possible if(GetContactStatus()) return TRUE; } // else no face has been touched during previous query // => we'll have to perform a normal query } else { // ### rewrite this OBB TestBox(mTBoxToModel, mBoxExtents, mRBoxToModel); // We're interested in all contacts =>test the new real box N(ew) against the previous fat box P(revious): if(IsCacheValid(cache) && TestBox.IsInside(cache.FatBox)) { // - if N is included in P, return previous list // => we simply leave the list (mTouchedFaces) unchanged // Set contact status if needed if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; // In any case we don't need to do a query return TRUE; } else { // - else do the query using a fat N // Reset cache since we'll about to perform a real query mTouchedPrimitives->Reset(); // Make a fat box so that coherence will work for subsequent frames TestBox.mExtents *= cache.FatCoeff; mBoxExtents *= cache.FatCoeff; // Update cache with query data (signature for cached faces) cache.FatBox = TestBox; } } } else { // Here we don't use temporal coherence => do a normal query mTouchedPrimitives->Reset(); } // Now we can precompute box-box data // Precompute absolute box-to-model rotation matrix for(udword i=0;i<3;i++) { for(udword j=0;j<3;j++) { // Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID) mAR.m[i][j] = 1e-6f + fabsf(mRBoxToModel.m[i][j]); } } // Precompute bounds for box-in-box test mB0 = mBoxExtents - mTModelToBox; mB1 = - mBoxExtents - mTModelToBox; // Precompute box-box data - Courtesy of Erwin de Vries mBBx1 = mBoxExtents.x*mAR.m[0][0] + mBoxExtents.y*mAR.m[1][0] + mBoxExtents.z*mAR.m[2][0]; mBBy1 = mBoxExtents.x*mAR.m[0][1] + mBoxExtents.y*mAR.m[1][1] + mBoxExtents.z*mAR.m[2][1]; mBBz1 = mBoxExtents.x*mAR.m[0][2] + mBoxExtents.y*mAR.m[1][2] + mBoxExtents.z*mAR.m[2][2]; mBB_1 = mBoxExtents.y*mAR.m[2][0] + mBoxExtents.z*mAR.m[1][0]; mBB_2 = mBoxExtents.x*mAR.m[2][0] + mBoxExtents.z*mAR.m[0][0]; mBB_3 = mBoxExtents.x*mAR.m[1][0] + mBoxExtents.y*mAR.m[0][0]; mBB_4 = mBoxExtents.y*mAR.m[2][1] + mBoxExtents.z*mAR.m[1][1]; mBB_5 = mBoxExtents.x*mAR.m[2][1] + mBoxExtents.z*mAR.m[0][1]; mBB_6 = mBoxExtents.x*mAR.m[1][1] + mBoxExtents.y*mAR.m[0][1]; mBB_7 = mBoxExtents.y*mAR.m[2][2] + mBoxExtents.z*mAR.m[1][2]; mBB_8 = mBoxExtents.x*mAR.m[2][2] + mBoxExtents.z*mAR.m[0][2]; mBB_9 = mBoxExtents.x*mAR.m[1][2] + mBoxExtents.y*mAR.m[0][2]; return FALSE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the OBB completely contains the box. In which case we can end the query sooner. * \param bc [in] box center * \param be [in] box extents * \return true if the OBB contains the whole box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL OBBCollider::OBBContainsBox(const Point& bc, const Point& be) { // I assume if all 8 box vertices are inside the OBB, so does the whole box. // Sounds ok but maybe there's a better way? /* #define TEST_PT(a,b,c) \ p.x=a; p.y=b; p.z=c; p+=bc; \ f = p.x * mRModelToBox.m[0][0] + p.y * mRModelToBox.m[1][0] + p.z * mRModelToBox.m[2][0]; if(f>mB0.x || fmB0.y || fmB0.z || f NCx-NEx) return FALSE; float NCy = bc.x * mRModelToBox.m[0][1] + bc.y * mRModelToBox.m[1][1] + bc.z * mRModelToBox.m[2][1]; float NEy = fabsf(mRModelToBox.m[0][1] * be.x) + fabsf(mRModelToBox.m[1][1] * be.y) + fabsf(mRModelToBox.m[2][1] * be.z); if(mB0.y < NCy+NEy) return FALSE; if(mB1.y > NCy-NEy) return FALSE; float NCz = bc.x * mRModelToBox.m[0][2] + bc.y * mRModelToBox.m[1][2] + bc.z * mRModelToBox.m[2][2]; float NEz = fabsf(mRModelToBox.m[0][2] * be.x) + fabsf(mRModelToBox.m[1][2] * be.y) + fabsf(mRModelToBox.m[2][2] * be.z); if(mB0.z < NCz+NEz) return FALSE; if(mB1.z > NCz-NEz) return FALSE; return TRUE; } #define TEST_BOX_IN_OBB(center, extents) \ if(OBBContainsBox(center, extents)) \ { \ /* Set contact status */ \ mFlags |= OPC_CONTACT; \ _Dump(node); \ return; \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_Collide(const AABBCollisionNode* node) { // Perform OBB-AABB overlap test if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { OBB_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) { // Perform OBB-AABB overlap test if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_Collide(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform OBB-AABB overlap test if(!BoxBoxOverlap(Extents, Center)) return; TEST_BOX_IN_OBB(Center, Extents) if(node->IsLeaf()) { OBB_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform OBB-AABB overlap test if(!BoxBoxOverlap(Extents, Center)) return; TEST_BOX_IN_OBB(Center, Extents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_Collide(const AABBNoLeafNode* node) { // Perform OBB-AABB overlap test if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { OBB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { OBB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) { // Perform OBB-AABB overlap test if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_Collide(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform OBB-AABB overlap test if(!BoxBoxOverlap(Extents, Center)) return; TEST_BOX_IN_OBB(Center, Extents) if(node->HasPosLeaf()) { OBB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { OBB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void OBBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform OBB-AABB overlap test if(!BoxBoxOverlap(Extents, Center)) return; TEST_BOX_IN_OBB(Center, Extents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridOBBCollider::HybridOBBCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridOBBCollider::~HybridOBBCollider() { } bool HybridOBBCollider::Collide(OBBCache& cache, const OBB& box, const HybridModel& model, const Matrix4x4* worldb, const Matrix4x4* worldm) { // We don't want primitive tests here! mFlags |= OPC_NO_PRIMITIVE_TESTS; // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, box, worldb, worldm)) return true; // Special case for 1-leaf trees if(mCurrentModel && mCurrentModel->HasSingleNode()) { // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles udword Nb = mIMesh->GetNbTriangles(); // Loop through all triangles for(udword i=0;imCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } // We only have a list of boxes so far if(GetContactStatus()) { // Reset contact status, since it currently only reflects collisions with leaf boxes Collider::InitQuery(); // Change dest container so that we can use built-in overlap tests and get collided primitives cache.TouchedPrimitives.Reset(); mTouchedPrimitives = &cache.TouchedPrimitives; // Read touched leaf boxes udword Nb = mTouchedBoxes.GetNbEntries(); const udword* Touched = mTouchedBoxes.GetEntries(); const LeafTriangles* LT = model.GetLeafTriangles(); const udword* Indices = model.GetIndices(); // Loop through touched leaves while(Nb--) { const LeafTriangles& CurrentLeaf = LT[*Touched++]; // Each leaf box has a set of triangles udword NbTris = CurrentLeaf.GetNbTriangles(); if(Indices) { const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = *T++; OBB_PRIM(TriangleIndex, OPC_CONTACT) } } else { udword BaseIndex = CurrentLeaf.GetTriangleIndex(); // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = BaseIndex++; OBB_PRIM(TriangleIndex, OPC_CONTACT) } } } } return true; } ode-0.14/OPCODE/OPC_OBBCollider.h0000644000000000000000000001502612635011627014615 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for an OBB collider. * \file OPC_OBBCollider.h * \author Pierre Terdiman * \date January, 1st, 2002 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_OBBCOLLIDER_H__ #define __OPC_OBBCOLLIDER_H__ struct OPCODE_API OBBCache : VolumeCache { OBBCache() : FatCoeff(1.1f) { FatBox.mCenter.Zero(); FatBox.mExtents.Zero(); FatBox.mRot.Identity(); } // Cached faces signature OBB FatBox; //!< Box used when performing the query resulting in cached faces // User settings float FatCoeff; //!< extents multiplier used to create a fat box }; class OPCODE_API OBBCollider : public VolumeCollider { public: // Constructor / Destructor OBBCollider(); virtual ~OBBCollider(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] a box cache * \param box [in] collision OBB in local space * \param model [in] Opcode model to collide with * \param worldb [in] OBB's world matrix, or null * \param worldm [in] model's world matrix, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Collide(OBBCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); // Settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Settings: select between full box-box tests or "SAT-lite" tests (where Class III axes are discarded) * \param flag [in] true for full tests, false for coarse tests */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetFullBoxBoxTest(bool flag) { mFullBoxBoxTest = flag; } // Settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(Collider) const char* ValidateSettings(); protected: // Precomputed data Matrix3x3 mAR; //!< Absolute rotation matrix Matrix3x3 mRModelToBox; //!< Rotation from model space to obb space Matrix3x3 mRBoxToModel; //!< Rotation from obb space to model space Point mTModelToBox; //!< Translation from model space to obb space Point mTBoxToModel; //!< Translation from obb space to model space Point mBoxExtents; Point mB0; //!< - mTModelToBox + mBoxExtents Point mB1; //!< - mTModelToBox - mBoxExtents float mBBx1; float mBBy1; float mBBz1; float mBB_1; float mBB_2; float mBB_3; float mBB_4; float mBB_5; float mBB_6; float mBB_7; float mBB_8; float mBB_9; // Leaf description Point mLeafVerts[3]; //!< Triangle vertices // Settings bool mFullBoxBoxTest; //!< Perform full BV-BV tests (true) or SAT-lite tests (false) // Internal methods void _Collide(const AABBCollisionNode* node); void _Collide(const AABBNoLeafNode* node); void _Collide(const AABBQuantizedNode* node); void _Collide(const AABBQuantizedNoLeafNode* node); void _CollideNoPrimitiveTest(const AABBCollisionNode* node); void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); // Overlap tests inline_ BOOL OBBContainsBox(const Point& bc, const Point& be); inline_ BOOL BoxBoxOverlap(const Point& extents, const Point& center); inline_ BOOL TriBoxOverlap(); // Init methods BOOL InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); }; class OPCODE_API HybridOBBCollider : public OBBCollider { public: // Constructor / Destructor HybridOBBCollider(); virtual ~HybridOBBCollider(); bool Collide(OBBCache& cache, const OBB& box, const HybridModel& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); protected: Container mTouchedBoxes; }; #endif // __OPC_OBBCOLLIDER_H__ ode-0.14/OPCODE/OPC_OptimizedTree.cpp0000644000000000000000000007760712635011627015671 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for optimized trees. Implements 4 trees: * - normal * - no leaf * - quantized * - no leaf / quantized * * \file OPC_OptimizedTree.cpp * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A standard AABB tree. * * \class AABBCollisionTree * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A no-leaf AABB tree. * * \class AABBNoLeafTree * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A quantized AABB tree. * * \class AABBQuantizedTree * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A quantized no-leaf AABB tree. * * \class AABBQuantizedNoLeafTree * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; //! Compilation flag: //! - true to fix quantized boxes (i.e. make sure they enclose the original ones) //! - false to see the effects of quantization errors (faster, but wrong results in some cases) static const bool gFixQuantized = true; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds an implicit tree from a standard one. An implicit tree is a complete tree (2*N-1 nodes) whose negative * box pointers and primitive pointers have been made implicit, hence packing 3 pointers in one. * * Layout for implicit trees: * Node: * - box * - data (32-bits value) * * if data's LSB = 1 => remaining bits are a primitive pointer * else remaining bits are a P-node pointer, and N = P + 1 * * \relates AABBCollisionNode * \fn _BuildCollisionTree(AABBCollisionNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) * \param linear [in] base address of destination nodes * \param box_id [in] index of destination node * \param current_id [in] current running index * \param current_node [in] current node from input tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void _BuildCollisionTree(AABBCollisionNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) { // Current node from input tree is "current_node". Must be flattened into "linear[boxid]". // Store the AABB current_node->GetAABB()->GetCenter(linear[box_id].mAABB.mCenter); current_node->GetAABB()->GetExtents(linear[box_id].mAABB.mExtents); // Store remaining info if(current_node->IsLeaf()) { // The input tree must be complete => i.e. one primitive/leaf ASSERT(current_node->GetNbPrimitives()==1); // Get the primitive index from the input tree udword PrimitiveIndex = current_node->GetPrimitives()[0]; // Setup box data as the primitive index, marked as leaf linear[box_id].mData = (PrimitiveIndex<<1)|1; } else { // To make the negative one implicit, we must store P and N in successive order udword PosID = current_id++; // Get a new id for positive child udword NegID = current_id++; // Get a new id for negative child // Setup box data as the forthcoming new P pointer linear[box_id].mData = (size_t)&linear[PosID]; // Make sure it's not marked as leaf ASSERT(!(linear[box_id].mData&1)); // Recurse with new IDs _BuildCollisionTree(linear, PosID, current_id, current_node->GetPos()); _BuildCollisionTree(linear, NegID, current_id, current_node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds a "no-leaf" tree from a standard one. This is a tree whose leaf nodes have been removed. * * Layout for no-leaf trees: * * Node: * - box * - P pointer => a node (LSB=0) or a primitive (LSB=1) * - N pointer => a node (LSB=0) or a primitive (LSB=1) * * \relates AABBNoLeafNode * \fn _BuildNoLeafTree(AABBNoLeafNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) * \param linear [in] base address of destination nodes * \param box_id [in] index of destination node * \param current_id [in] current running index * \param current_node [in] current node from input tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void _BuildNoLeafTree(AABBNoLeafNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) { const AABBTreeNode* P = current_node->GetPos(); const AABBTreeNode* N = current_node->GetNeg(); // Leaf nodes here?! ASSERT(P); ASSERT(N); // Internal node => keep the box current_node->GetAABB()->GetCenter(linear[box_id].mAABB.mCenter); current_node->GetAABB()->GetExtents(linear[box_id].mAABB.mExtents); if(P->IsLeaf()) { // The input tree must be complete => i.e. one primitive/leaf ASSERT(P->GetNbPrimitives()==1); // Get the primitive index from the input tree udword PrimitiveIndex = P->GetPrimitives()[0]; // Setup prev box data as the primitive index, marked as leaf linear[box_id].mPosData = (PrimitiveIndex<<1)|1; } else { // Get a new id for positive child udword PosID = current_id++; // Setup box data linear[box_id].mPosData = (size_t)&linear[PosID]; // Make sure it's not marked as leaf ASSERT(!(linear[box_id].mPosData&1)); // Recurse _BuildNoLeafTree(linear, PosID, current_id, P); } if(N->IsLeaf()) { // The input tree must be complete => i.e. one primitive/leaf ASSERT(N->GetNbPrimitives()==1); // Get the primitive index from the input tree udword PrimitiveIndex = N->GetPrimitives()[0]; // Setup prev box data as the primitive index, marked as leaf linear[box_id].mNegData = (PrimitiveIndex<<1)|1; } else { // Get a new id for negative child udword NegID = current_id++; // Setup box data linear[box_id].mNegData = (size_t)&linear[NegID]; // Make sure it's not marked as leaf ASSERT(!(linear[box_id].mNegData&1)); // Recurse _BuildNoLeafTree(linear, NegID, current_id, N); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBCollisionTree::AABBCollisionTree() : mNodes(null) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBCollisionTree::~AABBCollisionTree() { DELETEARRAY(mNodes); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds the collision tree from a generic AABB tree. * \param tree [in] generic AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBCollisionTree::Build(AABBTree* tree) { // Checkings if(!tree) return false; // Check the input tree is complete udword NbTriangles = tree->GetNbPrimitives(); udword NbNodes = tree->GetNbNodes(); if(NbNodes!=NbTriangles*2-1) return false; // Get nodes if(mNbNodes!=NbNodes) // Same number of nodes => keep moving { mNbNodes = NbNodes; DELETEARRAY(mNodes); mNodes = new AABBCollisionNode[mNbNodes]; CHECKALLOC(mNodes); } // Build the tree udword CurID = 1; _BuildCollisionTree(mNodes, 0, CurID, tree); ASSERT(CurID==mNbNodes); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the collision tree after vertices have been modified. * \param mesh_interface [in] mesh interface for current model * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBCollisionTree::Refit(const MeshInterface* /*mesh_interface*/) { ASSERT(!"Not implemented since AABBCollisionTrees have twice as more nodes to refit as AABBNoLeafTrees!"); return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Walks the tree and call the user back for each node. * \param callback [in] walking callback * \param user_data [in] callback's user data * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBCollisionTree::Walk(GenericWalkingCallback callback, void* user_data) const { if(!callback) return false; struct Local { static void _Walk(const AABBCollisionNode* current_node, GenericWalkingCallback callback, void* user_data) { if(!current_node || !(callback)(current_node, user_data)) return; if(!current_node->IsLeaf()) { _Walk(current_node->GetPos(), callback, user_data); _Walk(current_node->GetNeg(), callback, user_data); } } }; Local::_Walk(mNodes, callback, user_data); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBNoLeafTree::AABBNoLeafTree() : mNodes(null) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBNoLeafTree::~AABBNoLeafTree() { DELETEARRAY(mNodes); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds the collision tree from a generic AABB tree. * \param tree [in] generic AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBNoLeafTree::Build(AABBTree* tree) { // Checkings if(!tree) return false; // Check the input tree is complete udword NbTriangles = tree->GetNbPrimitives(); udword NbNodes = tree->GetNbNodes(); if(NbNodes!=NbTriangles*2-1) return false; // Get nodes if(mNbNodes!=NbTriangles-1) // Same number of nodes => keep moving { mNbNodes = NbTriangles-1; DELETEARRAY(mNodes); mNodes = new AABBNoLeafNode[mNbNodes]; CHECKALLOC(mNodes); } // Build the tree udword CurID = 1; _BuildNoLeafTree(mNodes, 0, CurID, tree); ASSERT(CurID==mNbNodes); return true; } inline_ void ComputeMinMax(Point& min, Point& max, const VertexPointers& vp) { // Compute triangle's AABB = a leaf box #ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); #else min = *vp.Vertex[0]; max = *vp.Vertex[0]; min.Min(*vp.Vertex[1]); max.Max(*vp.Vertex[1]); min.Min(*vp.Vertex[2]); max.Max(*vp.Vertex[2]); #endif } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the collision tree after vertices have been modified. * \param mesh_interface [in] mesh interface for current model * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBNoLeafTree::Refit(const MeshInterface* mesh_interface) { // Checkings if(!mesh_interface) return false; // Bottom-up update VertexPointers VP; ConversionArea VC; Point Min,Max; Point Min_,Max_; udword Index = mNbNodes; while(Index--) { AABBNoLeafNode& Current = mNodes[Index]; if(Current.HasPosLeaf()) { mesh_interface->GetTriangle(VP, Current.GetPosPrimitive(), VC); ComputeMinMax(Min, Max, VP); } else { const CollisionAABB& CurrentBox = Current.GetPos()->mAABB; CurrentBox.GetMin(Min); CurrentBox.GetMax(Max); } if(Current.HasNegLeaf()) { mesh_interface->GetTriangle(VP, Current.GetNegPrimitive(), VC); ComputeMinMax(Min_, Max_, VP); } else { const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB; CurrentBox.GetMin(Min_); CurrentBox.GetMax(Max_); } #ifdef OPC_USE_FCOMI Min.x = FCMin2(Min.x, Min_.x); Max.x = FCMax2(Max.x, Max_.x); Min.y = FCMin2(Min.y, Min_.y); Max.y = FCMax2(Max.y, Max_.y); Min.z = FCMin2(Min.z, Min_.z); Max.z = FCMax2(Max.z, Max_.z); #else Min.Min(Min_); Max.Max(Max_); #endif Current.mAABB.SetMinMax(Min, Max); } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Walks the tree and call the user back for each node. * \param callback [in] walking callback * \param user_data [in] callback's user data * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBNoLeafTree::Walk(GenericWalkingCallback callback, void* user_data) const { if(!callback) return false; struct Local { static void _Walk(const AABBNoLeafNode* current_node, GenericWalkingCallback callback, void* user_data) { if(!current_node || !(callback)(current_node, user_data)) return; if(!current_node->HasPosLeaf()) _Walk(current_node->GetPos(), callback, user_data); if(!current_node->HasNegLeaf()) _Walk(current_node->GetNeg(), callback, user_data); } }; Local::_Walk(mNodes, callback, user_data); return true; } // Quantization notes: // - We could use the highest bits of mData to store some more quantized bits. Dequantization code // would be slightly more complex, but number of overlap tests would be reduced (and anyhow those // bits are currently wasted). Of course it's not possible if we move to 16 bits mData. // - Something like "16 bits floats" could be tested, to bypass the int-to-float conversion. // - A dedicated BV-BV test could be used, dequantizing while testing for overlap. (i.e. it's some // lazy-dequantization which may save some work in case of early exits). At the very least some // muls could be saved by precomputing several more matrices. But maybe not worth the pain. // - Do we need to dequantize anyway? Not doing the extents-related muls only implies the box has // been scaled, for example. // - The deeper we move into the hierarchy, the smaller the extents should be. May not need a fixed // number of quantization bits. Even better, could probably be best delta-encoded. // Find max values. Some people asked why I wasn't simply using the first node. Well, I can't. // I'm not looking for (min, max) values like in a standard AABB, I'm looking for the extremal // centers/extents in order to quantize them. The first node would only give a single center and // a single extents. While extents would be the biggest, the center wouldn't. #define FIND_MAX_VALUES \ /* Get max values */ \ Point CMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \ Point EMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \ for(udword i=0;iCMax.x) CMax.x = fabsf(Nodes[i].mAABB.mCenter.x); \ if(fabsf(Nodes[i].mAABB.mCenter.y)>CMax.y) CMax.y = fabsf(Nodes[i].mAABB.mCenter.y); \ if(fabsf(Nodes[i].mAABB.mCenter.z)>CMax.z) CMax.z = fabsf(Nodes[i].mAABB.mCenter.z); \ if(fabsf(Nodes[i].mAABB.mExtents.x)>EMax.x) EMax.x = fabsf(Nodes[i].mAABB.mExtents.x); \ if(fabsf(Nodes[i].mAABB.mExtents.y)>EMax.y) EMax.y = fabsf(Nodes[i].mAABB.mExtents.y); \ if(fabsf(Nodes[i].mAABB.mExtents.z)>EMax.z) EMax.z = fabsf(Nodes[i].mAABB.mExtents.z); \ } #define INIT_QUANTIZATION \ udword nbc=15; /* Keep one bit for sign */ \ udword nbe=15; /* Keep one bit for fix */ \ if(!gFixQuantized) nbe++; \ \ /* Compute quantization coeffs */ \ Point CQuantCoeff, EQuantCoeff; \ CQuantCoeff.x = CMax.x!=0.0f ? float((1<Min[j]) mNodes[i].mAABB.mExtents[j]++; \ else FixMe=false; \ /* Prevent wrapping */ \ if(!mNodes[i].mAABB.mExtents[j]) \ { \ mNodes[i].mAABB.mExtents[j]=0xffff; \ FixMe=false; \ } \ }while(FixMe); \ } \ } #define REMAP_DATA(member) \ /* Fix data */ \ Data = Nodes[i].member; \ if(!(Data&1)) \ { \ /* Compute box number */ \ size_t Nb = (Data - size_t(Nodes))/Nodes[i].GetNodeSize(); \ Data = (size_t) &mNodes[Nb]; \ } \ /* ...remapped */ \ mNodes[i].member = Data; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBQuantizedTree::AABBQuantizedTree() : mNodes(null) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBQuantizedTree::~AABBQuantizedTree() { DELETEARRAY(mNodes); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds the collision tree from a generic AABB tree. * \param tree [in] generic AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBQuantizedTree::Build(AABBTree* tree) { // Checkings if(!tree) return false; // Check the input tree is complete udword NbTriangles = tree->GetNbPrimitives(); udword NbNodes = tree->GetNbNodes(); if(NbNodes!=NbTriangles*2-1) return false; // Get nodes mNbNodes = NbNodes; DELETEARRAY(mNodes); AABBCollisionNode* Nodes = new AABBCollisionNode[mNbNodes]; CHECKALLOC(Nodes); // Build the tree udword CurID = 1; _BuildCollisionTree(Nodes, 0, CurID, tree); // Quantize { mNodes = new AABBQuantizedNode[mNbNodes]; CHECKALLOC(mNodes); // Get max values FIND_MAX_VALUES // Quantization INIT_QUANTIZATION // Quantize size_t Data; for(udword i=0;iIsLeaf()) { _Walk(current_node->GetPos(), callback, user_data); _Walk(current_node->GetNeg(), callback, user_data); } } }; Local::_Walk(mNodes, callback, user_data); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBQuantizedNoLeafTree::AABBQuantizedNoLeafTree() : mNodes(null) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// AABBQuantizedNoLeafTree::~AABBQuantizedNoLeafTree() { DELETEARRAY(mNodes); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds the collision tree from a generic AABB tree. * \param tree [in] generic AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBQuantizedNoLeafTree::Build(AABBTree* tree) { // Checkings if(!tree) return false; // Check the input tree is complete udword NbTriangles = tree->GetNbPrimitives(); udword NbNodes = tree->GetNbNodes(); if(NbNodes!=NbTriangles*2-1) return false; // Get nodes mNbNodes = NbTriangles-1; DELETEARRAY(mNodes); AABBNoLeafNode* Nodes = new AABBNoLeafNode[mNbNodes]; CHECKALLOC(Nodes); // Build the tree udword CurID = 1; _BuildNoLeafTree(Nodes, 0, CurID, tree); ASSERT(CurID==mNbNodes); // Quantize { mNodes = new AABBQuantizedNoLeafNode[mNbNodes]; CHECKALLOC(mNodes); // Get max values FIND_MAX_VALUES // Quantization INIT_QUANTIZATION // Quantize size_t Data; for(udword i=0;iHasPosLeaf()) _Walk(current_node->GetPos(), callback, user_data); if(!current_node->HasNegLeaf()) _Walk(current_node->GetNeg(), callback, user_data); } }; Local::_Walk(mNodes, callback, user_data); return true; } ode-0.14/OPCODE/OPC_OptimizedTree.h0000644000000000000000000002227212635011627015322 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for optimized trees. * \file OPC_OptimizedTree.h * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_OPTIMIZEDTREE_H__ #define __OPC_OPTIMIZEDTREE_H__ //! Common interface for a node of an implicit tree #define IMPLEMENT_IMPLICIT_NODE(base_class, volume) \ public: \ /* Constructor / Destructor */ \ inline_ base_class() : mData(0) {} \ inline_ ~base_class() {} \ /* Leaf test */ \ inline_ BOOL IsLeaf() const { return (mData&1)!=0; } \ /* Data access */ \ inline_ const base_class* GetPos() const { return (base_class*)mData; } \ inline_ const base_class* GetNeg() const { return ((base_class*)mData)+1; } \ inline_ size_t GetPrimitive() const { return (mData>>1); } \ /* Stats */ \ inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ \ volume mAABB; \ size_t mData; //! Common interface for a node of a no-leaf tree #define IMPLEMENT_NOLEAF_NODE(base_class, volume) \ public: \ /* Constructor / Destructor */ \ inline_ base_class() : mPosData(0), mNegData(0) {} \ inline_ ~base_class() {} \ /* Leaf tests */ \ inline_ BOOL HasPosLeaf() const { return (mPosData&1)!=0; } \ inline_ BOOL HasNegLeaf() const { return (mNegData&1)!=0; } \ /* Data access */ \ inline_ const base_class* GetPos() const { return (base_class*)mPosData; } \ inline_ const base_class* GetNeg() const { return (base_class*)mNegData; } \ inline_ size_t GetPosPrimitive() const { return (mPosData>>1); } \ inline_ size_t GetNegPrimitive() const { return (mNegData>>1); } \ /* Stats */ \ inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ \ volume mAABB; \ size_t mPosData; \ size_t mNegData; class OPCODE_API AABBCollisionNode { IMPLEMENT_IMPLICIT_NODE(AABBCollisionNode, CollisionAABB) inline_ float GetVolume() const { return mAABB.mExtents.x * mAABB.mExtents.y * mAABB.mExtents.z; } inline_ float GetSize() const { return mAABB.mExtents.SquareMagnitude(); } inline_ udword GetRadius() const { udword* Bits = (udword*)&mAABB.mExtents.x; udword Max = Bits[0]; if(Bits[1]>Max) Max = Bits[1]; if(Bits[2]>Max) Max = Bits[2]; return Max; } // NB: using the square-magnitude or the true volume of the box, seems to yield better results // (assuming UNC-like informed traversal methods). I borrowed this idea from PQP. The usual "size" // otherwise, is the largest box extent. In SOLID that extent is computed on-the-fly each time it's // needed (the best approach IMHO). In RAPID the rotation matrix is permuted so that Extent[0] is // always the greatest, which saves looking for it at runtime. On the other hand, it yields matrices // whose determinant is not 1, i.e. you can't encode them anymore as unit quaternions. Not a very // good strategy. }; class OPCODE_API AABBQuantizedNode { IMPLEMENT_IMPLICIT_NODE(AABBQuantizedNode, QuantizedAABB) inline_ uword GetSize() const { const uword* Bits = mAABB.mExtents; uword Max = Bits[0]; if(Bits[1]>Max) Max = Bits[1]; if(Bits[2]>Max) Max = Bits[2]; return Max; } // NB: for quantized nodes I don't feel like computing a square-magnitude with integers all // over the place.......! }; class OPCODE_API AABBNoLeafNode { IMPLEMENT_NOLEAF_NODE(AABBNoLeafNode, CollisionAABB) }; class OPCODE_API AABBQuantizedNoLeafNode { IMPLEMENT_NOLEAF_NODE(AABBQuantizedNoLeafNode, QuantizedAABB) }; //! Common interface for a collision tree #define IMPLEMENT_COLLISION_TREE(base_class, node) \ public: \ /* Constructor / Destructor */ \ base_class(); \ virtual ~base_class(); \ /* Builds from a standard tree */ \ override(AABBOptimizedTree) bool Build(AABBTree* tree); \ /* Refits the tree */ \ override(AABBOptimizedTree) bool Refit(const MeshInterface* mesh_interface); \ /* Walks the tree */ \ override(AABBOptimizedTree) bool Walk(GenericWalkingCallback callback, void* user_data) const; \ /* Data access */ \ inline_ const node* GetNodes() const { return mNodes; } \ /* Stats */ \ override(AABBOptimizedTree) udword GetUsedBytes() const { return mNbNodes*sizeof(node); } \ private: \ node* mNodes; typedef bool (*GenericWalkingCallback) (const void* current, void* user_data); class OPCODE_API AABBOptimizedTree { public: // Constructor / Destructor AABBOptimizedTree() : mNbNodes (0) {} virtual ~AABBOptimizedTree() {} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Builds the collision tree from a generic AABB tree. * \param tree [in] generic AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual bool Build(AABBTree* tree) = 0; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Refits the collision tree after vertices have been modified. * \param mesh_interface [in] mesh interface for current model * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual bool Refit(const MeshInterface* mesh_interface) = 0; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Walks the tree and call the user back for each node. * \param callback [in] walking callback * \param user_data [in] callback's user data * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// virtual bool Walk(GenericWalkingCallback callback, void* user_data) const = 0; // Data access virtual udword GetUsedBytes() const = 0; inline_ udword GetNbNodes() const { return mNbNodes; } protected: udword mNbNodes; }; class OPCODE_API AABBCollisionTree : public AABBOptimizedTree { IMPLEMENT_COLLISION_TREE(AABBCollisionTree, AABBCollisionNode) }; class OPCODE_API AABBNoLeafTree : public AABBOptimizedTree { IMPLEMENT_COLLISION_TREE(AABBNoLeafTree, AABBNoLeafNode) }; class OPCODE_API AABBQuantizedTree : public AABBOptimizedTree { IMPLEMENT_COLLISION_TREE(AABBQuantizedTree, AABBQuantizedNode) public: Point mCenterCoeff; Point mExtentsCoeff; }; class OPCODE_API AABBQuantizedNoLeafTree : public AABBOptimizedTree { IMPLEMENT_COLLISION_TREE(AABBQuantizedNoLeafTree, AABBQuantizedNoLeafNode) public: Point mCenterCoeff; Point mExtentsCoeff; }; #endif // __OPC_OPTIMIZEDTREE_H__ ode-0.14/OPCODE/OPC_Picking.cpp0000644000000000000000000001231012635011627014445 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code to perform "picking". * \file OPC_Picking.cpp * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; #ifdef OPC_RAYHIT_CALLBACK /* Possible RayCollider usages: - boolean query (shadow feeler) - closest hit - all hits - number of intersection (boolean) */ bool Opcode::SetupAllHits(RayCollider& collider, CollisionFaces& contacts) { struct Local { static void AllContacts(const CollisionFace& hit, void* user_data) { CollisionFaces* CF = (CollisionFaces*)user_data; CF->AddFace(hit); } }; collider.SetFirstContact(false); collider.SetHitCallback(Local::AllContacts); collider.SetUserData(&contacts); return true; } bool Opcode::SetupClosestHit(RayCollider& collider, CollisionFace& closest_contact) { struct Local { static void ClosestContact(const CollisionFace& hit, void* user_data) { CollisionFace* CF = (CollisionFace*)user_data; if(hit.mDistancemDistance) *CF = hit; } }; collider.SetFirstContact(false); collider.SetHitCallback(Local::ClosestContact); collider.SetUserData(&closest_contact); closest_contact.mDistance = MAX_FLOAT; return true; } bool Opcode::SetupShadowFeeler(RayCollider& collider) { collider.SetFirstContact(true); collider.SetHitCallback(null); return true; } bool Opcode::SetupInOutTest(RayCollider& collider) { collider.SetFirstContact(false); collider.SetHitCallback(null); // Results with collider.GetNbIntersections() return true; } bool Opcode::Picking( CollisionFace& picked_face, const Ray& world_ray, const Model& model, const Matrix4x4* world, float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data) { struct Local { struct CullData { CollisionFace* Closest; float MinLimit; CullModeCallback Callback; void* UserData; Point ViewPoint; const MeshInterface* IMesh; }; // Called for each stabbed face static void RenderCullingCallback(const CollisionFace& hit, void* user_data) { CullData* Data = (CullData*)user_data; // Discard face if we already have a closer hit if(hit.mDistance>=Data->Closest->mDistance) return; // Discard face if hit point is smaller than min limit. This mainly happens when the face is in front // of the near clip plane (or straddles it). If we keep the face nonetheless, the user can select an // object that he may not even be able to see, which is very annoying. if(hit.mDistance<=Data->MinLimit) return; // This is the index of currently stabbed triangle. udword StabbedFaceIndex = hit.mFaceID; // We may keep it or not, depending on backface culling bool KeepIt = true; // Catch *render* cull mode for this face CullMode CM = (Data->Callback)(StabbedFaceIndex, Data->UserData); if(CM!=CULLMODE_NONE) // Don't even compute culling for double-sided triangles { // Compute backface culling for current face VertexPointers VP; ConversionArea VC; Data->IMesh->GetTriangle(VP, StabbedFaceIndex, VC); if(VP.BackfaceCulling(Data->ViewPoint)) { if(CM==CULLMODE_CW) KeepIt = false; } else { if(CM==CULLMODE_CCW) KeepIt = false; } } if(KeepIt) *Data->Closest = hit; } }; RayCollider RC; RC.SetMaxDist(max_dist); RC.SetTemporalCoherence(false); RC.SetCulling(false); // We need all faces since some of them can be double-sided RC.SetFirstContact(false); RC.SetHitCallback(Local::RenderCullingCallback); picked_face.mFaceID = INVALID_ID; picked_face.mDistance = MAX_FLOAT; picked_face.mU = 0.0f; picked_face.mV = 0.0f; Local::CullData Data; Data.Closest = &picked_face; Data.MinLimit = min_dist; Data.Callback = callback; Data.UserData = user_data; Data.ViewPoint = view_point; Data.IMesh = model.GetMeshInterface(); if(world) { // Get matrices Matrix4x4 InvWorld; InvertPRMatrix(InvWorld, *world); // Compute camera position in mesh space Data.ViewPoint *= InvWorld; } RC.SetUserData(&Data); if(RC.Collide(world_ray, model, world)) { return picked_face.mFaceID!=INVALID_ID; } return false; } #endif ode-0.14/OPCODE/OPC_Picking.h0000644000000000000000000000405412635011627014120 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code to perform "picking". * \file OPC_Picking.h * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_PICKING_H__ #define __OPC_PICKING_H__ #ifdef OPC_RAYHIT_CALLBACK enum CullMode { CULLMODE_NONE = 0, CULLMODE_CW = 1, CULLMODE_CCW = 2 }; typedef CullMode (*CullModeCallback)(udword triangle_index, void* user_data); OPCODE_API bool SetupAllHits (RayCollider& collider, CollisionFaces& contacts); OPCODE_API bool SetupClosestHit (RayCollider& collider, CollisionFace& closest_contact); OPCODE_API bool SetupShadowFeeler (RayCollider& collider); OPCODE_API bool SetupInOutTest (RayCollider& collider); OPCODE_API bool Picking( CollisionFace& picked_face, const Ray& world_ray, const Model& model, const Matrix4x4* world, float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data); #endif #endif //__OPC_PICKING_H__ ode-0.14/OPCODE/OPC_PlanesAABBOverlap.h0000644000000000000000000000500012635011627015705 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Planes-AABB overlap test. * - original code by Ville Miettinen, from Umbra/dPVS (released on the GD-Algorithms mailing list) * - almost used "as-is", I even left the comments (hence the frustum-related notes) * * \param center [in] box center * \param extents [in] box extents * \param out_clip_mask [out] bitmask for active planes * \param in_clip_mask [in] bitmask for active planes * \return TRUE if boxes overlap planes */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL PlanesCollider::PlanesAABBOverlap(const Point& center, const Point& extents, udword& out_clip_mask, udword in_clip_mask) { // Stats mNbVolumeBVTests++; const Plane* p = mPlanes; // Evaluate through all active frustum planes. We determine the relation // between the AABB and a plane by using the concept of "near" and "far" // vertices originally described by Zhang (and later by Mller). Our // variant here uses 3 fabs ops, 6 muls, 7 adds and two floating point // comparisons per plane. The routine early-exits if the AABB is found // to be outside any of the planes. The loop also constructs a new output // clip mask. Most FPUs have a native single-cycle fabsf() operation. udword Mask = 1; // current mask index (1,2,4,8,..) udword TmpOutClipMask = 0; // initialize output clip mask into empty. while(Mask<=in_clip_mask) // keep looping while we have active planes left... { if(in_clip_mask & Mask) // if clip plane is active, process it.. { float NP = extents.x*fabsf(p->n.x) + extents.y*fabsf(p->n.y) + extents.z*fabsf(p->n.z); // ### fabsf could be precomputed float MP = center.x*p->n.x + center.y*p->n.y + center.z*p->n.z + p->d; if(NP < MP) // near vertex behind the clip plane... return FALSE; // .. so there is no intersection.. if((-NP) < MP) // near and far vertices on different sides of plane.. TmpOutClipMask |= Mask; // .. so update the clip mask... } Mask+=Mask; // mk = (1<Add(udword(prim_index)); //! Planes-triangle test #define PLANES_PRIM(prim_index, flag) \ /* Request vertices from the app */ \ mIMesh->GetTriangle(mVP, prim_index, mVC); \ /* Perform triangle-box overlap test */ \ if(PlanesTriOverlap(clip_mask)) \ { \ SET_CONTACT(prim_index, flag) \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// PlanesCollider::PlanesCollider() : mNbPlanes (0), mPlanes (null) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// PlanesCollider::~PlanesCollider() { DELETEARRAY(mPlanes); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings and callbacks have been defined. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const char* PlanesCollider::ValidateSettings() { if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!"; return VolumeCollider::ValidateSettings(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] a planes cache * \param planes [in] list of planes in world space * \param nb_planes [in] number of planes * \param model [in] Opcode model to collide with * \param worldm [in] model's world matrix, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool PlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const Model& model, const Matrix4x4* worldm) { // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, planes, nb_planes, worldm)) return true; udword PlaneMask = (1<mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); else _Collide(Tree->GetNodes(), PlaneMask); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); else _Collide(Tree->GetNodes(), PlaneMask); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); else _Collide(Tree->GetNodes(), PlaneMask); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); else _Collide(Tree->GetNodes(), PlaneMask); } } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a collision query : * - reset stats & contact status * - compute planes in model space * - check temporal coherence * * \param cache [in/out] a planes cache * \param planes [in] list of planes * \param nb_planes [in] number of planes * \param worldm [in] model's world matrix, or null * \return TRUE if we can return immediately * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL PlanesCollider::InitQuery(PlanesCache& cache, const Plane* planes, udword nb_planes, const Matrix4x4* worldm) { // 1) Call the base method VolumeCollider::InitQuery(); // 2) Compute planes in model space if(nb_planes>mNbPlanes) { DELETEARRAY(mPlanes); mPlanes = new Plane[nb_planes]; } mNbPlanes = nb_planes; if(worldm) { Matrix4x4 InvWorldM; InvertPRMatrix(InvWorldM, *worldm); // for(udword i=0;iHasSingleNode()) { if(!SkipPrimitiveTests()) { // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. mTouchedPrimitives->Reset(); // Perform overlap test between the unique triangle and the planes (and set contact status if needed) udword clip_mask = (1< check results from previous frame before performing the collision query if(FirstContactEnabled()) { // We're only interested in the first contact found => test the unique previously touched face if(mTouchedPrimitives->GetNbEntries()) { // Get index of previously touched face = the first entry in the array udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); // Then reset the array: // - if the overlap test below is successful, the index we'll get added back anyway // - if it isn't, then the array should be reset anyway for the normal query mTouchedPrimitives->Reset(); // Perform overlap test between the cached triangle and the planes (and set contact status if needed) udword clip_mask = (1< we'll have to perform a normal query } else mTouchedPrimitives->Reset(); } else { // Here we don't use temporal coherence => do a normal query mTouchedPrimitives->Reset(); } return FALSE; } #define TEST_CLIP_MASK \ /* If the box is completely included, so are its children. We don't need to do extra tests, we */ \ /* can immediately output a list of visible children. Those ones won't need to be clipped. */ \ if(!OutClipMask) \ { \ /* Set contact status */ \ mFlags |= OPC_CONTACT; \ _Dump(node); \ return; \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_Collide(const AABBCollisionNode* node, udword clip_mask) { // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->IsLeaf()) { PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos(), OutClipMask); if(ContactFound()) return; _Collide(node->GetNeg(), OutClipMask); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node, udword clip_mask) { // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_Collide(const AABBQuantizedNode* node, udword clip_mask) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->IsLeaf()) { PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos(), OutClipMask); if(ContactFound()) return; _Collide(node->GetNeg(), OutClipMask); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node, udword clip_mask) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_Collide(const AABBNoLeafNode* node, udword clip_mask) { // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->HasPosLeaf()) { PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos(), OutClipMask); if(ContactFound()) return; if(node->HasNegLeaf()) { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg(), OutClipMask); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node, udword clip_mask) { // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_Collide(const AABBQuantizedNoLeafNode* node, udword clip_mask) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->HasPosLeaf()) { PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos(), OutClipMask); if(ContactFound()) return; if(node->HasNegLeaf()) { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg(), OutClipMask); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node, udword clip_mask) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. udword OutClipMask; if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; TEST_CLIP_MASK // Else the box straddles one or several planes, so we need to recurse down the tree. if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridPlanesCollider::HybridPlanesCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridPlanesCollider::~HybridPlanesCollider() { } bool HybridPlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const HybridModel& model, const Matrix4x4* worldm) { // We don't want primitive tests here! mFlags |= OPC_NO_PRIMITIVE_TESTS; // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, planes, nb_planes, worldm)) return true; // Special case for 1-leaf trees if(mCurrentModel && mCurrentModel->HasSingleNode()) { // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles udword Nb = mIMesh->GetNbTriangles(); // Loop through all triangles udword clip_mask = (1<mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); } } // We only have a list of boxes so far if(GetContactStatus()) { // Reset contact status, since it currently only reflects collisions with leaf boxes Collider::InitQuery(); // Change dest container so that we can use built-in overlap tests and get collided primitives cache.TouchedPrimitives.Reset(); mTouchedPrimitives = &cache.TouchedPrimitives; // Read touched leaf boxes udword Nb = mTouchedBoxes.GetNbEntries(); const udword* Touched = mTouchedBoxes.GetEntries(); const LeafTriangles* LT = model.GetLeafTriangles(); const udword* Indices = model.GetIndices(); // Loop through touched leaves udword clip_mask = (1<Distance(*mVP.Vertex[0]); float d1 = p->Distance(*mVP.Vertex[1]); float d2 = p->Distance(*mVP.Vertex[2]); if(d0>0.0f && d1>0.0f && d2>0.0f) return FALSE; // if(!(IR(d0)&SIGN_BITMASK) && !(IR(d1)&SIGN_BITMASK) && !(IR(d2)&SIGN_BITMASK)) return FALSE; } Mask+=Mask; p++; } /* for(udword i=0;i<6;i++) { float d0 = p[i].Distance(mLeafVerts[0]); float d1 = p[i].Distance(mLeafVerts[1]); float d2 = p[i].Distance(mLeafVerts[2]); if(d0>0.0f && d1>0.0f && d2>0.0f) return false; } */ return TRUE; } ode-0.14/OPCODE/OPC_RayAABBOverlap.h0000644000000000000000000000677612635011627015243 0ustar rootroot// Opcode 1.1: ray-AABB overlap tests based on Woo's code // Opcode 1.2: ray-AABB overlap tests based on the separating axis theorem // // The point of intersection is not computed anymore. The distance to impact is not needed anymore // since we now have two different queries for segments or rays. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes a segment-AABB overlap test using the separating axis theorem. Segment is cached within the class. * \param center [in] AABB center * \param extents [in] AABB extents * \return true on overlap */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL RayCollider::SegmentAABBOverlap(const Point& center, const Point& extents) { // Stats mNbRayBVTests++; float Dx = mData2.x - center.x; if(fabsf(Dx) > extents.x + mFDir.x) return FALSE; float Dy = mData2.y - center.y; if(fabsf(Dy) > extents.y + mFDir.y) return FALSE; float Dz = mData2.z - center.z; if(fabsf(Dz) > extents.z + mFDir.z) return FALSE; float f; f = mData.y * Dz - mData.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE; f = mData.z * Dx - mData.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE; f = mData.x * Dy - mData.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes a ray-AABB overlap test using the separating axis theorem. Ray is cached within the class. * \param center [in] AABB center * \param extents [in] AABB extents * \return true on overlap */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL RayCollider::RayAABBOverlap(const Point& center, const Point& extents) { // Stats mNbRayBVTests++; // float Dx = mOrigin.x - center.x; if(fabsf(Dx) > extents.x && Dx*mDir.x>=0.0f) return FALSE; // float Dy = mOrigin.y - center.y; if(fabsf(Dy) > extents.y && Dy*mDir.y>=0.0f) return FALSE; // float Dz = mOrigin.z - center.z; if(fabsf(Dz) > extents.z && Dz*mDir.z>=0.0f) return FALSE; float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && Dx*mDir.x>=0.0f) return FALSE; float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && Dy*mDir.y>=0.0f) return FALSE; float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && Dz*mDir.z>=0.0f) return FALSE; // float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && ((SIR(Dx)-1)^SIR(mDir.x))>=0.0f) return FALSE; // float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && ((SIR(Dy)-1)^SIR(mDir.y))>=0.0f) return FALSE; // float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && ((SIR(Dz)-1)^SIR(mDir.z))>=0.0f) return FALSE; float f; f = mDir.y * Dz - mDir.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE; f = mDir.z * Dx - mDir.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE; f = mDir.x * Dy - mDir.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE; return TRUE; } ode-0.14/OPCODE/OPC_RayCollider.cpp0000644000000000000000000007114712635011627015307 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a ray collider. * \file OPC_RayCollider.cpp * \author Pierre Terdiman * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a ray-vs-tree collider. * This class performs a stabbing query on an AABB tree, i.e. does a ray-mesh collision. * * HIGHER DISTANCE BOUND: * * If P0 and P1 are two 3D points, let's define: * - d = distance between P0 and P1 * - Origin = P0 * - Direction = (P1 - P0) / d = normalized direction vector * - A parameter t such as a point P on the line (P0,P1) is P = Origin + t * Direction * - t = 0 --> P = P0 * - t = d --> P = P1 * * Then we can define a general "ray" as: * * struct Ray * { * Point Origin; * Point Direction; * }; * * But it actually maps three different things: * - a segment, when 0 <= t <= d * - a half-line, when 0 <= t < +infinity, or -infinity < t <= d * - a line, when -infinity < t < +infinity * * In Opcode, we support segment queries, which yield half-line queries by setting d = +infinity. * We don't support line-queries. If you need them, shift the origin along the ray by an appropriate margin. * * In short, the lower bound is always 0, and you can setup the higher bound "d" with RayCollider::SetMaxDist(). * * Query |segment |half-line |line * --------|-------------------|---------------|---------------- * Usages |-shadow feelers |-raytracing |- * |-sweep tests |-in/out tests | * * FIRST CONTACT: * * - You can setup "first contact" mode or "all contacts" mode with RayCollider::SetFirstContact(). * - In "first contact" mode we return as soon as the ray hits one face. If can be useful e.g. for shadow feelers, where * you want to know whether the path to the light is free or not (a boolean answer is enough). * - In "all contacts" mode we return all faces hit by the ray. * * TEMPORAL COHERENCE: * * - You can enable or disable temporal coherence with RayCollider::SetTemporalCoherence(). * - It currently only works in "first contact" mode. * - If temporal coherence is enabled, the previously hit triangle is cached during the first query. Then, next queries * start by colliding the ray against the cached triangle. If they still collide, we return immediately. * * CLOSEST HIT: * * - You can enable or disable "closest hit" with RayCollider::SetClosestHit(). * - It currently only works in "all contacts" mode. * - If closest hit is enabled, faces are sorted by distance on-the-fly and the closest one only is reported. * * BACKFACE CULLING: * * - You can enable or disable backface culling with RayCollider::SetCulling(). * - If culling is enabled, ray will not hit back faces (only front faces). * * * * \class RayCollider * \author Pierre Terdiman * \version 1.3 * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * This class describes a face hit by a ray or segment. * This is a particular class dedicated to stabbing queries. * * \class CollisionFace * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * This class is a dedicated collection of CollisionFace. * * \class CollisionFaces * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; #include "OPC_RayAABBOverlap.h" #include "OPC_RayTriOverlap.h" #define SET_CONTACT(prim_index, flag) \ mNbIntersections++; \ /* Set contact status */ \ mFlags |= flag; \ /* In any case the contact has been found and recorded in mStabbedFace */ \ mStabbedFace.mFaceID = prim_index; #ifdef OPC_RAYHIT_CALLBACK #define HANDLE_CONTACT(prim_index, flag) \ SET_CONTACT(prim_index, flag) \ \ if(mHitCallback) (mHitCallback)(mStabbedFace, mUserData); #define UPDATE_CACHE \ if(cache && GetContactStatus()) \ { \ *cache = mStabbedFace.mFaceID; \ } #else #define HANDLE_CONTACT(prim_index, flag) \ SET_CONTACT(prim_index, flag) \ \ /* Now we can also record it in mStabbedFaces if available */ \ if(mStabbedFaces) \ { \ /* If we want all faces or if that's the first one we hit */ \ if(!mClosestHit || !mStabbedFaces->GetNbFaces()) \ { \ mStabbedFaces->AddFace(mStabbedFace); \ } \ else \ { \ /* We only keep closest hit */ \ CollisionFace* Current = const_cast(mStabbedFaces->GetFaces()); \ if(Current && mStabbedFace.mDistancemDistance) \ { \ *Current = mStabbedFace; \ } \ } \ } #define UPDATE_CACHE \ if(cache && GetContactStatus() && mStabbedFaces) \ { \ const CollisionFace* Current = mStabbedFaces->GetFaces(); \ if(Current) *cache = Current->mFaceID; \ else *cache = INVALID_ID; \ } #endif #define SEGMENT_PRIM(prim_index, flag) \ /* Request vertices from the app */ \ VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \ \ /* Perform ray-tri overlap test and return */ \ if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ { \ /* Intersection point is valid if dist < segment's length */ \ /* We know dist>0 so we can use integers */ \ if(IR(mStabbedFace.mDistance)GetTriangle(VP, prim_index, VC); \ \ /* Perform ray-tri overlap test and return */ \ if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ { \ HANDLE_CONTACT(prim_index, flag) \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RayCollider::RayCollider() : #ifdef OPC_RAYHIT_CALLBACK mHitCallback (null), mUserData (0), #else mStabbedFaces (null), mClosestHit (false), #endif mNbRayBVTests (0), mNbRayPrimTests (0), mNbIntersections (0), mMaxDist (MAX_FLOAT), mCulling (true) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RayCollider::~RayCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings and callbacks have been defined. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const char* RayCollider::ValidateSettings() { if(mMaxDist<0.0f) return "Higher distance bound must be positive!"; if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!"; #ifndef OPC_RAYHIT_CALLBACK if(mClosestHit && FirstContactEnabled()) return "Closest hit doesn't work with ""First contact"" mode!"; if(TemporalCoherenceEnabled() && mClosestHit) return "Temporal coherence can't guarantee to report closest hit!"; #endif if(SkipPrimitiveTests()) return "SkipPrimitiveTests not possible for RayCollider ! (not implemented)"; return null; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic stabbing query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - in the user-provided destination array * * \param world_ray [in] stabbing ray in world space * \param model [in] Opcode model to collide with * \param world [in] model's world matrix, or null * \param cache [in] a possibly cached face index, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool RayCollider::Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world, udword* cache) { // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(world_ray, world, cache)) return true; if(!model.HasLeafNodes()) { if(model.IsQuantized()) { const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform stabbing query if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); else _RayStab(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform stabbing query if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); else _RayStab(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform stabbing query if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); else _RayStab(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform stabbing query if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); else _RayStab(Tree->GetNodes()); } } // Update cache if needed UPDATE_CACHE return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a stabbing query : * - reset stats & contact status * - compute ray in local space * - check temporal coherence * * \param world_ray [in] stabbing ray in world space * \param world [in] object's world matrix, or null * \param face_id [in] index of previously stabbed triangle * \return TRUE if we can return immediately * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword* face_id) { // Reset stats & contact status Collider::InitQuery(); mNbRayBVTests = 0; mNbRayPrimTests = 0; mNbIntersections = 0; #ifndef OPC_RAYHIT_CALLBACK if(mStabbedFaces) mStabbedFaces->Reset(); #endif // Compute ray in local space // The (Origin/Dir) form is needed for the ray-triangle test anyway (even for segment tests) if(world) { Matrix3x3 InvWorld = *world; mDir = InvWorld * world_ray.mDir; Matrix4x4 World; InvertPRMatrix(World, *world); mOrigin = world_ray.mOrig * World; } else { mDir = world_ray.mDir; mOrigin = world_ray.mOrig; } // 4) Special case: 1-triangle meshes [Opcode 1.3] if(mCurrentModel && mCurrentModel->HasSingleNode()) { // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. if(!SkipPrimitiveTests()) { // Perform overlap test between the unique triangle and the ray (and set contact status if needed) SEGMENT_PRIM(udword(0), OPC_CONTACT) // Return immediately regardless of status return TRUE; } } // Check temporal coherence : // Test previously colliding primitives first if(TemporalCoherenceEnabled() && FirstContactEnabled() && face_id && *face_id!=INVALID_ID) { #ifdef OLD_CODE #ifndef OPC_RAYHIT_CALLBACK if(!mClosestHit) #endif { // Request vertices from the app VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, *face_id, VC); // Perform ray-cached tri overlap test if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) { // Intersection point is valid if: // - distance is positive (else it can just be a face behind the orig point) // - distance is smaller than a given max distance (useful for shadow feelers) // if(mStabbedFace.mDistance>0.0f && mStabbedFace.mDistanceAddFace(mStabbedFace); #endif return TRUE; } } } #else // New code // We handle both Segment/ray queries with the same segment code, and a possible infinite limit SEGMENT_PRIM(*face_id, OPC_TEMPORAL_CONTACT) // Return immediately if possible if(GetContactStatus()) return TRUE; #endif } // Precompute data (moved after temporal coherence since only needed for ray-AABB) if(IR(mMaxDist)!=IEEE_MAX_FLOAT) { // For Segment-AABB overlap mData = 0.5f * mDir * mMaxDist; mData2 = mOrigin + mData; // Precompute mFDir; mFDir.x = fabsf(mData.x); mFDir.y = fabsf(mData.y); mFDir.z = fabsf(mData.z); } else { // For Ray-AABB overlap // udword x = SIR(mDir.x)-1; // udword y = SIR(mDir.y)-1; // udword z = SIR(mDir.z)-1; // mData.x = FR(x); // mData.y = FR(y); // mData.z = FR(z); // Precompute mFDir; mFDir.x = fabsf(mDir.x); mFDir.y = fabsf(mDir.y); mFDir.z = fabsf(mDir.z); } return FALSE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stabbing query for vanilla AABB trees. * \param world_ray [in] stabbing ray in world space * \param tree [in] AABB tree * \param box_indices [out] indices of stabbed boxes * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool RayCollider::Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices) { // ### bad design here // This is typically called for a scene tree, full of -AABBs-, not full of triangles. // So we don't really have "primitives" to deal with. Hence it doesn't work with // "FirstContact" + "TemporalCoherence". ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); // Checkings if(!tree) return false; // Init collision query // Basically this is only called to initialize precomputed data if(InitQuery(world_ray)) return true; // Perform stabbing query if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(tree, box_indices); else _RayStab(tree, box_indices); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_SegmentStab(const AABBCollisionNode* node) { // Perform Segment-AABB overlap test if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; if(node->IsLeaf()) { SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _SegmentStab(node->GetPos()); if(ContactFound()) return; _SegmentStab(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_SegmentStab(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Segment-AABB overlap test if(!SegmentAABBOverlap(Center, Extents)) return; if(node->IsLeaf()) { SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _SegmentStab(node->GetPos()); if(ContactFound()) return; _SegmentStab(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_SegmentStab(const AABBNoLeafNode* node) { // Perform Segment-AABB overlap test if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; if(node->HasPosLeaf()) { SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _SegmentStab(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _SegmentStab(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_SegmentStab(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Segment-AABB overlap test if(!SegmentAABBOverlap(Center, Extents)) return; if(node->HasPosLeaf()) { SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _SegmentStab(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _SegmentStab(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for vanilla AABB trees. * \param node [in] current collision node * \param box_indices [out] indices of stabbed boxes */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_SegmentStab(const AABBTreeNode* node, Container& box_indices) { // Test the box against the segment Point Center, Extents; node->GetAABB()->GetCenter(Center); node->GetAABB()->GetExtents(Extents); if(!SegmentAABBOverlap(Center, Extents)) return; if(node->IsLeaf()) { box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives()); } else { _SegmentStab(node->GetPos(), box_indices); _SegmentStab(node->GetNeg(), box_indices); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_RayStab(const AABBCollisionNode* node) { // Perform Ray-AABB overlap test if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; if(node->IsLeaf()) { RAY_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _RayStab(node->GetPos()); if(ContactFound()) return; _RayStab(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_RayStab(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Ray-AABB overlap test if(!RayAABBOverlap(Center, Extents)) return; if(node->IsLeaf()) { RAY_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _RayStab(node->GetPos()); if(ContactFound()) return; _RayStab(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_RayStab(const AABBNoLeafNode* node) { // Perform Ray-AABB overlap test if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; if(node->HasPosLeaf()) { RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _RayStab(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _RayStab(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_RayStab(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Ray-AABB overlap test if(!RayAABBOverlap(Center, Extents)) return; if(node->HasPosLeaf()) { RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _RayStab(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _RayStab(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive stabbing query for vanilla AABB trees. * \param node [in] current collision node * \param box_indices [out] indices of stabbed boxes */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void RayCollider::_RayStab(const AABBTreeNode* node, Container& box_indices) { // Test the box against the ray Point Center, Extents; node->GetAABB()->GetCenter(Center); node->GetAABB()->GetExtents(Extents); if(!RayAABBOverlap(Center, Extents)) return; if(node->IsLeaf()) { mFlags |= OPC_CONTACT; box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives()); } else { _RayStab(node->GetPos(), box_indices); _RayStab(node->GetNeg(), box_indices); } } ode-0.14/OPCODE/OPC_RayCollider.h0000644000000000000000000003001112635011627014735 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a ray collider. * \file OPC_RayCollider.h * \author Pierre Terdiman * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_RAYCOLLIDER_H__ #define __OPC_RAYCOLLIDER_H__ class OPCODE_API CollisionFace { public: //! Constructor inline_ CollisionFace() {} //! Destructor inline_ ~CollisionFace() {} udword mFaceID; //!< Index of touched face float mDistance; //!< Distance from collider to hitpoint float mU, mV; //!< Impact barycentric coordinates }; class OPCODE_API CollisionFaces : public Container { public: //! Constructor CollisionFaces() {} //! Destructor ~CollisionFaces() {} inline_ udword GetNbFaces() const { return GetNbEntries()>>2; } inline_ const CollisionFace* GetFaces() const { return (const CollisionFace*)GetEntries(); } inline_ void Reset() { Container::Reset(); } inline_ void AddFace(const CollisionFace& face) { Add(face.mFaceID).Add(face.mDistance).Add(face.mU).Add(face.mV); } }; #ifdef OPC_RAYHIT_CALLBACK /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * User-callback, called by OPCODE to record a hit. * \param hit [in] current hit * \param user_data [in] user-defined data from SetCallback() */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// typedef void (*HitCallback) (const CollisionFace& hit, void* user_data); #endif class OPCODE_API RayCollider : public Collider { public: // Constructor / Destructor RayCollider(); virtual ~RayCollider(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic stabbing query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - in the user-provided destination array * * \param world_ray [in] stabbing ray in world space * \param model [in] Opcode model to collide with * \param world [in] model's world matrix, or null * \param cache [in] a possibly cached face index, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world=null, udword* cache=null); // bool Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices); // Settings #ifndef OPC_RAYHIT_CALLBACK /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Settings: enable or disable "closest hit" mode. * \param flag [in] true to report closest hit only * \see SetCulling(bool flag) * \see SetMaxDist(float max_dist) * \see SetDestination(StabbedFaces* sf) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetClosestHit(bool flag) { mClosestHit = flag; } #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Settings: enable or disable backface culling. * \param flag [in] true to enable backface culling * \see SetClosestHit(bool flag) * \see SetMaxDist(float max_dist) * \see SetDestination(StabbedFaces* sf) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetCulling(bool flag) { mCulling = flag; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Settings: sets the higher distance bound. * \param max_dist [in] higher distance bound. Default = maximal value, for ray queries (else segment) * \see SetClosestHit(bool flag) * \see SetCulling(bool flag) * \see SetDestination(StabbedFaces* sf) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetMaxDist(float max_dist=MAX_FLOAT) { mMaxDist = max_dist; } #ifdef OPC_RAYHIT_CALLBACK inline_ void SetHitCallback(HitCallback cb) { mHitCallback = cb; } inline_ void SetUserData(void* user_data) { mUserData = user_data; } #else /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Settings: sets the destination array for stabbed faces. * \param cf [in] destination array, filled during queries * \see SetClosestHit(bool flag) * \see SetCulling(bool flag) * \see SetMaxDist(float max_dist) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetDestination(CollisionFaces* cf) { mStabbedFaces = cf; } #endif // Stats /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of Ray-BV overlap tests after a collision query. * \see GetNbRayPrimTests() * \see GetNbIntersections() * \return the number of Ray-BV tests performed during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbRayBVTests() const { return mNbRayBVTests; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of Ray-Triangle overlap tests after a collision query. * \see GetNbRayBVTests() * \see GetNbIntersections() * \return the number of Ray-Triangle tests performed during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbRayPrimTests() const { return mNbRayPrimTests; } // In-out test /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of intersection found after a collision query. Can be used for in/out tests. * \see GetNbRayBVTests() * \see GetNbRayPrimTests() * \return the number of valid intersections during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbIntersections() const { return mNbIntersections; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(Collider) const char* ValidateSettings(); protected: // Ray in local space Point mOrigin; //!< Ray origin Point mDir; //!< Ray direction (normalized) Point mFDir; //!< fabsf(mDir) Point mData, mData2; // Stabbed faces CollisionFace mStabbedFace; //!< Current stabbed face #ifdef OPC_RAYHIT_CALLBACK HitCallback mHitCallback; //!< Callback used to record a hit void* mUserData; //!< User-defined data #else CollisionFaces* mStabbedFaces; //!< List of stabbed faces bool mClosestHit; //!< Report closest hit only #endif // Stats udword mNbRayBVTests; //!< Number of Ray-BV tests udword mNbRayPrimTests; //!< Number of Ray-Primitive tests // In-out test udword mNbIntersections; //!< Number of valid intersections // Dequantization coeffs Point mCenterCoeff; Point mExtentsCoeff; // Settings float mMaxDist; //!< Valid segment on the ray bool mCulling; //!< Stab culled faces or not // Internal methods void _SegmentStab(const AABBCollisionNode* node); void _SegmentStab(const AABBNoLeafNode* node); void _SegmentStab(const AABBQuantizedNode* node); void _SegmentStab(const AABBQuantizedNoLeafNode* node); void _SegmentStab(const AABBTreeNode* node, Container& box_indices); void _RayStab(const AABBCollisionNode* node); void _RayStab(const AABBNoLeafNode* node); void _RayStab(const AABBQuantizedNode* node); void _RayStab(const AABBQuantizedNoLeafNode* node); void _RayStab(const AABBTreeNode* node, Container& box_indices); // Overlap tests inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents); inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents); inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2); // Init methods BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world=null, udword* face_id=null); }; #endif // __OPC_RAYCOLLIDER_H__ ode-0.14/OPCODE/OPC_RayTriOverlap.h0000644000000000000000000000672312635011627015304 0ustar rootroot#define LOCAL_EPSILON 0.000001f /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes a ray-triangle intersection test. * Original code from Tomas Mller's "Fast Minimum Storage Ray-Triangle Intersection". * It's been optimized a bit with integer code, and modified to return a non-intersection if distance from * ray origin to triangle is negative. * * \param vert0 [in] triangle vertex * \param vert1 [in] triangle vertex * \param vert2 [in] triangle vertex * \return true on overlap. mStabbedFace is filled with relevant info. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL RayCollider::RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2) { // Stats mNbRayPrimTests++; // Find vectors for two edges sharing vert0 Point edge1 = vert1 - vert0; Point edge2 = vert2 - vert0; // Begin calculating determinant - also used to calculate U parameter Point pvec = mDir^edge2; // If determinant is near zero, ray lies in plane of triangle float det = edge1|pvec; if(mCulling) { if(det <= LOCAL_EPSILON * FCMin2(edge1.SquareMagnitude(), edge2.SquareMagnitude())) return FALSE; // From here, det is > 0. So we can use integer cmp. // Calculate distance from vert0 to ray origin Point tvec = mOrigin - vert0; // Calculate U parameter and test bounds mStabbedFace.mU = tvec|pvec; // if(IR(u)&0x80000000 || u>det) return FALSE; if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IR(det)) return FALSE; // Prepare to test V parameter Point qvec = tvec^edge1; // Calculate V parameter and test bounds mStabbedFace.mV = mDir|qvec; if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>det) return FALSE; // Calculate t, scale parameters, ray intersects triangle mStabbedFace.mDistance = edge2|qvec; // Det > 0 so we can early exit here // Intersection point is valid if distance is positive (else it can just be a face behind the orig point) if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE; // Else go on float OneOverDet = 1.0f / det; mStabbedFace.mDistance *= OneOverDet; mStabbedFace.mU *= OneOverDet; mStabbedFace.mV *= OneOverDet; } else { // the non-culling branch if(FastFabs(det) <= LOCAL_EPSILON * FCMin2(edge1.SquareMagnitude(), edge2.SquareMagnitude())) return FALSE; float OneOverDet = 1.0f / det; // Calculate distance from vert0 to ray origin Point tvec = mOrigin - vert0; // Calculate U parameter and test bounds mStabbedFace.mU = (tvec|pvec) * OneOverDet; // if(IR(u)&0x80000000 || u>1.0f) return FALSE; if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IEEE_1_0) return FALSE; // prepare to test V parameter Point qvec = tvec^edge1; // Calculate V parameter and test bounds mStabbedFace.mV = (mDir|qvec) * OneOverDet; if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>1.0f) return FALSE; // Calculate t, ray intersects triangle mStabbedFace.mDistance = (edge2|qvec) * OneOverDet; // Intersection point is valid if distance is positive (else it can just be a face behind the orig point) if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE; } return TRUE; } ode-0.14/OPCODE/OPC_Settings.h0000644000000000000000000000434012635011627014332 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains compilation flags. * \file OPC_Settings.h * \author Pierre Terdiman * \date May, 12, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_SETTINGS_H__ #define __OPC_SETTINGS_H__ //! Use CPU comparisons (comment that line to use standard FPU compares) //#define OPC_CPU_COMPARE //! Use FCOMI / FCMOV on Pentium-Pro based processors (comment that line to use plain C++) #define OPC_USE_FCOMI //! Use epsilon value in tri-tri overlap test #define OPC_TRITRI_EPSILON_TEST //! Use tree-coherence or not [not implemented yet] // #define OPC_USE_TREE_COHERENCE //! Use callbacks or direct pointers. Using callbacks might be a bit slower (but probably not much) // #define OPC_USE_CALLBACKS //! Support triangle and vertex strides or not. Using strides might be a bit slower (but probably not much) #define OPC_USE_STRIDE //! Discard negative pointer in vanilla trees #define OPC_NO_NEG_VANILLA_TREE //! Use a callback in the ray collider //#define OPC_RAYHIT_CALLBACK // NB: no compilation flag to enable/disable stats since they're actually needed in the box/box overlap test #endif //__OPC_SETTINGS_H__ ode-0.14/OPCODE/OPC_SphereAABBOverlap.h0000644000000000000000000000436412635011627015725 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Sphere-AABB overlap test, based on Jim Arvo's code. * \param center [in] box center * \param extents [in] box extents * \return TRUE on overlap */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL SphereCollider::SphereAABBOverlap(const Point& center, const Point& extents) { // Stats mNbVolumeBVTests++; float d = 0.0f; //find the square of the distance //from the sphere to the box #ifdef OLDIES for(udword i=0;i<3;i++) { float tmp = mCenter[i] - center[i]; float s = tmp + extents[i]; if(s<0.0f) d += s*s; else { s = tmp - extents[i]; if(s>0.0f) d += s*s; } } #endif //#ifdef NEW_TEST // float tmp = mCenter.x - center.x; // float s = tmp + extents.x; float tmp,s; tmp = mCenter.x - center.x; s = tmp + extents.x; if(s<0.0f) { d += s*s; if(d>mRadius2) return FALSE; } else { s = tmp - extents.x; if(s>0.0f) { d += s*s; if(d>mRadius2) return FALSE; } } tmp = mCenter.y - center.y; s = tmp + extents.y; if(s<0.0f) { d += s*s; if(d>mRadius2) return FALSE; } else { s = tmp - extents.y; if(s>0.0f) { d += s*s; if(d>mRadius2) return FALSE; } } tmp = mCenter.z - center.z; s = tmp + extents.z; if(s<0.0f) { d += s*s; if(d>mRadius2) return FALSE; } else { s = tmp - extents.z; if(s>0.0f) { d += s*s; if(d>mRadius2) return FALSE; } } //#endif #ifdef OLDIES // Point Min = center - extents; // Point Max = center + extents; float d = 0.0f; //find the square of the distance //from the sphere to the box for(udword i=0;i<3;i++) { float Min = center[i] - extents[i]; // if(mCenter[i]Max[i]) if(mCenter[i]>Max) { float s = mCenter[i] - Max; d += s*s; } } } #endif return d <= mRadius2; } ode-0.14/OPCODE/OPC_SphereCollider.cpp0000644000000000000000000006767512635011627016015 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a sphere collider. * \file OPC_SphereCollider.cpp * \author Pierre Terdiman * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains a sphere-vs-tree collider. * This class performs a collision test between a sphere and an AABB tree. You can use this to do a standard player vs world collision, * in a Nettle/Telemachos way. It doesn't suffer from all reported bugs in those two classic codes - the "new" one by Paul Nettle is a * debuggued version I think. Collision response can be driven by reported collision data - it works extremely well for me. In sake of * efficiency, all meshes (that is, all AABB trees) should of course also be kept in an extra hierarchical structure (octree, whatever). * * \class SphereCollider * \author Pierre Terdiman * \version 1.3 * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; #include "OPC_SphereAABBOverlap.h" #include "OPC_SphereTriOverlap.h" #define SET_CONTACT(prim_index, flag) \ /* Set contact status */ \ mFlags |= flag; \ mTouchedPrimitives->Add(udword(prim_index)); //! Sphere-triangle overlap test #define SPHERE_PRIM(prim_index, flag) \ /* Request vertices from the app */ \ VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \ \ /* Perform sphere-tri overlap test */ \ if(SphereTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ { \ SET_CONTACT(prim_index, flag) \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SphereCollider::SphereCollider() { mCenter.Zero(); mRadius2 = 0.0f; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SphereCollider::~SphereCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] a sphere cache * \param sphere [in] collision sphere in local space * \param model [in] Opcode model to collide with * \param worlds [in] sphere's world matrix, or null * \param worldm [in] model's world matrix, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SphereCollider::Collide(SphereCache& cache, const Sphere& sphere, const Model& model, const Matrix4x4* worlds, const Matrix4x4* worldm) { // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, sphere, worlds, worldm)) return true; // Special case for 1-leaf trees if(mCurrentModel && mCurrentModel->HasSingleNode()) { // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles udword Nb = mIMesh->GetNbTriangles(); // Loop through all triangles for(udword i=0;imCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); else _Collide(Tree->GetNodes()); } } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a collision query : * - reset stats & contact status * - setup matrices * - check temporal coherence * * \param cache [in/out] a sphere cache * \param sphere [in] sphere in local space * \param worlds [in] sphere's world matrix, or null * \param worldm [in] model's world matrix, or null * \return TRUE if we can return immediately * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL SphereCollider::InitQuery(SphereCache& cache, const Sphere& sphere, const Matrix4x4* worlds, const Matrix4x4* worldm) { // 1) Call the base method VolumeCollider::InitQuery(); // 2) Compute sphere in model space: // - Precompute R^2 mRadius2 = sphere.mRadius * sphere.mRadius; // - Compute center position mCenter = sphere.mCenter; // -> to world space if(worlds) mCenter *= *worlds; // -> to model space if(worldm) { // Invert model matrix Matrix4x4 InvWorldM; InvertPRMatrix(InvWorldM, *worldm); mCenter *= InvWorldM; } // 3) Setup destination pointer mTouchedPrimitives = &cache.TouchedPrimitives; // 4) Special case: 1-triangle meshes [Opcode 1.3] if(mCurrentModel && mCurrentModel->HasSingleNode()) { if(!SkipPrimitiveTests()) { // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. mTouchedPrimitives->Reset(); // Perform overlap test between the unique triangle and the sphere (and set contact status if needed) SPHERE_PRIM(udword(0), OPC_CONTACT) // Return immediately regardless of status return TRUE; } } // 5) Check temporal coherence : if(TemporalCoherenceEnabled()) { // Here we use temporal coherence // => check results from previous frame before performing the collision query if(FirstContactEnabled()) { // We're only interested in the first contact found => test the unique previously touched face if(mTouchedPrimitives->GetNbEntries()) { // Get index of previously touched face = the first entry in the array udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); // Then reset the array: // - if the overlap test below is successful, the index we'll get added back anyway // - if it isn't, then the array should be reset anyway for the normal query mTouchedPrimitives->Reset(); // Perform overlap test between the cached triangle and the sphere (and set contact status if needed) SPHERE_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) // Return immediately if possible if(GetContactStatus()) return TRUE; } // else no face has been touched during previous query // => we'll have to perform a normal query } else { // We're interested in all contacts =>test the new real sphere N(ew) against the previous fat sphere P(revious): float r = sqrtf(cache.FatRadius2) - sphere.mRadius; if(IsCacheValid(cache) && cache.Center.SquareDistance(mCenter) < r*r) { // - if N is included in P, return previous list // => we simply leave the list (mTouchedFaces) unchanged // Set contact status if needed if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; // In any case we don't need to do a query return TRUE; } else { // - else do the query using a fat N // Reset cache since we'll about to perform a real query mTouchedPrimitives->Reset(); // Make a fat sphere so that coherence will work for subsequent frames mRadius2 *= cache.FatCoeff; // mRadius2 = (sphere.mRadius * cache.FatCoeff)*(sphere.mRadius * cache.FatCoeff); // Update cache with query data (signature for cached faces) cache.Center = mCenter; cache.FatRadius2 = mRadius2; } } } else { // Here we don't use temporal coherence => do a normal query mTouchedPrimitives->Reset(); } return FALSE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Collision query for vanilla AABB trees. * \param cache [in/out] a sphere cache * \param sphere [in] collision sphere in world space * \param tree [in] AABB tree * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool SphereCollider::Collide(SphereCache& cache, const Sphere& sphere, const AABBTree* tree) { // This is typically called for a scene tree, full of -AABBs-, not full of triangles. // So we don't really have "primitives" to deal with. Hence it doesn't work with // "FirstContact" + "TemporalCoherence". ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); // Checkings if(!tree) return false; // Init collision query if(InitQuery(cache, sphere)) return true; // Perform collision query _Collide(tree); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Checks the sphere completely contains the box. In which case we can end the query sooner. * \param bc [in] box center * \param be [in] box extents * \return true if the sphere contains the whole box */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL SphereCollider::SphereContainsBox(const Point& bc, const Point& be) { // I assume if all 8 box vertices are inside the sphere, so does the whole box. // Sounds ok but maybe there's a better way? Point p; p.x=bc.x+be.x; p.y=bc.y+be.y; p.z=bc.z+be.z; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; p.x=bc.x+be.x; p.y=bc.y-be.y; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; p.x=bc.x+be.x; p.y=bc.y+be.y; p.z=bc.z-be.z; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; p.x=bc.x+be.x; p.y=bc.y-be.y; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; return TRUE; } #define TEST_BOX_IN_SPHERE(center, extents) \ if(SphereContainsBox(center, extents)) \ { \ /* Set contact status */ \ mFlags |= OPC_CONTACT; \ _Dump(node); \ return; \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_Collide(const AABBCollisionNode* node) { // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { SPHERE_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) { // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_Collide(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(Center, Extents)) return; TEST_BOX_IN_SPHERE(Center, Extents) if(node->IsLeaf()) { SPHERE_PRIM(node->GetPrimitive(), OPC_CONTACT) } else { _Collide(node->GetPos()); if(ContactFound()) return; _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(Center, Extents)) return; TEST_BOX_IN_SPHERE(Center, Extents) if(node->IsLeaf()) { SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) } else { _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; _CollideNoPrimitiveTest(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_Collide(const AABBNoLeafNode* node) { // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { SPHERE_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SPHERE_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) { // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_Collide(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(Center, Extents)) return; TEST_BOX_IN_SPHERE(Center, Extents) if(node->HasPosLeaf()) { SPHERE_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } else _Collide(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SPHERE_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } else _Collide(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) { // Dequantize box const QuantizedAABB& Box = node->mAABB; const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); // Perform Sphere-AABB overlap test if(!SphereAABBOverlap(Center, Extents)) return; TEST_BOX_IN_SPHERE(Center, Extents) if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetPos()); if(ContactFound()) return; if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } else _CollideNoPrimitiveTest(node->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for vanilla AABB trees. * \param node [in] current collision node */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void SphereCollider::_Collide(const AABBTreeNode* node) { // Perform Sphere-AABB overlap test Point Center, Extents; node->GetAABB()->GetCenter(Center); node->GetAABB()->GetExtents(Extents); if(!SphereAABBOverlap(Center, Extents)) return; if(node->IsLeaf() || SphereContainsBox(Center, Extents)) { mFlags |= OPC_CONTACT; mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives()); } else { _Collide(node->GetPos()); _Collide(node->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Constructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridSphereCollider::HybridSphereCollider() { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Destructor. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HybridSphereCollider::~HybridSphereCollider() { } bool HybridSphereCollider::Collide(SphereCache& cache, const Sphere& sphere, const HybridModel& model, const Matrix4x4* worlds, const Matrix4x4* worldm) { // We don't want primitive tests here! mFlags |= OPC_NO_PRIMITIVE_TESTS; // Checkings if(!Setup(&model)) return false; // Init collision query if(InitQuery(cache, sphere, worlds, worldm)) return true; // Special case for 1-leaf trees if(mCurrentModel && mCurrentModel->HasSingleNode()) { // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles udword Nb = mIMesh->GetNbTriangles(); // Loop through all triangles for(udword i=0;imCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } else { if(model.IsQuantized()) { const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); // Setup dequantization coeffs mCenterCoeff = Tree->mCenterCoeff; mExtentsCoeff = Tree->mExtentsCoeff; // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } else { const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); // Perform collision query - we don't want primitive tests here! _CollideNoPrimitiveTest(Tree->GetNodes()); } } // We only have a list of boxes so far if(GetContactStatus()) { // Reset contact status, since it currently only reflects collisions with leaf boxes Collider::InitQuery(); // Change dest container so that we can use built-in overlap tests and get collided primitives cache.TouchedPrimitives.Reset(); mTouchedPrimitives = &cache.TouchedPrimitives; // Read touched leaf boxes udword Nb = mTouchedBoxes.GetNbEntries(); const udword* Touched = mTouchedBoxes.GetEntries(); const LeafTriangles* LT = model.GetLeafTriangles(); const udword* Indices = model.GetIndices(); // Loop through touched leaves while(Nb--) { const LeafTriangles& CurrentLeaf = LT[*Touched++]; // Each leaf box has a set of triangles udword NbTris = CurrentLeaf.GetNbTriangles(); if(Indices) { const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = *T++; SPHERE_PRIM(TriangleIndex, OPC_CONTACT) } } else { udword BaseIndex = CurrentLeaf.GetTriangleIndex(); // Loop through triangles and test each of them while(NbTris--) { udword TriangleIndex = BaseIndex++; SPHERE_PRIM(TriangleIndex, OPC_CONTACT) } } } } return true; } ode-0.14/OPCODE/OPC_SphereCollider.h0000644000000000000000000001130112635011627015431 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a sphere collider. * \file OPC_SphereCollider.h * \author Pierre Terdiman * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_SPHERECOLLIDER_H__ #define __OPC_SPHERECOLLIDER_H__ struct OPCODE_API SphereCache : VolumeCache { SphereCache() : Center(0.0f,0.0f,0.0f), FatRadius2(0.0f), FatCoeff(1.1f) {} ~SphereCache() {} // Cached faces signature Point Center; //!< Sphere used when performing the query resulting in cached faces float FatRadius2; //!< Sphere used when performing the query resulting in cached faces // User settings float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere }; class OPCODE_API SphereCollider : public VolumeCollider { public: // Constructor / Destructor SphereCollider(); virtual ~SphereCollider(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results: * - with GetContactStatus() * - with GetNbTouchedPrimitives() * - with GetTouchedPrimitives() * * \param cache [in/out] a sphere cache * \param sphere [in] collision sphere in local space * \param model [in] Opcode model to collide with * \param worlds [in] sphere's world matrix, or null * \param worldm [in] model's world matrix, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Collide(SphereCache& cache, const Sphere& sphere, const Model& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); // bool Collide(SphereCache& cache, const Sphere& sphere, const AABBTree* tree); protected: // Sphere in model space Point mCenter; //!< Sphere center float mRadius2; //!< Sphere radius squared // Internal methods void _Collide(const AABBCollisionNode* node); void _Collide(const AABBNoLeafNode* node); void _Collide(const AABBQuantizedNode* node); void _Collide(const AABBQuantizedNoLeafNode* node); void _Collide(const AABBTreeNode* node); void _CollideNoPrimitiveTest(const AABBCollisionNode* node); void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); // Overlap tests inline_ BOOL SphereContainsBox(const Point& bc, const Point& be); inline_ BOOL SphereAABBOverlap(const Point& center, const Point& extents); BOOL SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2); // Init methods BOOL InitQuery(SphereCache& cache, const Sphere& sphere, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); }; class OPCODE_API HybridSphereCollider : public SphereCollider { public: // Constructor / Destructor HybridSphereCollider(); virtual ~HybridSphereCollider(); bool Collide(SphereCache& cache, const Sphere& sphere, const HybridModel& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); protected: Container mTouchedBoxes; }; #endif // __OPC_SPHERECOLLIDER_H__ ode-0.14/OPCODE/OPC_SphereTriOverlap.h0000644000000000000000000001053512635011627015773 0ustar rootroot // This is collision detection. If you do another distance test for collision *response*, // if might be useful to simply *skip* the test below completely, and report a collision. // - if sphere-triangle overlap, result is ok // - if they don't, we'll discard them during collision response with a similar test anyway // Overall this approach should run faster. // Original code by David Eberly in Magic. BOOL SphereCollider::SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2) { // Stats mNbVolumePrimTests++; // Early exit if one of the vertices is inside the sphere Point kDiff = vert2 - mCenter; float fC = kDiff.SquareMagnitude(); if(fC <= mRadius2) return TRUE; kDiff = vert1 - mCenter; fC = kDiff.SquareMagnitude(); if(fC <= mRadius2) return TRUE; kDiff = vert0 - mCenter; fC = kDiff.SquareMagnitude(); if(fC <= mRadius2) return TRUE; // Else do the full distance test Point TriEdge0 = vert1 - vert0; Point TriEdge1 = vert2 - vert0; //Point kDiff = vert0 - mCenter; float fA00 = TriEdge0.SquareMagnitude(); float fA01 = TriEdge0 | TriEdge1; float fA11 = TriEdge1.SquareMagnitude(); float fB0 = kDiff | TriEdge0; float fB1 = kDiff | TriEdge1; //float fC = kDiff.SquareMagnitude(); float fDet = fabsf(fA00*fA11 - fA01*fA01); float u = fA01*fB1-fA11*fB0; float v = fA01*fB0-fA00*fB1; float SqrDist; if(u + v <= fDet) { if(u < 0.0f) { if(v < 0.0f) // region 4 { if(fB0 < 0.0f) { // v = 0.0f; if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; } else { u = -fB0/fA00; SqrDist = fB0*u+fC; } } else { // u = 0.0f; if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; } else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; } else { v = -fB1/fA11; SqrDist = fB1*v+fC; } } } else // region 3 { // u = 0.0f; if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; } else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; } else { v = -fB1/fA11; SqrDist = fB1*v+fC; } } } else if(v < 0.0f) // region 5 { // v = 0.0f; if(fB0>=0.0f) { /*u = 0.0f;*/ SqrDist = fC; } else if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; } else { u = -fB0/fA00; SqrDist = fB0*u+fC; } } else // region 0 { // minimum at interior point if(fDet==0.0f) { // u = 0.0f; // v = 0.0f; SqrDist = MAX_FLOAT; } else { float fInvDet = 1.0f/fDet; u *= fInvDet; v *= fInvDet; SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; } } } else { float fTmp0, fTmp1, fNumer, fDenom; if(u < 0.0f) // region 2 { fTmp0 = fA01 + fB0; fTmp1 = fA11 + fB1; if(fTmp1 > fTmp0) { fNumer = fTmp1 - fTmp0; fDenom = fA00-2.0f*fA01+fA11; if(fNumer >= fDenom) { // u = 1.0f; // v = 0.0f; SqrDist = fA00+2.0f*fB0+fC; } else { u = fNumer/fDenom; v = 1.0f - u; SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; } } else { // u = 0.0f; if(fTmp1 <= 0.0f) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; } else if(fB1 >= 0.0f) { /*v = 0.0f;*/ SqrDist = fC; } else { v = -fB1/fA11; SqrDist = fB1*v+fC; } } } else if(v < 0.0f) // region 6 { fTmp0 = fA01 + fB1; fTmp1 = fA00 + fB0; if(fTmp1 > fTmp0) { fNumer = fTmp1 - fTmp0; fDenom = fA00-2.0f*fA01+fA11; if(fNumer >= fDenom) { // v = 1.0f; // u = 0.0f; SqrDist = fA11+2.0f*fB1+fC; } else { v = fNumer/fDenom; u = 1.0f - v; SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; } } else { // v = 0.0f; if(fTmp1 <= 0.0f) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; } else if(fB0 >= 0.0f) { /*u = 0.0f;*/ SqrDist = fC; } else { u = -fB0/fA00; SqrDist = fB0*u+fC; } } } else // region 1 { fNumer = fA11 + fB1 - fA01 - fB0; if(fNumer <= 0.0f) { // u = 0.0f; // v = 1.0f; SqrDist = fA11+2.0f*fB1+fC; } else { fDenom = fA00-2.0f*fA01+fA11; if(fNumer >= fDenom) { // u = 1.0f; // v = 0.0f; SqrDist = fA00+2.0f*fB0+fC; } else { u = fNumer/fDenom; v = 1.0f - u; SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; } } } } return fabsf(SqrDist) < mRadius2; } ode-0.14/OPCODE/OPC_TreeBuilders.cpp0000644000000000000000000003405712635011627015466 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for tree builders. * \file OPC_TreeBuilders.cpp * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A builder for AABB-trees of vertices. * * \class AABBTreeOfVerticesBuilder * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A builder for AABB-trees of AABBs. * * \class AABBTreeOfAABBsBuilder * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * A builder for AABB-trees of triangles. * * \class AABBTreeOfTrianglesBuilder * \author Pierre Terdiman * \version 1.3 * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the AABB of a set of primitives. * \param primitives [in] list of indices of primitives * \param nb_prims [in] number of indices * \param global_box [out] global AABB enclosing the set of input primitives * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeOfAABBsBuilder::ComputeGlobalBox(const dTriIndex* primitives, udword nb_prims, AABB& global_box) const { // Checkings if(!primitives || !nb_prims) return false; // Initialize global box global_box = mAABBArray[primitives[0]]; // Loop through boxes for(udword i=1;iGetTriangle(VP, *primitives++, VC); // Update global box Min.Min(*VP.Vertex[0]).Min(*VP.Vertex[1]).Min(*VP.Vertex[2]); Max.Max(*VP.Vertex[0]).Max(*VP.Vertex[1]).Max(*VP.Vertex[2]); } global_box.SetMinMax(Min, Max); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the splitting value along a given axis for a given primitive. * \param index [in] index of the primitive to split * \return splitting value */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Point AABBTreeOfTrianglesBuilder::GetSplittingValues(udword index) const { VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, index, VC); return ( *VP.Vertex[0] + *VP.Vertex[1] + *VP.Vertex[2] ) * INV3; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the splitting value along a given axis for a given primitive. * \param index [in] index of the primitive to split * \param axis [in] axis index (0,1,2) * \return splitting value */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AABBTreeOfTrianglesBuilder::GetSplittingValue(udword index, udword axis) const { /* // Compute center of triangle Point Center; mTriList[index].Center(mVerts, Center); // Return value return Center[axis];*/ // Compute correct component from center of triangle // return (mVerts[mTriList[index].mVRef[0]][axis] // +mVerts[mTriList[index].mVRef[1]][axis] // +mVerts[mTriList[index].mVRef[2]][axis])*INV3; VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, index, VC); // Compute correct component from center of triangle return ((*VP.Vertex[0])[axis] +(*VP.Vertex[1])[axis] +(*VP.Vertex[2])[axis])*INV3; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the splitting value along a given axis for a given node. * \param primitives [in] list of indices of primitives * \param nb_prims [in] number of indices * \param global_box [in] global AABB enclosing the set of input primitives * \param axis [in] axis index (0,1,2) * \return splitting value */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float AABBTreeOfTrianglesBuilder::GetSplittingValue(const dTriIndex* primitives, udword nb_prims, const AABB& global_box, udword axis) const { if(mSettings.mRules&SPLIT_GEOM_CENTER) { // Loop through triangles float SplitValue = 0.0f; VertexPointers VP; ConversionArea VC; for(udword i=0;iGetTriangle(VP, primitives[i], VC); // Update split value SplitValue += (*VP.Vertex[0])[axis]; SplitValue += (*VP.Vertex[1])[axis]; SplitValue += (*VP.Vertex[2])[axis]; } return SplitValue / float(nb_prims*3); } else return AABBTreeBuilder::GetSplittingValue(primitives, nb_prims, global_box, axis); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Computes the AABB of a set of primitives. * \param primitives [in] list of indices of primitives * \param nb_prims [in] number of indices * \param global_box [out] global AABB enclosing the set of input primitives * \return true if success */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeOfVerticesBuilder::ComputeGlobalBox(const dTriIndex* primitives, udword nb_prims, AABB& global_box) const { // Checkings if(!primitives || !nb_prims) return false; // Initialize global box global_box.SetEmpty(); // Loop through vertices for(udword i=0;iHasLeafNodes()!=cache.Model1->HasLeafNodes()) return false; if(cache.Model0->IsQuantized()!=cache.Model1->IsQuantized()) return false; /* Rules: - perform hull test - when hulls collide, disable hull test - if meshes overlap, reset countdown - if countdown reaches 0, enable hull test */ #ifdef __MESHMERIZER_H__ // Handle hulls if(cache.HullTest) { if(cache.Model0->GetHull() && cache.Model1->GetHull()) { struct Local { static Point* SVCallback(const Point& sv, udword& previndex, udword user_data) { CollisionHull* Hull = (CollisionHull*)user_data; previndex = Hull->ComputeSupportingVertex(sv, previndex); return (Point*)&Hull->GetVerts()[previndex]; } }; bool Collide; if(0) { static GJKEngine GJK; -- not thread safe, store in ThreadLocalData static bool GJKInitDone=false; -- not thread safe, to be removed if(!GJKInitDone) { GJK.Enable(GJK_BACKUP_PROCEDURE); GJK.Enable(GJK_DEGENERATE); GJK.Enable(GJK_HILLCLIMBING); GJKInitDone = true; } GJK.SetCallbackObj0(Local::SVCallback); GJK.SetCallbackObj1(Local::SVCallback); GJK.SetUserData0(udword(cache.Model0->GetHull())); GJK.SetUserData1(udword(cache.Model1->GetHull())); Collide = GJK.Collide(*world0, *world1, &cache.SepVector); } else { static SVEngine SVE; -- not thread safe, store in ThreadLocalData SVE.SetCallbackObj0(Local::SVCallback); SVE.SetCallbackObj1(Local::SVCallback); SVE.SetUserData0(udword(cache.Model0->GetHull())); SVE.SetUserData1(udword(cache.Model1->GetHull())); Collide = SVE.Collide(*world0, *world1, &cache.SepVector); } if(!Collide) { // Reset stats & contact status mFlags &= ~OPC_CONTACT; mNbBVBVTests = 0; mNbPrimPrimTests = 0; mNbBVPrimTests = 0; mPairs.Reset(); return true; } } } // Here, hulls collide cache.HullTest = false; #endif // __MESHMERIZER_H__ // Checkings if(!Setup(cache.Model0->GetMeshInterface(), cache.Model1->GetMeshInterface())) return false; // Simple double-dispatch bool Status; if(!cache.Model0->HasLeafNodes()) { if(cache.Model0->IsQuantized()) { const AABBQuantizedNoLeafTree* T0 = (const AABBQuantizedNoLeafTree*)cache.Model0->GetTree(); const AABBQuantizedNoLeafTree* T1 = (const AABBQuantizedNoLeafTree*)cache.Model1->GetTree(); Status = Collide(T0, T1, world0, world1, &cache); } else { const AABBNoLeafTree* T0 = (const AABBNoLeafTree*)cache.Model0->GetTree(); const AABBNoLeafTree* T1 = (const AABBNoLeafTree*)cache.Model1->GetTree(); Status = Collide(T0, T1, world0, world1, &cache); } } else { if(cache.Model0->IsQuantized()) { const AABBQuantizedTree* T0 = (const AABBQuantizedTree*)cache.Model0->GetTree(); const AABBQuantizedTree* T1 = (const AABBQuantizedTree*)cache.Model1->GetTree(); Status = Collide(T0, T1, world0, world1, &cache); } else { const AABBCollisionTree* T0 = (const AABBCollisionTree*)cache.Model0->GetTree(); const AABBCollisionTree* T1 = (const AABBCollisionTree*)cache.Model1->GetTree(); Status = Collide(T0, T1, world0, world1, &cache); } } #ifdef __MESHMERIZER_H__ if(Status) { // Reset counter as long as overlap occurs if(GetContactStatus()) cache.ResetCountDown(); // Enable hull test again when counter reaches zero cache.CountDown--; if(!cache.CountDown) { cache.ResetCountDown(); cache.HullTest = true; } } #endif return Status; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a collision query : * - reset stats & contact status * - setup matrices * * \param world0 [in] world matrix for first object * \param world1 [in] world matrix for second object * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::InitQuery(const Matrix4x4* world0, const Matrix4x4* world1) { // Reset stats & contact status Collider::InitQuery(); mNbBVBVTests = 0; mNbPrimPrimTests = 0; mNbBVPrimTests = 0; mPairs.Reset(); // Setup matrices Matrix4x4 InvWorld0, InvWorld1; if(world0) InvertPRMatrix(InvWorld0, *world0); else InvWorld0.Identity(); if(world1) InvertPRMatrix(InvWorld1, *world1); else InvWorld1.Identity(); Matrix4x4 World0to1 = world0 ? (*world0 * InvWorld1) : InvWorld1; Matrix4x4 World1to0 = world1 ? (*world1 * InvWorld0) : InvWorld0; mR0to1 = World0to1; World0to1.GetTrans(mT0to1); mR1to0 = World1to0; World1to0.GetTrans(mT1to0); // Precompute absolute 1-to-0 rotation matrix for(udword i=0;i<3;i++) { for(udword j=0;j<3;j++) { // Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID) mAR.m[i][j] = 1e-6f + fabsf(mR1to0.m[i][j]); } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Takes advantage of temporal coherence. * \param cache [in] cache for a pair of previously colliding primitives * \return true if we can return immediately * \warning only works for "First Contact" mode */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeCollider::CheckTemporalCoherence(Pair* cache) { // Checkings if(!cache) return false; // Test previously colliding primitives first if(TemporalCoherenceEnabled() && FirstContactEnabled()) { PrimTest(cache->id0, cache->id1); if(GetContactStatus()) return true; } return false; } #define UPDATE_CACHE \ if(cache && GetContactStatus()) \ { \ cache->id0 = mPairs.GetEntry(0); \ cache->id1 = mPairs.GetEntry(1); \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Collision query for normal AABB trees. * \param tree0 [in] AABB tree from first object * \param tree1 [in] AABB tree from second object * \param world0 [in] world matrix for first object * \param world1 [in] world matrix for second object * \param cache [in/out] cache for a pair of previously colliding primitives * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeCollider::Collide(const AABBCollisionTree* tree0, const AABBCollisionTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) { // Init collision query InitQuery(world0, world1); // Check previous state if(CheckTemporalCoherence(cache)) return true; // Perform collision query _Collide(tree0->GetNodes(), tree1->GetNodes()); UPDATE_CACHE return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Collision query for no-leaf AABB trees. * \param tree0 [in] AABB tree from first object * \param tree1 [in] AABB tree from second object * \param world0 [in] world matrix for first object * \param world1 [in] world matrix for second object * \param cache [in/out] cache for a pair of previously colliding primitives * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeCollider::Collide(const AABBNoLeafTree* tree0, const AABBNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) { // Init collision query InitQuery(world0, world1); // Check previous state if(CheckTemporalCoherence(cache)) return true; // Perform collision query _Collide(tree0->GetNodes(), tree1->GetNodes()); UPDATE_CACHE return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Collision query for quantized AABB trees. * \param tree0 [in] AABB tree from first object * \param tree1 [in] AABB tree from second object * \param world0 [in] world matrix for first object * \param world1 [in] world matrix for second object * \param cache [in/out] cache for a pair of previously colliding primitives * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeCollider::Collide(const AABBQuantizedTree* tree0, const AABBQuantizedTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) { // Init collision query InitQuery(world0, world1); // Check previous state if(CheckTemporalCoherence(cache)) return true; // Setup dequantization coeffs mCenterCoeff0 = tree0->mCenterCoeff; mExtentsCoeff0 = tree0->mExtentsCoeff; mCenterCoeff1 = tree1->mCenterCoeff; mExtentsCoeff1 = tree1->mExtentsCoeff; // Dequantize box A const AABBQuantizedNode* N0 = tree0->GetNodes(); const Point a(float(N0->mAABB.mExtents[0]) * mExtentsCoeff0.x, float(N0->mAABB.mExtents[1]) * mExtentsCoeff0.y, float(N0->mAABB.mExtents[2]) * mExtentsCoeff0.z); const Point Pa(float(N0->mAABB.mCenter[0]) * mCenterCoeff0.x, float(N0->mAABB.mCenter[1]) * mCenterCoeff0.y, float(N0->mAABB.mCenter[2]) * mCenterCoeff0.z); // Dequantize box B const AABBQuantizedNode* N1 = tree1->GetNodes(); const Point b(float(N1->mAABB.mExtents[0]) * mExtentsCoeff1.x, float(N1->mAABB.mExtents[1]) * mExtentsCoeff1.y, float(N1->mAABB.mExtents[2]) * mExtentsCoeff1.z); const Point Pb(float(N1->mAABB.mCenter[0]) * mCenterCoeff1.x, float(N1->mAABB.mCenter[1]) * mCenterCoeff1.y, float(N1->mAABB.mCenter[2]) * mCenterCoeff1.z); // Perform collision query _Collide(N0, N1, a, Pa, b, Pb); UPDATE_CACHE return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Collision query for quantized no-leaf AABB trees. * \param tree0 [in] AABB tree from first object * \param tree1 [in] AABB tree from second object * \param world0 [in] world matrix for first object * \param world1 [in] world matrix for second object * \param cache [in/out] cache for a pair of previously colliding primitives * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool AABBTreeCollider::Collide(const AABBQuantizedNoLeafTree* tree0, const AABBQuantizedNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) { // Init collision query InitQuery(world0, world1); // Check previous state if(CheckTemporalCoherence(cache)) return true; // Setup dequantization coeffs mCenterCoeff0 = tree0->mCenterCoeff; mExtentsCoeff0 = tree0->mExtentsCoeff; mCenterCoeff1 = tree1->mCenterCoeff; mExtentsCoeff1 = tree1->mExtentsCoeff; // Perform collision query _Collide(tree0->GetNodes(), tree1->GetNodes()); UPDATE_CACHE return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Standard trees /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // The normal AABB tree can use 2 different descent rules (with different performances) //#define ORIGINAL_CODE //!< UNC-like descent rules #define ALTERNATIVE_CODE //!< Alternative descent rules #ifdef ORIGINAL_CODE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param b0 [in] collision node from first tree * \param b1 [in] collision node from second tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1) { // Perform BV-BV overlap test if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter)) return; if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; } if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize()))) { _Collide(b0->GetNeg(), b1); if(ContactFound()) return; _Collide(b0->GetPos(), b1); } else { _Collide(b0, b1->GetNeg()); if(ContactFound()) return; _Collide(b0, b1->GetPos()); } } #endif #ifdef ALTERNATIVE_CODE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for normal AABB trees. * \param b0 [in] collision node from first tree * \param b1 [in] collision node from second tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1) { // Perform BV-BV overlap test if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter)) { return; } if(b0->IsLeaf()) { if(b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); } else { _Collide(b0, b1->GetNeg()); if(ContactFound()) return; _Collide(b0, b1->GetPos()); } } else if(b1->IsLeaf()) { _Collide(b0->GetNeg(), b1); if(ContactFound()) return; _Collide(b0->GetPos(), b1); } else { _Collide(b0->GetNeg(), b1->GetNeg()); if(ContactFound()) return; _Collide(b0->GetNeg(), b1->GetPos()); if(ContactFound()) return; _Collide(b0->GetPos(), b1->GetNeg()); if(ContactFound()) return; _Collide(b0->GetPos(), b1->GetPos()); } } #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // No-leaf trees /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Leaf-leaf test for two primitive indices. * \param id0 [in] index from first leaf-triangle * \param id1 [in] index from second leaf-triangle */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::PrimTest(udword id0, udword id1) { // Request vertices from the app VertexPointers VP0; VertexPointers VP1; ConversionArea VC0; ConversionArea VC1; mIMesh0->GetTriangle(VP0, id0, VC0); mIMesh1->GetTriangle(VP1, id1, VC1); // Transform from space 1 to space 0 Point u0,u1,u2; TransformPoint(u0, *VP1.Vertex[0], mR1to0, mT1to0); TransformPoint(u1, *VP1.Vertex[1], mR1to0, mT1to0); TransformPoint(u2, *VP1.Vertex[2], mR1to0, mT1to0); // Perform triangle-triangle overlap test if(TriTriOverlap(*VP0.Vertex[0], *VP0.Vertex[1], *VP0.Vertex[2], u0, u1, u2)) { // Keep track of colliding pairs mPairs.Add(id0).Add(id1); // Set contact status mFlags |= OPC_CONTACT; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Leaf-leaf test for a previously fetched triangle from tree A (in B's space) and a new leaf from B. * \param id1 [in] leaf-triangle index from tree B */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void AABBTreeCollider::PrimTestTriIndex(udword id1) { // Request vertices from the app VertexPointers VP; ConversionArea VC; mIMesh1->GetTriangle(VP, id1, VC); // Perform triangle-triangle overlap test if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) { // Keep track of colliding pairs mPairs.Add(mLeafIndex).Add(id1); // Set contact status mFlags |= OPC_CONTACT; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Leaf-leaf test for a previously fetched triangle from tree B (in A's space) and a new leaf from A. * \param id0 [in] leaf-triangle index from tree A */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void AABBTreeCollider::PrimTestIndexTri(udword id0) { // Request vertices from the app VertexPointers VP; ConversionArea VC; mIMesh0->GetTriangle(VP, id0, VC); // Perform triangle-triangle overlap test if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) { // Keep track of colliding pairs mPairs.Add(id0).Add(mLeafIndex); // Set contact status mFlags |= OPC_CONTACT; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision of a leaf node from A and a branch from B. * \param b [in] collision node from second tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_CollideTriBox(const AABBNoLeafNode* b) { // Perform triangle-box overlap test if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return; // Keep same triangle, deal with first child if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive()); else _CollideTriBox(b->GetPos()); if(ContactFound()) return; // Keep same triangle, deal with second child if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive()); else _CollideTriBox(b->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision of a leaf node from B and a branch from A. * \param b [in] collision node from first tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_CollideBoxTri(const AABBNoLeafNode* b) { // Perform triangle-box overlap test if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return; // Keep same triangle, deal with first child if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive()); else _CollideBoxTri(b->GetPos()); if(ContactFound()) return; // Keep same triangle, deal with second child if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive()); else _CollideBoxTri(b->GetNeg()); } //! Request triangle vertices from the app and transform them #define FETCH_LEAF(prim_index, imesh, rot, trans) \ mLeafIndex = prim_index; \ /* Request vertices from the app */ \ VertexPointers VP; ConversionArea VC; imesh->GetTriangle(VP, prim_index, VC); \ /* Transform them in a common space */ \ TransformPoint(mLeafVerts[0], *VP.Vertex[0], rot, trans); \ TransformPoint(mLeafVerts[1], *VP.Vertex[1], rot, trans); \ TransformPoint(mLeafVerts[2], *VP.Vertex[2], rot, trans); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for no-leaf AABB trees. * \param a [in] collision node from first tree * \param b [in] collision node from second tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_Collide(const AABBNoLeafNode* a, const AABBNoLeafNode* b) { // Perform BV-BV overlap test if(!BoxBoxOverlap(a->mAABB.mExtents, a->mAABB.mCenter, b->mAABB.mExtents, b->mAABB.mCenter)) return; // Catch leaf status BOOL BHasPosLeaf = b->HasPosLeaf(); BOOL BHasNegLeaf = b->HasNegLeaf(); if(a->HasPosLeaf()) { FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1) if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); else _CollideTriBox(b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); else _CollideTriBox(b->GetNeg()); } else { if(BHasPosLeaf) { FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetPos()); } else _Collide(a->GetPos(), b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) { FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetPos()); } else _Collide(a->GetPos(), b->GetNeg()); } if(ContactFound()) return; if(a->HasNegLeaf()) { FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1) if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); else _CollideTriBox(b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); else _CollideTriBox(b->GetNeg()); } else { if(BHasPosLeaf) { // ### That leaf has possibly already been fetched FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetNeg()); } else _Collide(a->GetNeg(), b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) { // ### That leaf has possibly already been fetched FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetNeg()); } else _Collide(a->GetNeg(), b->GetNeg()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Quantized trees /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized AABB trees. * \param b0 [in] collision node from first tree * \param b1 [in] collision node from second tree * \param a [in] extent from box A * \param Pa [in] center from box A * \param b [in] extent from box B * \param Pb [in] center from box B */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_Collide(const AABBQuantizedNode* b0, const AABBQuantizedNode* b1, const Point& a, const Point& Pa, const Point& b, const Point& Pb) { // Perform BV-BV overlap test if(!BoxBoxOverlap(a, Pa, b, Pb)) return; if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; } if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize()))) { // Dequantize box const QuantizedAABB* Box = &b0->GetNeg()->mAABB; const Point negPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z); const Point nega(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z); _Collide(b0->GetNeg(), b1, nega, negPa, b, Pb); if(ContactFound()) return; // Dequantize box Box = &b0->GetPos()->mAABB; const Point posPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z); const Point posa(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z); _Collide(b0->GetPos(), b1, posa, posPa, b, Pb); } else { // Dequantize box const QuantizedAABB* Box = &b1->GetNeg()->mAABB; const Point negPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z); const Point negb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z); _Collide(b0, b1->GetNeg(), a, Pa, negb, negPb); if(ContactFound()) return; // Dequantize box Box = &b1->GetPos()->mAABB; const Point posPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z); const Point posb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z); _Collide(b0, b1->GetPos(), a, Pa, posb, posPb); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Quantized no-leaf trees /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision of a leaf node from A and a quantized branch from B. * \param leaf [in] leaf triangle from first tree * \param b [in] collision node from second tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_CollideTriBox(const AABBQuantizedNoLeafNode* b) { // Dequantize box const QuantizedAABB* bb = &b->mAABB; const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z); const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z); // Perform triangle-box overlap test if(!TriBoxOverlap(Pb, eb)) return; if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive()); else _CollideTriBox(b->GetPos()); if(ContactFound()) return; if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive()); else _CollideTriBox(b->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision of a leaf node from B and a quantized branch from A. * \param b [in] collision node from first tree * \param leaf [in] leaf triangle from second tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_CollideBoxTri(const AABBQuantizedNoLeafNode* b) { // Dequantize box const QuantizedAABB* bb = &b->mAABB; const Point Pa(float(bb->mCenter[0]) * mCenterCoeff0.x, float(bb->mCenter[1]) * mCenterCoeff0.y, float(bb->mCenter[2]) * mCenterCoeff0.z); const Point ea(float(bb->mExtents[0]) * mExtentsCoeff0.x, float(bb->mExtents[1]) * mExtentsCoeff0.y, float(bb->mExtents[2]) * mExtentsCoeff0.z); // Perform triangle-box overlap test if(!TriBoxOverlap(Pa, ea)) return; if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive()); else _CollideBoxTri(b->GetPos()); if(ContactFound()) return; if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive()); else _CollideBoxTri(b->GetNeg()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Recursive collision query for quantized no-leaf AABB trees. * \param a [in] collision node from first tree * \param b [in] collision node from second tree */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AABBTreeCollider::_Collide(const AABBQuantizedNoLeafNode* a, const AABBQuantizedNoLeafNode* b) { // Dequantize box A const QuantizedAABB* ab = &a->mAABB; const Point Pa(float(ab->mCenter[0]) * mCenterCoeff0.x, float(ab->mCenter[1]) * mCenterCoeff0.y, float(ab->mCenter[2]) * mCenterCoeff0.z); const Point ea(float(ab->mExtents[0]) * mExtentsCoeff0.x, float(ab->mExtents[1]) * mExtentsCoeff0.y, float(ab->mExtents[2]) * mExtentsCoeff0.z); // Dequantize box B const QuantizedAABB* bb = &b->mAABB; const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z); const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z); // Perform BV-BV overlap test if(!BoxBoxOverlap(ea, Pa, eb, Pb)) return; // Catch leaf status BOOL BHasPosLeaf = b->HasPosLeaf(); BOOL BHasNegLeaf = b->HasNegLeaf(); if(a->HasPosLeaf()) { FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1) if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); else _CollideTriBox(b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); else _CollideTriBox(b->GetNeg()); } else { if(BHasPosLeaf) { FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetPos()); } else _Collide(a->GetPos(), b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) { FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetPos()); } else _Collide(a->GetPos(), b->GetNeg()); } if(ContactFound()) return; if(a->HasNegLeaf()) { FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1) if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); else _CollideTriBox(b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); else _CollideTriBox(b->GetNeg()); } else { if(BHasPosLeaf) { // ### That leaf has possibly already been fetched FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetNeg()); } else _Collide(a->GetNeg(), b->GetPos()); if(ContactFound()) return; if(BHasNegLeaf) { // ### That leaf has possibly already been fetched FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) _CollideBoxTri(a->GetNeg()); } else _Collide(a->GetNeg(), b->GetNeg()); } } ode-0.14/OPCODE/OPC_TreeCollider.h0000644000000000000000000003217412635011627015115 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains code for a tree collider. * \file OPC_TreeCollider.h * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_TREECOLLIDER_H__ #define __OPC_TREECOLLIDER_H__ //! This structure holds cached information used by the algorithm. //! Two model pointers and two colliding primitives are cached. Model pointers are assigned //! to their respective meshes, and the pair of colliding primitives is used for temporal //! coherence. That is, in case temporal coherence is enabled, those two primitives are //! tested for overlap before everything else. If they still collide, we're done before //! even entering the recursive collision code. struct OPCODE_API BVTCache : Pair { //! Constructor inline_ BVTCache() { ResetCache(); ResetCountDown(); } void ResetCache() { Model0 = null; Model1 = null; id0 = 0; id1 = 1; #ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! HullTest = true; SepVector.pid = 0; SepVector.qid = 0; SepVector.SV = Point(1.0f, 0.0f, 0.0f); #endif // __MESHMERIZER_H__ } #ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! inline_ void ResetCountDown() { CountDown = 50; } #else void ResetCountDown(){}; #endif // __MESHMERIZER_H__ const Model* Model0; //!< Model for first object const Model* Model1; //!< Model for second object #ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! SVCache SepVector; udword CountDown; bool HullTest; #endif // __MESHMERIZER_H__ }; class OPCODE_API AABBTreeCollider : public Collider { public: // Constructor / Destructor AABBTreeCollider(); virtual ~AABBTreeCollider(); // Generic collision query /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Generic collision query for generic OPCODE models. After the call, access the results with: * - GetContactStatus() * - GetNbPairs() * - GetPairs() * * \param cache [in] collision cache for model pointers and a colliding pair of primitives * \param world0 [in] world matrix for first object, or null * \param world1 [in] world matrix for second object, or null * \return true if success * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Collide(BVTCache& cache, const Matrix4x4* world0=null, const Matrix4x4* world1=null); // Collision queries bool Collide(const AABBCollisionTree* tree0, const AABBCollisionTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); bool Collide(const AABBNoLeafTree* tree0, const AABBNoLeafTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); bool Collide(const AABBQuantizedTree* tree0, const AABBQuantizedTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); bool Collide(const AABBQuantizedNoLeafTree* tree0, const AABBQuantizedNoLeafTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); // Settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Settings: selects between full box-box tests or "SAT-lite" tests (where Class III axes are discarded) * \param flag [in] true for full tests, false for coarse tests * \see SetFullPrimBoxTest(bool flag) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetFullBoxBoxTest(bool flag) { mFullBoxBoxTest = flag; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Settings: selects between full triangle-box tests or "SAT-lite" tests (where Class III axes are discarded) * \param flag [in] true for full tests, false for coarse tests * \see SetFullBoxBoxTest(bool flag) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ void SetFullPrimBoxTest(bool flag) { mFullPrimBoxTest = flag; } // Stats /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of BV-BV overlap tests after a collision query. * \see GetNbPrimPrimTests() * \see GetNbBVPrimTests() * \return the number of BV-BV tests performed during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbBVBVTests() const { return mNbBVBVTests; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of Triangle-Triangle overlap tests after a collision query. * \see GetNbBVBVTests() * \see GetNbBVPrimTests() * \return the number of Triangle-Triangle tests performed during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbPrimPrimTests() const { return mNbPrimPrimTests; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of BV-Triangle overlap tests after a collision query. * \see GetNbBVBVTests() * \see GetNbPrimPrimTests() * \return the number of BV-Triangle tests performed during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbBVPrimTests() const { return mNbBVPrimTests; } // Data access /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of contacts after a collision query. * \see GetContactStatus() * \see GetPairs() * \return the number of contacts / colliding pairs. */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbPairs() const { return mPairs.GetNbEntries()>>1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the pairs of colliding triangles after a collision query. * \see GetContactStatus() * \see GetNbPairs() * \return the list of colliding pairs (triangle indices) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const Pair* GetPairs() const { return (const Pair*)mPairs.GetEntries(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(Collider) const char* ValidateSettings(); protected: // Colliding pairs Container mPairs; //!< Pairs of colliding primitives // User mesh interfaces const MeshInterface* mIMesh0; //!< User-defined mesh interface for object0 const MeshInterface* mIMesh1; //!< User-defined mesh interface for object1 // Stats udword mNbBVBVTests; //!< Number of BV-BV tests udword mNbPrimPrimTests; //!< Number of Primitive-Primitive tests udword mNbBVPrimTests; //!< Number of BV-Primitive tests // Precomputed data Matrix3x3 mAR; //!< Absolute rotation matrix Matrix3x3 mR0to1; //!< Rotation from object0 to object1 Matrix3x3 mR1to0; //!< Rotation from object1 to object0 Point mT0to1; //!< Translation from object0 to object1 Point mT1to0; //!< Translation from object1 to object0 // Dequantization coeffs Point mCenterCoeff0; Point mExtentsCoeff0; Point mCenterCoeff1; Point mExtentsCoeff1; // Leaf description Point mLeafVerts[3]; //!< Triangle vertices udword mLeafIndex; //!< Triangle index // Settings bool mFullBoxBoxTest; //!< Perform full BV-BV tests (true) or SAT-lite tests (false) bool mFullPrimBoxTest; //!< Perform full Primitive-BV tests (true) or SAT-lite tests (false) // Internal methods // Standard AABB trees void _Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1); // Quantized AABB trees void _Collide(const AABBQuantizedNode* b0, const AABBQuantizedNode* b1, const Point& a, const Point& Pa, const Point& b, const Point& Pb); // No-leaf AABB trees void _CollideTriBox(const AABBNoLeafNode* b); void _CollideBoxTri(const AABBNoLeafNode* b); void _Collide(const AABBNoLeafNode* a, const AABBNoLeafNode* b); // Quantized no-leaf AABB trees void _CollideTriBox(const AABBQuantizedNoLeafNode* b); void _CollideBoxTri(const AABBQuantizedNoLeafNode* b); void _Collide(const AABBQuantizedNoLeafNode* a, const AABBQuantizedNoLeafNode* b); // Overlap tests void PrimTest(udword id0, udword id1); inline_ void PrimTestTriIndex(udword id1); inline_ void PrimTestIndexTri(udword id0); inline_ BOOL BoxBoxOverlap(const Point& ea, const Point& ca, const Point& eb, const Point& cb); inline_ BOOL TriBoxOverlap(const Point& center, const Point& extents); inline_ BOOL TriTriOverlap(const Point& V0, const Point& V1, const Point& V2, const Point& U0, const Point& U1, const Point& U2); // Init methods void InitQuery(const Matrix4x4* world0=null, const Matrix4x4* world1=null); bool CheckTemporalCoherence(Pair* cache); inline_ BOOL Setup(const MeshInterface* mi0, const MeshInterface* mi1) { mIMesh0 = mi0; mIMesh1 = mi1; if(!mIMesh0 || !mIMesh1) return FALSE; return TRUE; } }; #endif // __OPC_TREECOLLIDER_H__ ode-0.14/OPCODE/OPC_TriBoxOverlap.h0000644000000000000000000002633312635011627015300 0ustar rootroot //! This macro quickly finds the min & max values among 3 variables #define FINDMINMAX(x0, x1, x2, min, max) \ min = max = x0; \ if(x1max) max=x1; \ if(x2max) max=x2; //! TO BE DOCUMENTED inline_ BOOL planeBoxOverlap(const Point& normal, const float d, const Point& maxbox) { Point vmin, vmax; for(udword q=0;q<=2;q++) { if(normal[q]>0.0f) { vmin[q]=-maxbox[q]; vmax[q]=maxbox[q]; } else { vmin[q]=maxbox[q]; vmax[q]=-maxbox[q]; } } if((normal|vmin)+d>0.0f) return FALSE; if((normal|vmax)+d>=0.0f) return TRUE; return FALSE; } //! TO BE DOCUMENTED #define AXISTEST_X01(a, b, fa, fb) \ min = a*v0.y - b*v0.z; \ max = a*v2.y - b*v2.z; \ if(min>max) {const float tmp=max; max=min; min=tmp; } \ rad = fa * extents.y + fb * extents.z; \ if(min>rad || max<-rad) return FALSE; //! TO BE DOCUMENTED #define AXISTEST_X2(a, b, fa, fb) \ min = a*v0.y - b*v0.z; \ max = a*v1.y - b*v1.z; \ if(min>max) {const float tmp=max; max=min; min=tmp; } \ rad = fa * extents.y + fb * extents.z; \ if(min>rad || max<-rad) return FALSE; //! TO BE DOCUMENTED #define AXISTEST_Y02(a, b, fa, fb) \ min = b*v0.z - a*v0.x; \ max = b*v2.z - a*v2.x; \ if(min>max) {const float tmp=max; max=min; min=tmp; } \ rad = fa * extents.x + fb * extents.z; \ if(min>rad || max<-rad) return FALSE; //! TO BE DOCUMENTED #define AXISTEST_Y1(a, b, fa, fb) \ min = b*v0.z - a*v0.x; \ max = b*v1.z - a*v1.x; \ if(min>max) {const float tmp=max; max=min; min=tmp; } \ rad = fa * extents.x + fb * extents.z; \ if(min>rad || max<-rad) return FALSE; //! TO BE DOCUMENTED #define AXISTEST_Z12(a, b, fa, fb) \ min = a*v1.x - b*v1.y; \ max = a*v2.x - b*v2.y; \ if(min>max) {const float tmp=max; max=min; min=tmp; } \ rad = fa * extents.x + fb * extents.y; \ if(min>rad || max<-rad) return FALSE; //! TO BE DOCUMENTED #define AXISTEST_Z0(a, b, fa, fb) \ min = a*v0.x - b*v0.y; \ max = a*v1.x - b*v1.y; \ if(min>max) {const float tmp=max; max=min; min=tmp; } \ rad = fa * extents.x + fb * extents.y; \ if(min>rad || max<-rad) return FALSE; // compute triangle edges // - edges lazy evaluated to take advantage of early exits // - fabs precomputed (half less work, possible since extents are always >0) // - customized macros to take advantage of the null component // - axis vector discarded, possibly saves useless movs #define IMPLEMENT_CLASS3_TESTS \ float rad; \ float min, max; \ \ const float fey0 = fabsf(e0.y); \ const float fez0 = fabsf(e0.z); \ AXISTEST_X01(e0.z, e0.y, fez0, fey0); \ const float fex0 = fabsf(e0.x); \ AXISTEST_Y02(e0.z, e0.x, fez0, fex0); \ AXISTEST_Z12(e0.y, e0.x, fey0, fex0); \ \ const float fey1 = fabsf(e1.y); \ const float fez1 = fabsf(e1.z); \ AXISTEST_X01(e1.z, e1.y, fez1, fey1); \ const float fex1 = fabsf(e1.x); \ AXISTEST_Y02(e1.z, e1.x, fez1, fex1); \ AXISTEST_Z0(e1.y, e1.x, fey1, fex1); \ \ const Point e2 = mLeafVerts[0] - mLeafVerts[2]; \ const float fey2 = fabsf(e2.y); \ const float fez2 = fabsf(e2.z); \ AXISTEST_X2(e2.z, e2.y, fez2, fey2); \ const float fex2 = fabsf(e2.x); \ AXISTEST_Y1(e2.z, e2.x, fez2, fex2); \ AXISTEST_Z12(e2.y, e2.x, fey2, fex2); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Triangle-Box overlap test using the separating axis theorem. * This is the code from Tomas Mller, a bit optimized: * - with some more lazy evaluation (faster path on PC) * - with a tiny bit of assembly * - with "SAT-lite" applied if needed * - and perhaps with some more minor modifs... * * \param center [in] box center * \param extents [in] box extents * \return true if triangle & box overlap */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL AABBTreeCollider::TriBoxOverlap(const Point& center, const Point& extents) { // Stats mNbBVPrimTests++; // use separating axis theorem to test overlap between triangle and box // need to test for overlap in these directions: // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle // we do not even need to test these) // 2) normal of the triangle // 3) crossproduct(edge from tri, {x,y,z}-directin) // this gives 3x3=9 more tests // move everything so that the boxcenter is in (0,0,0) Point v0, v1, v2; v0.x = mLeafVerts[0].x - center.x; v1.x = mLeafVerts[1].x - center.x; v2.x = mLeafVerts[2].x - center.x; // First, test overlap in the {x,y,z}-directions #ifdef OPC_USE_FCOMI // find min, max of the triangle in x-direction, and test for overlap in X if(FCMin3(v0.x, v1.x, v2.x)>extents.x) return FALSE; if(FCMax3(v0.x, v1.x, v2.x)<-extents.x) return FALSE; // same for Y v0.y = mLeafVerts[0].y - center.y; v1.y = mLeafVerts[1].y - center.y; v2.y = mLeafVerts[2].y - center.y; if(FCMin3(v0.y, v1.y, v2.y)>extents.y) return FALSE; if(FCMax3(v0.y, v1.y, v2.y)<-extents.y) return FALSE; // same for Z v0.z = mLeafVerts[0].z - center.z; v1.z = mLeafVerts[1].z - center.z; v2.z = mLeafVerts[2].z - center.z; if(FCMin3(v0.z, v1.z, v2.z)>extents.z) return FALSE; if(FCMax3(v0.z, v1.z, v2.z)<-extents.z) return FALSE; #else float min,max; // Find min, max of the triangle in x-direction, and test for overlap in X FINDMINMAX(v0.x, v1.x, v2.x, min, max); if(min>extents.x || max<-extents.x) return FALSE; // Same for Y v0.y = mLeafVerts[0].y - center.y; v1.y = mLeafVerts[1].y - center.y; v2.y = mLeafVerts[2].y - center.y; FINDMINMAX(v0.y, v1.y, v2.y, min, max); if(min>extents.y || max<-extents.y) return FALSE; // Same for Z v0.z = mLeafVerts[0].z - center.z; v1.z = mLeafVerts[1].z - center.z; v2.z = mLeafVerts[2].z - center.z; FINDMINMAX(v0.z, v1.z, v2.z, min, max); if(min>extents.z || max<-extents.z) return FALSE; #endif // 2) Test if the box intersects the plane of the triangle // compute plane equation of triangle: normal*x+d=0 // ### could be precomputed since we use the same leaf triangle several times const Point e0 = v1 - v0; const Point e1 = v2 - v1; const Point normal = e0 ^ e1; const float d = -normal|v0; if(!planeBoxOverlap(normal, d, extents)) return FALSE; // 3) "Class III" tests if(mFullPrimBoxTest) { IMPLEMENT_CLASS3_TESTS } return TRUE; } //! A dedicated version where the box is constant inline_ BOOL OBBCollider::TriBoxOverlap() { // Stats mNbVolumePrimTests++; // Hook const Point& extents = mBoxExtents; const Point& v0 = mLeafVerts[0]; const Point& v1 = mLeafVerts[1]; const Point& v2 = mLeafVerts[2]; // use separating axis theorem to test overlap between triangle and box // need to test for overlap in these directions: // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle // we do not even need to test these) // 2) normal of the triangle // 3) crossproduct(edge from tri, {x,y,z}-directin) // this gives 3x3=9 more tests // Box center is already in (0,0,0) // First, test overlap in the {x,y,z}-directions #ifdef OPC_USE_FCOMI // find min, max of the triangle in x-direction, and test for overlap in X if(FCMin3(v0.x, v1.x, v2.x)>mBoxExtents.x) return FALSE; if(FCMax3(v0.x, v1.x, v2.x)<-mBoxExtents.x) return FALSE; if(FCMin3(v0.y, v1.y, v2.y)>mBoxExtents.y) return FALSE; if(FCMax3(v0.y, v1.y, v2.y)<-mBoxExtents.y) return FALSE; if(FCMin3(v0.z, v1.z, v2.z)>mBoxExtents.z) return FALSE; if(FCMax3(v0.z, v1.z, v2.z)<-mBoxExtents.z) return FALSE; #else float min,max; // Find min, max of the triangle in x-direction, and test for overlap in X FINDMINMAX(v0.x, v1.x, v2.x, min, max); if(min>mBoxExtents.x || max<-mBoxExtents.x) return FALSE; FINDMINMAX(v0.y, v1.y, v2.y, min, max); if(min>mBoxExtents.y || max<-mBoxExtents.y) return FALSE; FINDMINMAX(v0.z, v1.z, v2.z, min, max); if(min>mBoxExtents.z || max<-mBoxExtents.z) return FALSE; #endif // 2) Test if the box intersects the plane of the triangle // compute plane equation of triangle: normal*x+d=0 // ### could be precomputed since we use the same leaf triangle several times const Point e0 = v1 - v0; const Point e1 = v2 - v1; const Point normal = e0 ^ e1; const float d = -normal|v0; if(!planeBoxOverlap(normal, d, mBoxExtents)) return FALSE; // 3) "Class III" tests - here we always do full tests since the box is a primitive (not a BV) { IMPLEMENT_CLASS3_TESTS } return TRUE; } //! ...and another one, jeez inline_ BOOL AABBCollider::TriBoxOverlap() { // Stats mNbVolumePrimTests++; // Hook const Point& center = mBox.mCenter; const Point& extents = mBox.mExtents; // use separating axis theorem to test overlap between triangle and box // need to test for overlap in these directions: // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle // we do not even need to test these) // 2) normal of the triangle // 3) crossproduct(edge from tri, {x,y,z}-directin) // this gives 3x3=9 more tests // move everything so that the boxcenter is in (0,0,0) Point v0, v1, v2; v0.x = mLeafVerts[0].x - center.x; v1.x = mLeafVerts[1].x - center.x; v2.x = mLeafVerts[2].x - center.x; // First, test overlap in the {x,y,z}-directions #ifdef OPC_USE_FCOMI // find min, max of the triangle in x-direction, and test for overlap in X if(FCMin3(v0.x, v1.x, v2.x)>extents.x) return FALSE; if(FCMax3(v0.x, v1.x, v2.x)<-extents.x) return FALSE; // same for Y v0.y = mLeafVerts[0].y - center.y; v1.y = mLeafVerts[1].y - center.y; v2.y = mLeafVerts[2].y - center.y; if(FCMin3(v0.y, v1.y, v2.y)>extents.y) return FALSE; if(FCMax3(v0.y, v1.y, v2.y)<-extents.y) return FALSE; // same for Z v0.z = mLeafVerts[0].z - center.z; v1.z = mLeafVerts[1].z - center.z; v2.z = mLeafVerts[2].z - center.z; if(FCMin3(v0.z, v1.z, v2.z)>extents.z) return FALSE; if(FCMax3(v0.z, v1.z, v2.z)<-extents.z) return FALSE; #else float min,max; // Find min, max of the triangle in x-direction, and test for overlap in X FINDMINMAX(v0.x, v1.x, v2.x, min, max); if(min>extents.x || max<-extents.x) return FALSE; // Same for Y v0.y = mLeafVerts[0].y - center.y; v1.y = mLeafVerts[1].y - center.y; v2.y = mLeafVerts[2].y - center.y; FINDMINMAX(v0.y, v1.y, v2.y, min, max); if(min>extents.y || max<-extents.y) return FALSE; // Same for Z v0.z = mLeafVerts[0].z - center.z; v1.z = mLeafVerts[1].z - center.z; v2.z = mLeafVerts[2].z - center.z; FINDMINMAX(v0.z, v1.z, v2.z, min, max); if(min>extents.z || max<-extents.z) return FALSE; #endif // 2) Test if the box intersects the plane of the triangle // compute plane equation of triangle: normal*x+d=0 // ### could be precomputed since we use the same leaf triangle several times const Point e0 = v1 - v0; const Point e1 = v2 - v1; const Point normal = e0 ^ e1; const float d = -normal|v0; if(!planeBoxOverlap(normal, d, extents)) return FALSE; // 3) "Class III" tests - here we always do full tests since the box is a primitive (not a BV) { IMPLEMENT_CLASS3_TESTS } return TRUE; } ode-0.14/OPCODE/OPC_TriTriOverlap.h0000644000000000000000000002205712635011627015305 0ustar rootroot //! if OPC_TRITRI_EPSILON_TEST is true then we do a check (if |dv|b) \ { \ const float c=a; \ a=b; \ b=c; \ } //! Edge to edge test based on Franlin Antonio's gem: "Faster Line Segment Intersection", in Graphics Gems III, pp. 199-202 #define EDGE_EDGE_TEST(V0, U0, U1) \ Bx = U0[i0] - U1[i0]; \ By = U0[i1] - U1[i1]; \ Cx = V0[i0] - U0[i0]; \ Cy = V0[i1] - U0[i1]; \ f = Ay*Bx - Ax*By; \ d = By*Cx - Bx*Cy; \ if((f>0.0f && d>=0.0f && d<=f) || (f<0.0f && d<=0.0f && d>=f)) \ { \ const float e=Ax*Cy - Ay*Cx; \ if(f>0.0f) \ { \ if(e>=0.0f && e<=f) return TRUE; \ } \ else \ { \ if(e<=0.0f && e>=f) return TRUE; \ } \ } //! TO BE DOCUMENTED #define EDGE_AGAINST_TRI_EDGES(V0, V1, U0, U1, U2) \ { \ float Bx,By,Cx,Cy,d,f; \ const float Ax = V1[i0] - V0[i0]; \ const float Ay = V1[i1] - V0[i1]; \ /* test edge U0,U1 against V0,V1 */ \ EDGE_EDGE_TEST(V0, U0, U1); \ /* test edge U1,U2 against V0,V1 */ \ EDGE_EDGE_TEST(V0, U1, U2); \ /* test edge U2,U1 against V0,V1 */ \ EDGE_EDGE_TEST(V0, U2, U0); \ } //! TO BE DOCUMENTED #define POINT_IN_TRI(V0, U0, U1, U2) \ { \ /* is T1 completly inside T2? */ \ /* check if V0 is inside tri(U0,U1,U2) */ \ float a = U1[i1] - U0[i1]; \ float b = -(U1[i0] - U0[i0]); \ float c = -a*U0[i0] - b*U0[i1]; \ float d0 = a*V0[i0] + b*V0[i1] + c; \ \ a = U2[i1] - U1[i1]; \ b = -(U2[i0] - U1[i0]); \ c = -a*U1[i0] - b*U1[i1]; \ const float d1 = a*V0[i0] + b*V0[i1] + c; \ \ a = U0[i1] - U2[i1]; \ b = -(U0[i0] - U2[i0]); \ c = -a*U2[i0] - b*U2[i1]; \ const float d2 = a*V0[i0] + b*V0[i1] + c; \ if(d0*d1>0.0f) \ { \ if(d0*d2>0.0f) return TRUE; \ } \ } //! TO BE DOCUMENTED BOOL CoplanarTriTri(const Point& n, const Point& v0, const Point& v1, const Point& v2, const Point& u0, const Point& u1, const Point& u2) { float A[3]; short i0,i1; /* first project onto an axis-aligned plane, that maximizes the area */ /* of the triangles, compute indices: i0,i1. */ A[0] = fabsf(n[0]); A[1] = fabsf(n[1]); A[2] = fabsf(n[2]); if(A[0]>A[1]) { if(A[0]>A[2]) { i0=1; /* A[0] is greatest */ i1=2; } else { i0=0; /* A[2] is greatest */ i1=1; } } else /* A[0]<=A[1] */ { if(A[2]>A[1]) { i0=0; /* A[2] is greatest */ i1=1; } else { i0=0; /* A[1] is greatest */ i1=2; } } /* test all edges of triangle 1 against the edges of triangle 2 */ EDGE_AGAINST_TRI_EDGES(v0, v1, u0, u1, u2); EDGE_AGAINST_TRI_EDGES(v1, v2, u0, u1, u2); EDGE_AGAINST_TRI_EDGES(v2, v0, u0, u1, u2); /* finally, test if tri1 is totally contained in tri2 or vice versa */ POINT_IN_TRI(v0, u0, u1, u2); POINT_IN_TRI(u0, v0, v1, v2); return FALSE; } //! TO BE DOCUMENTED #define NEWCOMPUTE_INTERVALS(VV0, VV1, VV2, D0, D1, D2, D0D1, D0D2, A, B, C, X0, X1) \ { \ if(D0D1>0.0f) \ { \ /* here we know that D0D2<=0.0 */ \ /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ A=VV2; B=(VV0 - VV2)*D2; C=(VV1 - VV2)*D2; X0=D2 - D0; X1=D2 - D1; \ } \ else if(D0D2>0.0f) \ { \ /* here we know that d0d1<=0.0 */ \ A=VV1; B=(VV0 - VV1)*D1; C=(VV2 - VV1)*D1; X0=D1 - D0; X1=D1 - D2; \ } \ else if(D1*D2>0.0f || D0!=0.0f) \ { \ /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ A=VV0; B=(VV1 - VV0)*D0; C=(VV2 - VV0)*D0; X0=D0 - D1; X1=D0 - D2; \ } \ else if(D1!=0.0f) \ { \ A=VV1; B=(VV0 - VV1)*D1; C=(VV2 - VV1)*D1; X0=D1 - D0; X1=D1 - D2; \ } \ else if(D2!=0.0f) \ { \ A=VV2; B=(VV0 - VV2)*D2; C=(VV1 - VV2)*D2; X0=D2 - D0; X1=D2 - D1; \ } \ else \ { \ /* triangles are coplanar */ \ return CoplanarTriTri(N1, V0, V1, V2, U0, U1, U2); \ } \ } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Triangle/triangle intersection test routine, * by Tomas Moller, 1997. * See article "A Fast Triangle-Triangle Intersection Test", * Journal of Graphics Tools, 2(2), 1997 * * Updated June 1999: removed the divisions -- a little faster now! * Updated October 1999: added {} to CROSS and SUB macros * * int NoDivTriTriIsect(float V0[3],float V1[3],float V2[3], * float U0[3],float U1[3],float U2[3]) * * \param V0 [in] triangle 0, vertex 0 * \param V1 [in] triangle 0, vertex 1 * \param V2 [in] triangle 0, vertex 2 * \param U0 [in] triangle 1, vertex 0 * \param U1 [in] triangle 1, vertex 1 * \param U2 [in] triangle 1, vertex 2 * \return true if triangles overlap */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ BOOL AABBTreeCollider::TriTriOverlap(const Point& V0, const Point& V1, const Point& V2, const Point& U0, const Point& U1, const Point& U2) { // Stats mNbPrimPrimTests++; // Compute plane equation of triangle(V0,V1,V2) Point E1 = V1 - V0; Point E2 = V2 - V0; const Point N1 = E1 ^ E2; const float d1 =-N1 | V0; // Plane equation 1: N1.X+d1=0 // Put U0,U1,U2 into plane equation 1 to compute signed distances to the plane float du0 = (N1|U0) + d1; float du1 = (N1|U1) + d1; float du2 = (N1|U2) + d1; // Coplanarity robustness check #ifdef OPC_TRITRI_EPSILON_TEST float absd1 = FastFabs(d1), sqmagN1 = N1.SquareMagnitude(); if (absd1>=sqmagN1) { if(FastFabs(du0)<=LOCAL_EPSILON*absd1) du0 = 0.0f; if(FastFabs(du1)<=LOCAL_EPSILON*absd1) du1 = 0.0f; if(FastFabs(du2)<=LOCAL_EPSILON*absd1) du2 = 0.0f; } else { if(FastFabs(du0)<=LOCAL_EPSILON*FCMax2(absd1, FCMin2(sqmagN1, U0.SquareMagnitude()))) du0 = 0.0f; if(FastFabs(du1)<=LOCAL_EPSILON*FCMax2(absd1, FCMin2(sqmagN1, U1.SquareMagnitude()))) du1 = 0.0f; if(FastFabs(du2)<=LOCAL_EPSILON*FCMax2(absd1, FCMin2(sqmagN1, U2.SquareMagnitude()))) du2 = 0.0f; } #endif const float du0du1 = du0 * du1; const float du0du2 = du0 * du2; if(du0du1>0.0f && du0du2>0.0f) // same sign on all of them + not equal 0 ? return FALSE; // no intersection occurs // Compute plane of triangle (U0,U1,U2) E1 = U1 - U0; E2 = U2 - U0; const Point N2 = E1 ^ E2; const float d2=-N2 | U0; // plane equation 2: N2.X+d2=0 // put V0,V1,V2 into plane equation 2 float dv0 = (N2|V0) + d2; float dv1 = (N2|V1) + d2; float dv2 = (N2|V2) + d2; #ifdef OPC_TRITRI_EPSILON_TEST float absd2 = FastFabs(d2), sqmagN2 = N2.SquareMagnitude(); if (absd2>=sqmagN2) { if(FastFabs(dv0)<=LOCAL_EPSILON*absd2) dv0 = 0.0f; if(FastFabs(dv1)<=LOCAL_EPSILON*absd2) dv1 = 0.0f; if(FastFabs(dv2)<=LOCAL_EPSILON*absd2) dv2 = 0.0f; } else { if(FastFabs(dv0)<=LOCAL_EPSILON*FCMax2(absd2, FCMin2(sqmagN2, V0.SquareMagnitude()))) dv0 = 0.0f; if(FastFabs(dv1)<=LOCAL_EPSILON*FCMax2(absd2, FCMin2(sqmagN2, V1.SquareMagnitude()))) dv1 = 0.0f; if(FastFabs(dv2)<=LOCAL_EPSILON*FCMax2(absd2, FCMin2(sqmagN2, V2.SquareMagnitude()))) dv2 = 0.0f; } #endif const float dv0dv1 = dv0 * dv1; const float dv0dv2 = dv0 * dv2; if(dv0dv1>0.0f && dv0dv2>0.0f) // same sign on all of them + not equal 0 ? return FALSE; // no intersection occurs // Compute direction of intersection line const Point D = N1^N2; // Compute and index to the largest component of D float max=fabsf(D[0]); short index=0; float bb=fabsf(D[1]); float cc=fabsf(D[2]); if(bb>max) max=bb,index=1; if(cc>max) max=cc,index=2; // This is the simplified projection onto L const float vp0 = V0[index]; const float vp1 = V1[index]; const float vp2 = V2[index]; const float up0 = U0[index]; const float up1 = U1[index]; const float up2 = U2[index]; // Compute interval for triangle 1 float a,b,c,x0,x1; NEWCOMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,a,b,c,x0,x1); // Compute interval for triangle 2 float d,e,f,y0,y1; NEWCOMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,d,e,f,y0,y1); const float xx=x0*x1; const float yy=y0*y1; const float xxyy=xx*yy; float isect1[2], isect2[2]; float tmp=a*xxyy; isect1[0]=tmp+b*x1*yy; isect1[1]=tmp+c*x0*yy; tmp=d*xxyy; isect2[0]=tmp+e*xx*y1; isect2[1]=tmp+f*xx*y0; SORT(isect1[0],isect1[1]); SORT(isect2[0],isect2[1]); if(isect1[1]HasPosLeaf()) mTouchedPrimitives->Add(udword(node->GetPosPrimitive())); \ else _Dump(node->GetPos()); \ \ if(ContactFound()) return; \ \ if(node->HasNegLeaf()) mTouchedPrimitives->Add(udword(node->GetNegPrimitive())); \ else _Dump(node->GetNeg()); \ } #define IMPLEMENT_LEAFDUMP(type) \ void VolumeCollider::_Dump(const type* node) \ { \ if(node->IsLeaf()) \ { \ mTouchedPrimitives->Add(udword(node->GetPrimitive())); \ } \ else \ { \ _Dump(node->GetPos()); \ \ if(ContactFound()) return; \ \ _Dump(node->GetNeg()); \ } \ } IMPLEMENT_NOLEAFDUMP(AABBNoLeafNode) IMPLEMENT_NOLEAFDUMP(AABBQuantizedNoLeafNode) IMPLEMENT_LEAFDUMP(AABBCollisionNode) IMPLEMENT_LEAFDUMP(AABBQuantizedNode) ode-0.14/OPCODE/OPC_VolumeCollider.h0000644000000000000000000001572312635011627015466 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Contains base volume collider class. * \file OPC_VolumeCollider.h * \author Pierre Terdiman * \date June, 2, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPC_VOLUMECOLLIDER_H__ #define __OPC_VOLUMECOLLIDER_H__ struct OPCODE_API VolumeCache { VolumeCache() : Model(null) {} ~VolumeCache() {} Container TouchedPrimitives; //!< Indices of touched primitives const BaseModel* Model; //!< Owner }; class OPCODE_API VolumeCollider : public Collider { public: // Constructor / Destructor VolumeCollider(); virtual ~VolumeCollider() = 0; // Collision report /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the number of touched primitives after a collision query. * \see GetContactStatus() * \see GetTouchedPrimitives() * \return the number of touched primitives */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbTouchedPrimitives() const { return mTouchedPrimitives ? mTouchedPrimitives->GetNbEntries() : 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Gets the list of touched primitives after a collision query. * \see GetContactStatus() * \see GetNbTouchedPrimitives() * \return the list of touched primitives (primitive indices) */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ const udword* GetTouchedPrimitives() const { return mTouchedPrimitives ? mTouchedPrimitives->GetEntries() : null; } // Stats /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of Volume-BV overlap tests after a collision query. * \see GetNbVolumePrimTests() * \return the number of Volume-BV tests performed during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbVolumeBVTests() const { return mNbVolumeBVTests; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Stats: gets the number of Volume-Triangle overlap tests after a collision query. * \see GetNbVolumeBVTests() * \return the number of Volume-Triangle tests performed during last query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// inline_ udword GetNbVolumePrimTests() const { return mNbVolumePrimTests; } // Settings /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider. * \return null if everything is ok, else a string describing the problem */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(Collider) const char* ValidateSettings(); protected: // Touched primitives Container* mTouchedPrimitives; //!< List of touched primitives // Dequantization coeffs Point mCenterCoeff; Point mExtentsCoeff; // Stats udword mNbVolumeBVTests; //!< Number of Volume-BV tests udword mNbVolumePrimTests; //!< Number of Volume-Primitive tests // Internal methods void _Dump(const AABBCollisionNode* node); void _Dump(const AABBNoLeafNode* node); void _Dump(const AABBQuantizedNode* node); void _Dump(const AABBQuantizedNoLeafNode* node); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Initializes a query */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// override(Collider) inline_ void InitQuery() { // Reset stats & contact status mNbVolumeBVTests = 0; mNbVolumePrimTests = 0; Collider::InitQuery(); } inline_ BOOL IsCacheValid(VolumeCache& cache) { // We're going to do a volume-vs-model query. if(cache.Model!=mCurrentModel) { // Cached list was for another model so we can't keep it // Keep track of new owner and reset cache cache.Model = mCurrentModel; return FALSE; } else { // Same models, no problem return TRUE; } } }; #endif // __OPC_VOLUMECOLLIDER_H__ ode-0.14/OPCODE/Opcode.cpp0000644000000000000000000000405112635011627013574 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Main file for Opcode.dll. * \file Opcode.cpp * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Finding a good name is difficult! Here's the draft for this lib.... Spooky, uh? VOID? Very Optimized Interference Detection ZOID? Zappy's Optimized Interference Detection CID? Custom/Clever Interference Detection AID / ACID! Accurate Interference Detection QUID? Quick Interference Detection RIDE? Realtime Interference DEtection WIDE? Wicked Interference DEtection (....) GUID! KID ! k-dop interference detection :) OPCODE! OPtimized COllision DEtection */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Precompiled Header #include "Stdafx.h" using namespace Opcode; bool Opcode::InitOpcode() { //Log("// Initializing OPCODE\n\n"); // LogAPIInfo(); return true; } bool Opcode::CloseOpcode() { //Log("// Closing OPCODE\n\n"); return true; } #ifdef ICE_MAIN void ModuleAttach(HINSTANCE hinstance) { } void ModuleDetach() { } #endif ode-0.14/OPCODE/Opcode.dsp0000644000000000000000000002151612635011627013605 0ustar rootroot# Microsoft Developer Studio Project File - Name="OPCODE" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Static Library" 0x0104 CFG=OPCODE - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "Opcode.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "Opcode.mak" CFG="OPCODE - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "OPCODE - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "OPCODE - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName ""$/TR4/ODE/VC6", WNKAAAAA" # PROP Scc_LocalPath "..\vc6" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "OPCODE - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD CPP /nologo /G6 /Zp4 /MD /O2 /Ob0 /I ".\\" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "ICE_NO_DLL" /FD /c # SUBTRACT CPP /Fr /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo /out:"..\lib\OPCODE.lib" !ELSEIF "$(CFG)" == "OPCODE - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD CPP /nologo /G6 /Zp4 /MDd /Gm /ZI /Od /I ".\\" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "ICE_NO_DLL" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo /out:"..\lib\OPCODE_D.lib" !ENDIF # Begin Target # Name "OPCODE - Win32 Release" # Name "OPCODE - Win32 Debug" # Begin Source File SOURCE=.\Ice\IceAABB.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceAABB.h # End Source File # Begin Source File SOURCE=.\Ice\IceAxes.h # End Source File # Begin Source File SOURCE=.\Ice\IceBoundingSphere.h # End Source File # Begin Source File SOURCE=.\Ice\IceContainer.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceContainer.h # End Source File # Begin Source File SOURCE=.\Ice\IceFPU.h # End Source File # Begin Source File SOURCE=.\Ice\IceHPoint.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceHPoint.h # End Source File # Begin Source File SOURCE=.\Ice\IceIndexedTriangle.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceIndexedTriangle.h # End Source File # Begin Source File SOURCE=.\Ice\IceLSS.h # End Source File # Begin Source File SOURCE=.\Ice\IceMatrix3x3.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceMatrix3x3.h # End Source File # Begin Source File SOURCE=.\Ice\IceMatrix4x4.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceMatrix4x4.h # End Source File # Begin Source File SOURCE=.\Ice\IceMemoryMacros.h # End Source File # Begin Source File SOURCE=.\Ice\IceOBB.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceOBB.h # End Source File # Begin Source File SOURCE=.\Ice\IcePairs.h # End Source File # Begin Source File SOURCE=.\Ice\IcePlane.cpp # End Source File # Begin Source File SOURCE=.\Ice\IcePlane.h # End Source File # Begin Source File SOURCE=.\Ice\IcePoint.cpp # End Source File # Begin Source File SOURCE=.\Ice\IcePoint.h # End Source File # Begin Source File SOURCE=.\Ice\IcePreprocessor.h # End Source File # Begin Source File SOURCE=.\Ice\IceRandom.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceRandom.h # End Source File # Begin Source File SOURCE=.\Ice\IceRay.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceRay.h # End Source File # Begin Source File SOURCE=.\Ice\IceRevisitedRadix.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceRevisitedRadix.h # End Source File # Begin Source File SOURCE=.\Ice\IceSegment.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceSegment.h # End Source File # Begin Source File SOURCE=.\Ice\IceTriangle.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceTriangle.h # End Source File # Begin Source File SOURCE=.\Ice\IceTrilist.h # End Source File # Begin Source File SOURCE=.\Ice\IceTypes.h # End Source File # Begin Source File SOURCE=.\Ice\IceUtils.cpp # End Source File # Begin Source File SOURCE=.\Ice\IceUtils.h # End Source File # Begin Source File SOURCE=.\OPC_AABBCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_AABBCollider.h # End Source File # Begin Source File SOURCE=.\OPC_AABBTree.cpp # End Source File # Begin Source File SOURCE=.\OPC_AABBTree.h # End Source File # Begin Source File SOURCE=.\OPC_BaseModel.cpp # End Source File # Begin Source File SOURCE=.\OPC_BaseModel.h # End Source File # Begin Source File SOURCE=.\OPC_BoxBoxOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_BoxPruning.cpp # End Source File # Begin Source File SOURCE=.\OPC_BoxPruning.h # End Source File # Begin Source File SOURCE=.\OPC_Collider.cpp # End Source File # Begin Source File SOURCE=.\OPC_Collider.h # End Source File # Begin Source File SOURCE=.\OPC_Common.cpp # End Source File # Begin Source File SOURCE=.\OPC_Common.h # End Source File # Begin Source File SOURCE=.\OPC_HybridModel.cpp # End Source File # Begin Source File SOURCE=.\OPC_HybridModel.h # End Source File # Begin Source File SOURCE=.\OPC_IceHook.h # End Source File # Begin Source File SOURCE=.\OPC_LSSAABBOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_LSSCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_LSSCollider.h # End Source File # Begin Source File SOURCE=.\OPC_LSSTriOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_MeshInterface.cpp # End Source File # Begin Source File SOURCE=.\OPC_MeshInterface.h # End Source File # Begin Source File SOURCE=.\OPC_Model.cpp # End Source File # Begin Source File SOURCE=.\OPC_Model.h # End Source File # Begin Source File SOURCE=.\OPC_OBBCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_OBBCollider.h # End Source File # Begin Source File SOURCE=.\OPC_OptimizedTree.cpp # End Source File # Begin Source File SOURCE=.\OPC_OptimizedTree.h # End Source File # Begin Source File SOURCE=.\OPC_Picking.cpp # End Source File # Begin Source File SOURCE=.\OPC_Picking.h # End Source File # Begin Source File SOURCE=.\OPC_PlanesAABBOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_PlanesCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_PlanesCollider.h # End Source File # Begin Source File SOURCE=.\OPC_PlanesTriOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_RayAABBOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_RayCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_RayCollider.h # End Source File # Begin Source File SOURCE=.\OPC_RayTriOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_Settings.h # End Source File # Begin Source File SOURCE=.\OPC_SphereAABBOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_SphereCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_SphereCollider.h # End Source File # Begin Source File SOURCE=.\OPC_SphereTriOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_SweepAndPrune.cpp # End Source File # Begin Source File SOURCE=.\OPC_SweepAndPrune.h # End Source File # Begin Source File SOURCE=.\OPC_TreeBuilders.cpp # End Source File # Begin Source File SOURCE=.\OPC_TreeBuilders.h # End Source File # Begin Source File SOURCE=.\OPC_TreeCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_TreeCollider.h # End Source File # Begin Source File SOURCE=.\OPC_TriBoxOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_TriTriOverlap.h # End Source File # Begin Source File SOURCE=.\OPC_VolumeCollider.cpp # End Source File # Begin Source File SOURCE=.\OPC_VolumeCollider.h # End Source File # Begin Source File SOURCE=.\Opcode.cpp # End Source File # Begin Source File SOURCE=.\Opcode.h # End Source File # Begin Source File SOURCE=.\StdAfx.cpp # End Source File # Begin Source File SOURCE=.\StdAfx.h # End Source File # End Target # End Project ode-0.14/OPCODE/Opcode.dsw0000644000000000000000000000077212635011627013615 0ustar rootrootMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "OPCODE"=.\Opcode.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### ode-0.14/OPCODE/Opcode.h0000644000000000000000000001001512635011627013236 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * Main file for Opcode.dll. * \file Opcode.h * \author Pierre Terdiman * \date March, 20, 2001 */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Include Guard #ifndef __OPCODE_H__ #define __OPCODE_H__ // stddef.h and stdarg.h must be included before Opcode headers // as they latermay not compile being not able to find types in std:: #include #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Things to help us compile on non-windows platforms #if defined(__APPLE__) || defined(__MACOSX__) #if __APPLE_CC__ < 1495 #define sqrtf sqrt #define sinf sin #define cosf cos #define acosf acos #define asinf asin #endif #endif #ifndef _MSC_VER #ifndef __int64 #define __int64 long long int #endif #ifndef __stdcall /* this is defined in MinGW and CygWin, so avoid the warning */ #define __stdcall /* */ #endif #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Compilation messages #ifdef _MSC_VER #if defined(OPCODE_EXPORTS) // #pragma message("Compiling OPCODE") #elif !defined(OPCODE_EXPORTS) // #pragma message("Using OPCODE") /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Automatic linking #ifndef BAN_OPCODE_AUTOLINK #ifdef _DEBUG //#pragma comment(lib, "Opcode_D.lib") #else //#pragma comment(lib, "Opcode.lib") #endif #endif #endif #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Preprocessor #ifndef ICE_NO_DLL #ifdef OPCODE_EXPORTS #define OPCODE_API// __declspec(dllexport) #else #define OPCODE_API// __declspec(dllimport) #endif #else #define OPCODE_API #endif #include "OPC_Settings.h" #include "OPC_IceHook.h" namespace Opcode { // Bulk-of-the-work #include "OPC_Common.h" #include "OPC_MeshInterface.h" // Builders #include "OPC_TreeBuilders.h" // Trees #include "OPC_AABBTree.h" #include "OPC_OptimizedTree.h" // Models #include "OPC_BaseModel.h" #include "OPC_Model.h" #include "OPC_HybridModel.h" // Colliders #include "OPC_Collider.h" #include "OPC_VolumeCollider.h" #include "OPC_TreeCollider.h" #include "OPC_RayCollider.h" #include "OPC_SphereCollider.h" #include "OPC_OBBCollider.h" #include "OPC_AABBCollider.h" #include "OPC_LSSCollider.h" #include "OPC_PlanesCollider.h" // Usages #include "OPC_Picking.h" FUNCTION OPCODE_API bool InitOpcode(); FUNCTION OPCODE_API bool CloseOpcode(); } #endif // __OPCODE_H__ ode-0.14/OPCODE/README-ODE.txt0000644000000000000000000000113512635011627013762 0ustar rootroot This is a copy of the OPCODE collision detection library by Pierre Terdiman. See http://www.codercorner.com/Opcode.htm for more information, and read the ReadMe.txt in this directory. If you want to use the TriList (triangle mesh) geometry class in ODE, the OPCODE library must be compiled. If you are using the autotools support to compile ODE, you just have to specify --with-trimesh=opcode when calling ./configure. This code was originally written for and compiled on windows, but it has been ported so that it should compile under unix/gcc too. Your mileage may vary. Russ Smith, April 12 2005. ode-0.14/OPCODE/ReadMe.txt0000644000000000000000000002061612635011627013562 0ustar rootroot OPCODE distribution 1.3 (june 2003) ----------------------- New in Opcode 1.3: - fixed the divide by 0 bug that was happening when all centers where located on a coordinate axis (thanks to Jorrit T) - linearized "complete" vanilla AABB trees - ANSI-compliant "for" loops (for the ones porting it to Linux...) - callbacks & pointers moved to mesh interface - support for triangle & vertex strides - optimized the sphere-triangle overlap code a bit - dynamic trees (refit) - more builders - ValidateSubdivision in builders - LSS collider - primitive-bv tests can now be skipped in most volume queries - temporal coherence now also works for airborne objects - temporal coherence completed for boxes / all contacts, LSS, etc - ray-collider now uses a callback - some common "usages" have been introduced (only picking for now) - SPLIT_COMPLETE removed (now implicitely using mLimit = 1) - hybrid collision models - sweep-and-prune code added, moved from my old Z-Collide lib - it now works with meshes made of only 1 triangle (except in mesh-mesh case!) Disclaimer: - I forced myself to actually *do* the release today no matter what. Else it would never have been done. That's why the code may not be very polished. I also removed a *lot* of things (more usages, distance queries, etc...) that weren't ready for prime-time (or that were linked to too many of my supporting libs) - Some comments may also be obsolete here and there. The old User Manual for Opcode 1.2 may not fit version 1.3 either, since there's a new "mesh interface" to support strides, etc. - Everything in the "Ice" directory has been hacked out of my engine and edited until everything compiled. Don't expect anything out there to be cute or something. In particular, some CPP files are not even included when not needed, so you can expect some linker errors if you try messing around with them... Otherwise, it should be just like previous version, only better. In particular, hybrid models can be very memory-friendly (sometimes using like 10 times less ram than the best trees from version 1.2). The possible speed hit is often invisible (if it even exists), especially using temporal coherence in "all contacts" mode. (Admittedly, this depends on your particular usage pattern / what you do on collided triangles). The sweep-and-prune code is similar to the "vanilla" version found in V-Collide (but that one's better IMHO...) The simple "radix" version is often just as good, see for yourself. OPCODE distribution 1.2 (august 2002) ----------------------- New in Opcode 1.2: - new VolumeCollider base class - simplified callback setup - you can now use callbacks or pointers (setup at compile time) - destination array not needed anymore in the RayCollider (faster in-out tests) - renamed classes: AABBRayCollider => RayCollider, AABBSphereCollider => SphereCollider - the sphere query now only returns a list of faces (extra info discarded). On the other hand it's a lot faster. - OBB, AABB and planes queries. Original OBB and AABB queries contributed by Erwin de Vries. - cosmetic changes in OPC_BoxBoxOverlap.h contributed by Gottfried Chen - some inlining problems fixed - faster ray-mesh tests using the separating axis theorem - new split value in AABB tree construction (contributed by Igor Kravtchenko). Provides faster queries most of the time. - improved temporal coherence for sphere & AABB queries (works in "All contacts" mode) Notes: - Everything in the "Ice code" directory (in VC++) is basically copy-pasted from my engine, with a lot of code removed until there was no link error anymore. Don't expect those files to be cute or anything, they've never been meant to be released and they're often updated/modified/messy. - Some experimental features have been removed as well. Else I would never have released the 1.2... - Not as polished/optimal as I would like it to be, but that's life. I promised myself to release it before october 2002 (one YEAR later ?!).... That's the only reason why it's there. - Some people reported ColDet was faster. Uh, come on. They were using Opcode in "All contacts" mode whereas ColDet was doing "first contact"... OPCODE distribution 1.1 (october 2001) ----------------------- New in Opcode 1.1: - stabbing queries - sphere queries - abtract base class for colliders - settings validation methods - compilation flags now grouped in OPC_Settings.h - smaller files, new VC++ virtual dirs (cleaner) Notes: - "override(baseclass)" is a personal cosmetic thing. It's the same as "virtual", but provides more info. - I code in 1600*1200, so some lines may look a bit long.. - This version is not as polished as the previous one due to lack of time. The stabbing & sphere queries can still be optimized: for example by trying other atomic overlap tests. I'm using my first ray-AABB code, but the newer one seems better. Tim Schrder's one is good as well. See: www.codercorner.com/RayAABB.cpp - The trees can easily be compressed even more, I save this for later (lack of time, lack of time!) - I removed various tests before releasing this one: - a separation line, a.k.a. "front" in QuickCD, because gains were unclear - distance queries in a PQP style, because it was way too slow - support for deformable models, too slow as well - You can easily use Opcode to do your player-vs-world collision detection, in a Nettle/Telemachos way. If someone out there wants to donate some art / level for the cause, I'd be glad to release a demo. (current demo uses copyrighted art I'm not allowed to spread) - Sorry for the lack of real docs and/or solid examples. I just don't have enough time. OPCODE distribution 1.0 (march 2001) ----------------------- - First release =============================================================================== WHAT ? OPCODE means OPtimized COllision DEtection. So this is a collision detection package similar to RAPID. Here's a quick list of features: - C++ interface, developed for Windows systems using VC++ 6.0 - Works on arbitrary meshes (convex or non-convex), even polygon soups - Current implementation uses AABB-trees - Introduces Primitive-BV overlap tests during recursive collision queries (whereas standard libraries only rely on Primitive-Primitive and BV-BV tests) - Introduces no-leaf trees, i.e. collision trees whose leaf nodes have been removed - Supports collision queries on quantized trees (decompressed on-the-fly) - Supports "first contact" or "all contacts" modes ( la RAPID) - Uses temporal coherence for "first contact" mode (~10 to 20 times faster, useful in rigid body simulation during bisection) - Memory footprint is 7.2 times smaller than RAPID's one, which is ideal for console games with limited ram (actually, if you use the unmodified RAPID code using double precision, it's more like 13 times smaller...) - And yet it often runs faster than RAPID (according to RDTSC, sometimes more than 5 times faster when objects are deeply overlapping) - Performance is usually close to RAPID's one in close-proximity situations - Stabbing, planes & volume queries (sphere, AABB, OBB, LSS) - Sweep-and-prune - Now works with deformable meshes - Hybrid trees What it can be used for: - standard mesh-mesh collision detection (similar to RAPID, SOLID, QuickCD, PQP, ColDet...) - N-body collisions (similar to V-Collide) - camera-vs-world collisions (similar to Telemachos/Paul Nettle/Stan Melax articles) - shadow feelers to speed up lightmap computations - in-out tests to speed up voxelization processes - picking - rigid body simulation - view frustum culling - etc WHY ? - Because RAPID uses too many bytes. - Because the idea was nice... WHEN ? It's been coded in march 2001 following a thread on the GD-Algorithms list. GDAlgorithms-list mailing list GDAlgorithms-list@lists.sourceforge.net http://lists.sourceforge.net/lists/listinfo/gdalgorithms-list WHO ? Pierre Terdiman June, 1, 2003 p.terdiman@wanadoo.fr p.terdiman@codercorner.com http://www.codercorner.com http://www.codercorner.com/Opcode.htm ode-0.14/OPCODE/StdAfx.cpp0000644000000000000000000000110212635011627013546 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //#define ICE_MAIN #include "Stdafx.h" ode-0.14/OPCODE/Stdafx.h0000644000000000000000000000207212635011627013262 0ustar rootroot/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* * OPCODE - Optimized Collision Detection * Copyright (C) 2001 Pierre Terdiman * Homepage: http://www.codercorner.com/Opcode.htm */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if !defined(AFX_STDAFX_H__EFB95044_1D31_11D5_8B0F_0050BAC83302__INCLUDED_) #define AFX_STDAFX_H__EFB95044_1D31_11D5_8B0F_0050BAC83302__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // Insert your headers here #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include "Opcode.h" //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_STDAFX_H__EFB95044_1D31_11D5_8B0F_0050BAC83302__INCLUDED_) ode-0.14/OPCODE/TemporalCoherence.txt0000644000000000000000000000236112635011627016021 0ustar rootroot > Hi John, > > I know I'll forget to tell you this if I don't write it right now.... > > >(2) How is the receiving geometry for the shadow decided? > > I wrote about an LSS-test but actually performing a new VFC test (from the > light's view) is the same. In both cases, here's a trick to take advantage > of temporal coherence : test the world against a slightly larger than > necessary LSS or frustum. Keep the list of touched surfaces. Then next > frame, if the new volume is still contained within the previous one used for > the query, you can reuse the same list immediately. Actually it's a bit > similar to what you did in your sphere-tree, I think. Anyway, now the O(log > N) VFC is O(1) for some frames. It's not worth it for the "real" VFC, but > when you have N virtual frustum to test to drop N shadows, that's another > story. > > Two downsides: > - You need more ram to keep track of one list of meshes / shadow, but > usually it's not a lot. > - By using a larger volume for the query you possibly touch more > faces/surfaces, which will be rendered in the shadow pass. Usually it's not > a problem either since rendering is simply faster than geometric queries > those days. But of course, "your mileage may vary". > > Happy new year ! > > Pierre ode-0.14/README.md0000644000000000000000000000247612635011627012176 0ustar rootrootThe Open Dynamics Engine (ODE) ============================== ![ODE logo](http://bitbucket.org/odedevs/ode/raw/default/web/ODElogo.png) Copyright (C) 2001-2007 Russell L. Smith. ODE is a free, industrial quality library for simulating articulated rigid body dynamics - for example ground vehicles, legged creatures, and moving objects in VR environments. It is fast, flexible, robust and platform independent, with advanced joints, contact with friction, and built-in collision detection. This library is free software; you can redistribute it and/or modify it under the terms of EITHER: * The GNU Lesser General Public License version 2.1 or any later. * The BSD-style License. See the [COPYING](http://bitbucket.org/odedevs/ode/raw/default/COPYING) file for more details. * Installation instructions are in the [INSTALL.txt](http://bitbucket.org/odedevs/ode/raw/default/INSTALL.txt) file. * The ODE web pages are at [ode.org](http://www.ode.org/). * An online manual is at [the Wiki](http://ode-wiki.org/wiki/index.php?title=Manual). * API documentation is in the file ode/docs/index.html, or you can view it on the web at [opende.sf.net/docs/index.html](http://opende.sf.net/docs/index.html). [![Build Status](https://drone.io/bitbucket.org/odedevs/ode/status.png)](https://drone.io/bitbucket.org/odedevs/ode/latest)ode-0.14/bindings/0000775000000000000000000000000012635012023012474 5ustar rootrootode-0.14/bindings/python/0000775000000000000000000000000012635012023014015 5ustar rootrootode-0.14/bindings/python/INSTALL.txt0000644000000000000000000000342512635011627015677 0ustar rootroot1. REQUIREMENTS: 1. Python 2.4 or higher (http://www.python.org/) - Tested with Python 2.7 (2.6 on earlier builds) 2. Cython 0.14.1** or higher (http://cython.org/) - Tested with Cython 0.15 (0.14.1 on earlier builds) 3. ODE shared*** library (or static with -fPIC) - See the notes on building ODE below. 4. pkg-config (http://www.freedesktop.org/wiki/Software/pkg-config) - Windows executable (and GLib dependency) can be downloaded from http://www.gtk.org/download/win32.php - If you used premake to configure ODE, you may need to create an ode.pc file in your PKG_CONFIG_PATH manually. See /ode.pc.in 2. BUILDING ODE On certain systems (*nix) there is a requirement that a shared library (such as the python module) contains only position-independent code (PIC). In those cases, ODE needs to be either compiled as a shared library too (--enable-shared), or as a static library with PIC (-fPIC). Once ODE is built and installed in your desired destination, proceed with building the wrapper. 3a. BUILDING WITH Visual Studio (Windows) python setup.py build_ext 3b. BUILDING WITH MINGW (Windows) python setup.py build_ext -c mingw32 3c. BUILDING WITH GCC/G++ (Linux, OS X, etc.) python setup.py build_ext 4. INSTALLATION 4a. For system-wide installation (needs administrator privileges): python setup.py install 4b. For user installation: python setup.py install --user 5. DEMOS and DOCUMENTATION Try running the tutorials in the 'demos' directory. The tutorials were taken from the PyODE website (http://pyode.sourceforge.net/). For usage documentation, please refer to the PyODE API documentation at http://pyode.sourceforge.net/api-1.2.0/index.html. ode-0.14/bindings/python/TODO.txt0000644000000000000000000000106712635011627015336 0ustar rootrootCODE: * (setup.py) add package information (version, authors, etc.) * (setup.py) add 'install' action * (setup.py) add configurable ODE DLL (currently hard-coded to default single precision) * (ode.pxd) clean up, add more comments * (ode.pyx) refactor for a more Pythonic implementation (e.g. replace getters and setters with properties)? * (?) Add option to build bindings in ODE's makefiles DOCS: * Update and include API docs from PyODE * Adapt and include PyODE tutorials/demos * Update license text in ode.pxd and ode.pyx ode-0.14/bindings/python/demos/0000775000000000000000000000000012635012023015124 5ustar rootrootode-0.14/bindings/python/demos/tutorial1.py0000755000000000000000000000232212635011627017433 0ustar rootroot#!/usr/bin/env python # http://pyode.sourceforge.net/tutorials/tutorial1.html # pyODE example 1: Getting started # modified by Gideon Klompje (removed literals and using # 'ode.Mass.setSphereTotal' instead of 'ode.Mass.setSphere') import ode # Simulation constants GRAVITY = (0, -9.81, 0) SPHERE_RADIUS = 0.05 SPHERE_MASS = 1.0 SPHERE_START_POS = (0, 2, 0) SPHERE_FORCE = (0, 200, 0) # Initial force to apply to the sphere TIME_STEP = 0.04 TIME_STOP = 2.0 # When to stop the simulation # Create a world object world = ode.World() world.setGravity(GRAVITY) # Create a spherical body inside the world body = ode.Body(world) mass = ode.Mass() mass.setSphereTotal(SPHERE_MASS, SPHERE_RADIUS) body.setMass(mass) body.setPosition(SPHERE_START_POS) body.addForce(SPHERE_FORCE) # Do the simulation... if __name__ == "__main__": total_time = 0.0 while total_time < TIME_STOP: # output the body's position and velocity x, y, z = body.getPosition() u, v, w = body.getLinearVel() print "%1.2fsec: pos=(%6.3f, %6.3f, %6.3f) vel=(%6.3f, %6.3f, %6.3f)" % \ (total_time, x, y, z, u, v, w) # advance the simulation world.step(TIME_STEP) total_time += TIME_STEP ode-0.14/bindings/python/demos/tutorial2.py0000755000000000000000000000660612635011627017445 0ustar rootroot#!/usr/bin/env python # http://pyode.sourceforge.net/tutorials/tutorial2.html # pyODE example 2: Connecting bodies with joints # modified by Gideon Klompje (removed literals and using # 'ode.Mass.setSphereTotal' instead of 'ode.Mass.setSphere') import ode import pygame from pygame.locals import QUIT, KEYDOWN # Constants WINDOW_RESOLUTION = (640, 480) DRAW_SCALE = WINDOW_RESOLUTION[0] / 5 """Factor to multiply physical coordinates by to obtain screen size in pixels""" DRAW_OFFSET = (WINDOW_RESOLUTION[0] / 2, 50) """Screen coordinates (in pixels) that map to the physical origin (0, 0, 0)""" BACKGROUND_COLOR = (255, 255, 255) GRAVITY = (0, -9.81, 0) SPHERE1_POSITION = (1, 0, 0) SPHERE1_MASS = 1 SPHERE1_RADIUS = 0.15 SPHERE1_COLOR = (55, 0, 200) SPHERE2_POSITION = (2, 0, 0) SPHERE2_MASS = 1 SPHERE2_RADIUS = 0.15 SPHERE2_COLOR = (55, 0, 200) JOINT1_ANCHOR = (0, 0, 0) JOINT1_COLOR = (200, 0, 55) JOINT1_WIDTH = 2 """Width of the line (in pixels) representing the joint""" JOINT2_ANCHOR = SPHERE1_POSITION JOINT2_COLOR = (200, 0, 55) JOINT2_WIDTH = 2 """Width of the line (in pixels) representing the joint""" TIME_STEP = 0.04 # Utility functions def coord(x, y, integer=False): """ Convert world coordinates to pixel coordinates. Setting 'integer' to True will return integer coordinates. """ xs = (DRAW_OFFSET[0] + DRAW_SCALE*x) ys = (DRAW_OFFSET[1] - DRAW_SCALE*y) if integer: return int(round(xs)), int(round(ys)) else: return xs, ys # Initialize pygame pygame.init() # Open a display screen = pygame.display.set_mode(WINDOW_RESOLUTION) # Create a world object world = ode.World() world.setGravity(GRAVITY) # Create two bodies body1 = ode.Body(world) M = ode.Mass() M.setSphereTotal(SPHERE1_MASS, SPHERE1_RADIUS) body1.setMass(M) body1.setPosition(SPHERE1_POSITION) body2 = ode.Body(world) M = ode.Mass() M.setSphereTotal(SPHERE2_MASS, SPHERE2_RADIUS) body2.setMass(M) body2.setPosition(SPHERE2_POSITION) # Connect body1 with the static environment j1 = ode.BallJoint(world) j1.attach(body1, ode.environment) j1.setAnchor(JOINT1_ANCHOR) # Connect body2 with body1 j2 = ode.BallJoint(world) j2.attach(body1, body2) j2.setAnchor(JOINT2_ANCHOR) # Simulation loop... if __name__ == "__main__": fps = 1.0 / TIME_STEP clk = pygame.time.Clock() sph1_rad = int(DRAW_SCALE * SPHERE1_RADIUS) sph2_rad = int(DRAW_SCALE * SPHERE2_RADIUS) loopFlag = True while loopFlag: for e in pygame.event.get(): if e.type==QUIT: loopFlag=False if e.type==KEYDOWN: loopFlag=False # Clear the screen screen.fill(BACKGROUND_COLOR) # Draw the two bodies and the lines representing the joints x1, y1, z1 = body1.getPosition() x2, y2, z2 = body2.getPosition() xj1, yj1, zj1 = j1.getAnchor() xj2, yj2, zj2 = j2.getAnchor() pygame.draw.line(screen, JOINT1_COLOR, coord(xj1, yj1), coord(x1, y1), JOINT1_WIDTH) pygame.draw.line(screen, JOINT2_COLOR, coord(xj2, yj2), coord(x2, y2), JOINT2_WIDTH) pygame.draw.circle(screen, SPHERE1_COLOR, coord(x1, y1, integer=True), sph1_rad, 0) pygame.draw.circle(screen, SPHERE2_COLOR, coord(x2, y2, integer=True), sph2_rad, 0) pygame.display.flip() # Next simulation step world.step(TIME_STEP) # Try to keep the specified framerate clk.tick(fps) ode-0.14/bindings/python/demos/tutorial3.py0000644000000000000000000001405412635011627017437 0ustar rootroot#!/usr/bin/env python # http://pyode.sourceforge.net/tutorials/tutorial3.html # pyODE example 3: Collision detection # Originally by Matthias Baas. # Updated by Pierre Gay to work without pygame or cgkit. import sys, os, random, time from math import * from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * import ode # geometric utility functions def scalp (vec, scal): vec[0] *= scal vec[1] *= scal vec[2] *= scal def length (vec): return sqrt (vec[0]**2 + vec[1]**2 + vec[2]**2) # prepare_GL def prepare_GL(): """Prepare drawing. """ # Viewport glViewport(0,0,640,480) # Initialize glClearColor(0.8,0.8,0.9,0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST) glDisable(GL_LIGHTING) glEnable(GL_LIGHTING) glEnable(GL_NORMALIZE) glShadeModel(GL_FLAT) # Projection glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective (45,1.3333,0.2,20) # Initialize ModelView matrix glMatrixMode(GL_MODELVIEW) glLoadIdentity() # Light source glLightfv(GL_LIGHT0,GL_POSITION,[0,0,1,0]) glLightfv(GL_LIGHT0,GL_DIFFUSE,[1,1,1,1]) glLightfv(GL_LIGHT0,GL_SPECULAR,[1,1,1,1]) glEnable(GL_LIGHT0) # View transformation gluLookAt (2.4, 3.6, 4.8, 0.5, 0.5, 0, 0, 1, 0) # draw_body def draw_body(body): """Draw an ODE body. """ x,y,z = body.getPosition() R = body.getRotation() rot = [R[0], R[3], R[6], 0., R[1], R[4], R[7], 0., R[2], R[5], R[8], 0., x, y, z, 1.0] glPushMatrix() glMultMatrixd(rot) if body.shape=="box": sx,sy,sz = body.boxsize glScalef(sx, sy, sz) glutSolidCube(1) glPopMatrix() # create_box def create_box(world, space, density, lx, ly, lz): """Create a box body and its corresponding geom.""" # Create body body = ode.Body(world) M = ode.Mass() M.setBox(density, lx, ly, lz) body.setMass(M) # Set parameters for drawing the body body.shape = "box" body.boxsize = (lx, ly, lz) # Create a box geom for collision detection geom = ode.GeomBox(space, lengths=body.boxsize) geom.setBody(body) return body, geom # drop_object def drop_object(): """Drop an object into the scene.""" global bodies, geom, counter, objcount body, geom = create_box(world, space, 1000, 1.0,0.2,0.2) body.setPosition( (random.gauss(0,0.1),3.0,random.gauss(0,0.1)) ) theta = random.uniform(0,2*pi) ct = cos (theta) st = sin (theta) body.setRotation([ct, 0., -st, 0., 1., 0., st, 0., ct]) bodies.append(body) geoms.append(geom) counter=0 objcount+=1 # explosion def explosion(): """Simulate an explosion. Every object is pushed away from the origin. The force is dependent on the objects distance from the origin. """ global bodies for b in bodies: l=b.getPosition () d = length (l) a = max(0, 40000*(1.0-0.2*d*d)) l = [l[0] / 4, l[1], l[2] /4] scalp (l, a / length (l)) b.addForce(l) # pull def pull(): """Pull the objects back to the origin. Every object will be pulled back to the origin. Every couple of frames there'll be a thrust upwards so that the objects won't stick to the ground all the time. """ global bodies, counter for b in bodies: l=list (b.getPosition ()) scalp (l, -1000 / length (l)) b.addForce(l) if counter%60==0: b.addForce((0,10000,0)) # Collision callback def near_callback(args, geom1, geom2): """Callback function for the collide() method. This function checks if the given geoms do collide and creates contact joints if they do. """ # Check if the objects do collide contacts = ode.collide(geom1, geom2) # Create contact joints world,contactgroup = args for c in contacts: c.setBounce(0.2) c.setMu(5000) j = ode.ContactJoint(world, contactgroup, c) j.attach(geom1.getBody(), geom2.getBody()) ###################################################################### # Initialize Glut glutInit ([]) # Open a window glutInitDisplayMode (GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE) x = 0 y = 0 width = 640 height = 480 glutInitWindowPosition (x, y); glutInitWindowSize (width, height); glutCreateWindow ("testode") # Create a world object world = ode.World() world.setGravity( (0,-9.81,0) ) world.setERP(0.8) world.setCFM(1E-5) # Create a space object space = ode.Space() # Create a plane geom which prevent the objects from falling forever floor = ode.GeomPlane(space, (0,1,0), 0) # A list with ODE bodies bodies = [] # The geoms for each of the bodies geoms = [] # A joint group for the contact joints that are generated whenever # two bodies collide contactgroup = ode.JointGroup() # Some variables used inside the simulation loop fps = 50 dt = 1.0/fps running = True state = 0 counter = 0 objcount = 0 lasttime = time.time() # keyboard callback def _keyfunc (c, x, y): sys.exit (0) glutKeyboardFunc (_keyfunc) # draw callback def _drawfunc (): # Draw the scene prepare_GL() for b in bodies: draw_body(b) glutSwapBuffers () glutDisplayFunc (_drawfunc) # idle callback def _idlefunc (): global counter, state, lasttime t = dt - (time.time() - lasttime) if (t > 0): time.sleep(t) counter += 1 if state==0: if counter==20: drop_object() if objcount==30: state=1 counter=0 # State 1: Explosion and pulling back the objects elif state==1: if counter==100: explosion() if counter>300: pull() if counter==500: counter=20 glutPostRedisplay () # Simulate n = 4 for i in range(n): # Detect collisions and create contact joints space.collide((world,contactgroup), near_callback) # Simulation step world.step(dt/n) # Remove all contact joints contactgroup.empty() lasttime = time.time() glutIdleFunc (_idlefunc) glutMainLoop () ode-0.14/bindings/python/ode.pxd0000644000000000000000000005227612635011627015324 0ustar rootroot###################################################################### # Python Open Dynamics Engine Wrapper # Copyright (C) 2004 PyODE developers (see file AUTHORS) # All rights reserved. # # This library is free software; you can redistribute it and/or # modify it under the terms of EITHER: # (1) The GNU Lesser General Public License as published by the Free # Software Foundation; either version 2.1 of the License, or (at # your option) any later version. The text of the GNU Lesser # General Public License is included with this library in the # file LICENSE. # (2) The BSD-style license that is included with this library in # the file LICENSE-BSD. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # LICENSE and LICENSE-BSD for more details. ###################################################################### cdef extern from "stdlib.h": void* malloc(long) void free(void*) cdef extern from "stdio.h": int printf(char*) # Include the basic floating point type -> dReal (either float or double) #include "_precision.pyx" cdef extern from "ode/ode.h": ctypedef double dReal # Dummy structs cdef struct dxWorld: int _dummy cdef struct dxSpace: int _dummy cdef struct dxBody: int _dummy cdef struct dxGeom: int _dummy cdef struct dxJoint: int _dummy cdef struct dxJointGroup: int _dummy cdef struct dxTriMeshData: int _dummy cdef struct dxHeightfieldData: int _dummy # Types ctypedef dxWorld* dWorldID ctypedef dxSpace* dSpaceID ctypedef dxBody* dBodyID ctypedef dxGeom* dGeomID ctypedef dxJoint* dJointID ctypedef dxJointGroup* dJointGroupID ctypedef dxTriMeshData* dTriMeshDataID ctypedef dxHeightfieldData* dHeightfieldDataID ctypedef dReal dVector3[4] ctypedef dReal dVector4[4] ctypedef dReal dMatrix3[4*3] ctypedef dReal dMatrix4[4*4] ctypedef dReal dMatrix6[8*6] ctypedef dReal dQuaternion[4] cdef extern dReal dInfinity cdef extern int dAMotorUser cdef extern int dAMotorEuler ctypedef struct dMass: dReal mass dVector4 c dMatrix3 I ctypedef struct dJointFeedback: dVector3 f1 dVector3 t1 dVector3 f2 dVector3 t2 ctypedef void dNearCallback(void* data, dGeomID o1, dGeomID o2) ctypedef dReal dHeightfieldGetHeight( void* p_user_data, int x, int z ) ctypedef struct dSurfaceParameters: int mode dReal mu dReal mu2 dReal bounce dReal bounce_vel dReal soft_erp dReal soft_cfm dReal motion1,motion2 dReal slip1,slip2 ctypedef struct dContactGeom: dVector3 pos dVector3 normal dReal depth dGeomID g1,g2 ctypedef struct dContact: dSurfaceParameters surface dContactGeom geom dVector3 fdir1 # World dWorldID dWorldCreate() void dWorldDestroy (dWorldID) void dCloseODE() void dInitODE() void dWorldSetGravity (dWorldID, dReal x, dReal y, dReal z) void dWorldGetGravity (dWorldID, dVector3 gravity) void dWorldSetERP (dWorldID, dReal erp) dReal dWorldGetERP (dWorldID) void dWorldSetCFM (dWorldID, dReal cfm) dReal dWorldGetCFM (dWorldID) void dWorldStep (dWorldID, dReal stepsize) void dWorldQuickStep (dWorldID, dReal stepsize) void dWorldSetQuickStepNumIterations (dWorldID, int num) int dWorldGetQuickStepNumIterations (dWorldID) void dWorldSetContactMaxCorrectingVel (dWorldID, dReal vel) dReal dWorldGetContactMaxCorrectingVel (dWorldID) void dWorldSetContactSurfaceLayer (dWorldID, dReal depth) dReal dWorldGetContactSurfaceLayer (dWorldID) void dWorldSetAutoDisableFlag (dWorldID, int do_auto_disable) int dWorldGetAutoDisableFlag (dWorldID) void dWorldSetAutoDisableLinearThreshold (dWorldID, dReal linear_threshold) dReal dWorldGetAutoDisableLinearThreshold (dWorldID) void dWorldSetAutoDisableAngularThreshold (dWorldID, dReal angular_threshold) dReal dWorldGetAutoDisableAngularThreshold (dWorldID) void dWorldSetAutoDisableSteps (dWorldID, int steps) int dWorldGetAutoDisableSteps (dWorldID) void dWorldSetAutoDisableTime (dWorldID, dReal time) dReal dWorldGetAutoDisableTime (dWorldID) dReal dWorldGetLinearDamping (dWorldID) void dWorldSetLinearDamping (dWorldID, dReal scale) dReal dWorldGetAngularDamping (dWorldID) void dWorldSetAngularDamping (dWorldID, dReal scale) void dWorldImpulseToForce (dWorldID, dReal stepsize, dReal ix, dReal iy, dReal iz, dVector3 force) # Body dBodyID dBodyCreate (dWorldID) void dBodyDestroy (dBodyID) void dBodySetData (dBodyID, void *data) void *dBodyGetData (dBodyID) void dBodySetPosition (dBodyID, dReal x, dReal y, dReal z) void dBodySetRotation (dBodyID, dMatrix3 R) void dBodySetQuaternion (dBodyID, dQuaternion q) void dBodySetLinearVel (dBodyID, dReal x, dReal y, dReal z) void dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z) dReal * dBodyGetPosition (dBodyID) dReal * dBodyGetRotation (dBodyID) dReal * dBodyGetQuaternion (dBodyID) dReal * dBodyGetLinearVel (dBodyID) dReal * dBodyGetAngularVel (dBodyID) void dBodySetMass (dBodyID, dMass *mass) void dBodyGetMass (dBodyID, dMass *mass) void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz) void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz) void dBodyAddRelForce (dBodyID, dReal fx, dReal fy, dReal fz) void dBodyAddRelTorque (dBodyID, dReal fx, dReal fy, dReal fz) void dBodyAddForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) void dBodyAddForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) void dBodyAddRelForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) void dBodyAddRelForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) dReal * dBodyGetForce (dBodyID) dReal * dBodyGetTorque (dBodyID) void dBodySetForce(dBodyID, dReal x, dReal y, dReal z) void dBodySetTorque(dBodyID, dReal x, dReal y, dReal z) void dBodyGetRelPointPos (dBodyID, dReal px, dReal py, dReal pz, dVector3 result) void dBodyGetRelPointVel (dBodyID, dReal px, dReal py, dReal pz, dVector3 result) void dBodyGetPointVel (dBodyID, dReal px, dReal py, dReal pz, dVector3 result) void dBodyGetPosRelPoint (dBodyID, dReal px, dReal py, dReal pz, dVector3 result) void dBodyVectorToWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result) void dBodyVectorFromWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result) void dBodySetFiniteRotationMode (dBodyID, int mode) void dBodySetFiniteRotationAxis (dBodyID, dReal x, dReal y, dReal z) int dBodyGetFiniteRotationMode (dBodyID) void dBodyGetFiniteRotationAxis (dBodyID, dVector3 result) int dBodyGetNumJoints (dBodyID b) dJointID dBodyGetJoint (dBodyID, int index) void dBodyEnable (dBodyID) void dBodyDisable (dBodyID) int dBodyIsEnabled (dBodyID) void dBodySetGravityMode (dBodyID b, int mode) int dBodyGetGravityMode (dBodyID b) void dBodySetDynamic (dBodyID) void dBodySetKinematic (dBodyID) int dBodyIsKinematic (dBodyID) void dBodySetMaxAngularSpeed (dBodyID, dReal max_speed) # Joints dJointID dJointCreateBall (dWorldID, dJointGroupID) dJointID dJointCreateHinge (dWorldID, dJointGroupID) dJointID dJointCreateSlider (dWorldID, dJointGroupID) dJointID dJointCreateContact (dWorldID, dJointGroupID, dContact *) dJointID dJointCreateUniversal (dWorldID, dJointGroupID) dJointID dJointCreateHinge2 (dWorldID, dJointGroupID) dJointID dJointCreateFixed (dWorldID, dJointGroupID) dJointID dJointCreateNull (dWorldID, dJointGroupID) dJointID dJointCreateAMotor (dWorldID, dJointGroupID) dJointID dJointCreateLMotor (dWorldID, dJointGroupID) dJointID dJointCreatePlane2D (dWorldID, dJointGroupID) void dJointDestroy (dJointID) void dJointEnable (dJointID) void dJointDisable (dJointID) int dJointIsEnabled (dJointID) dJointGroupID dJointGroupCreate (int max_size) void dJointGroupDestroy (dJointGroupID) void dJointGroupEmpty (dJointGroupID) void dJointAttach (dJointID, dBodyID body1, dBodyID body2) void dJointSetData (dJointID, void *data) void *dJointGetData (dJointID) int dJointGetType (dJointID) dBodyID dJointGetBody (dJointID, int index) void dJointSetBallAnchor (dJointID, dReal x, dReal y, dReal z) void dJointSetHingeAnchor (dJointID, dReal x, dReal y, dReal z) void dJointSetHingeAxis (dJointID, dReal x, dReal y, dReal z) void dJointSetHingeParam (dJointID, int parameter, dReal value) void dJointAddHingeTorque(dJointID joint, dReal torque) void dJointSetSliderAxis (dJointID, dReal x, dReal y, dReal z) void dJointSetSliderParam (dJointID, int parameter, dReal value) void dJointAddSliderForce(dJointID joint, dReal force) void dJointSetHinge2Anchor (dJointID, dReal x, dReal y, dReal z) void dJointSetHinge2Axis1 (dJointID, dReal x, dReal y, dReal z) void dJointSetHinge2Axis2 (dJointID, dReal x, dReal y, dReal z) void dJointSetHinge2Param (dJointID, int parameter, dReal value) void dJointAddHinge2Torques(dJointID joint, dReal torque1, dReal torque2) void dJointSetUniversalAnchor (dJointID, dReal x, dReal y, dReal z) void dJointSetUniversalAxis1 (dJointID, dReal x, dReal y, dReal z) void dJointSetUniversalAxis2 (dJointID, dReal x, dReal y, dReal z) void dJointSetUniversalParam (dJointID, int parameter, dReal value) void dJointAddUniversalTorques(dJointID joint, dReal torque1, dReal torque2) void dJointSetFixed (dJointID) void dJointSetAMotorNumAxes (dJointID, int num) void dJointSetAMotorAxis (dJointID, int anum, int rel, dReal x, dReal y, dReal z) void dJointSetAMotorAngle (dJointID, int anum, dReal angle) void dJointSetAMotorParam (dJointID, int parameter, dReal value) void dJointSetAMotorMode (dJointID, int mode) void dJointAddAMotorTorques (dJointID, dReal torque1, dReal torque2, dReal torque3) void dJointSetLMotorAxis (dJointID, int anum, int rel, dReal x, dReal y, dReal z) void dJointSetLMotorNumAxes (dJointID, int num) void dJointSetLMotorParam (dJointID, int parameter, dReal value) void dJointGetBallAnchor (dJointID, dVector3 result) void dJointGetBallAnchor2 (dJointID, dVector3 result) void dJointGetHingeAnchor (dJointID, dVector3 result) void dJointGetHingeAnchor2 (dJointID, dVector3 result) void dJointGetHingeAxis (dJointID, dVector3 result) dReal dJointGetHingeParam (dJointID, int parameter) dReal dJointGetHingeAngle (dJointID) dReal dJointGetHingeAngleRate (dJointID) dReal dJointGetSliderPosition (dJointID) dReal dJointGetSliderPositionRate (dJointID) void dJointGetSliderAxis (dJointID, dVector3 result) dReal dJointGetSliderParam (dJointID, int parameter) void dJointGetHinge2Anchor (dJointID, dVector3 result) void dJointGetHinge2Anchor2 (dJointID, dVector3 result) void dJointGetHinge2Axis1 (dJointID, dVector3 result) void dJointGetHinge2Axis2 (dJointID, dVector3 result) dReal dJointGetHinge2Param (dJointID, int parameter) dReal dJointGetHinge2Angle1 (dJointID) dReal dJointGetHinge2Angle1Rate (dJointID) dReal dJointGetHinge2Angle2Rate (dJointID) void dJointGetUniversalAnchor (dJointID, dVector3 result) void dJointGetUniversalAnchor2 (dJointID, dVector3 result) void dJointGetUniversalAxis1 (dJointID, dVector3 result) void dJointGetUniversalAxis2 (dJointID, dVector3 result) dReal dJointGetUniversalParam (dJointID, int parameter) dReal dJointGetUniversalAngle1 (dJointID) dReal dJointGetUniversalAngle2 (dJointID) dReal dJointGetUniversalAngle1Rate (dJointID) dReal dJointGetUniversalAngle2Rate (dJointID) int dJointGetAMotorNumAxes (dJointID) void dJointGetAMotorAxis (dJointID, int anum, dVector3 result) int dJointGetAMotorAxisRel (dJointID, int anum) dReal dJointGetAMotorAngle (dJointID, int anum) dReal dJointGetAMotorAngleRate (dJointID, int anum) dReal dJointGetAMotorParam (dJointID, int parameter) int dJointGetAMotorMode (dJointID) int dJointGetLMotorNumAxes (dJointID) void dJointGetLMotorAxis (dJointID, int anum, dVector3 result) dReal dJointGetLMotorParam (dJointID, int parameter) void dJointSetPlane2DXParam (dJointID, int parameter, dReal value) void dJointSetPlane2DYParam (dJointID, int parameter, dReal value) void dJointSetPlane2DAngleParam (dJointID, int parameter, dReal value) void dJointSetFeedback (dJointID, dJointFeedback *) dJointFeedback *dJointGetFeedback (dJointID) int dAreConnected (dBodyID, dBodyID) # Mass void dMassSetZero (dMass *) void dMassSetParameters (dMass *, dReal themass, dReal cgx, dReal cgy, dReal cgz, dReal I11, dReal I22, dReal I33, dReal I12, dReal I13, dReal I23) void dMassSetSphere (dMass *, dReal density, dReal radius) void dMassSetSphereTotal (dMass *, dReal total_mass, dReal radius) void dMassSetCapsule (dMass *, dReal density, int direction, dReal radius, dReal length) void dMassSetCapsuleTotal (dMass *, dReal total_mass, int direction, dReal radius, dReal length) void dMassSetCylinder (dMass *, dReal density, int direction, dReal radius, dReal length) void dMassSetCylinderTotal (dMass *, dReal total_mass, int direction, dReal radius, dReal length) void dMassSetBox (dMass *, dReal density, dReal lx, dReal ly, dReal lz) void dMassSetBoxTotal (dMass *, dReal total_mass, dReal lx, dReal ly, dReal lz) void dMassAdjust (dMass *, dReal newmass) void dMassTranslate (dMass *, dReal x, dReal y, dReal z) void dMassRotate (dMass *, dMatrix3 R) void dMassAdd (dMass *a, dMass *b) # Space # dSpaceID dSimpleSpaceCreate(int space) # dSpaceID dHashSpaceCreate(int space) dSpaceID dSimpleSpaceCreate(dSpaceID space) dSpaceID dHashSpaceCreate(dSpaceID space) dSpaceID dQuadTreeSpaceCreate (dSpaceID space, dVector3 Center, dVector3 Extents, int Depth) void dSpaceDestroy (dSpaceID) void dSpaceAdd (dSpaceID, dGeomID) void dSpaceRemove (dSpaceID, dGeomID) int dSpaceQuery (dSpaceID, dGeomID) void dSpaceCollide (dSpaceID space, void *data, dNearCallback *callback) void dSpaceCollide2 (dGeomID o1, dGeomID o2, void *data, dNearCallback *callback) void dHashSpaceSetLevels (dSpaceID space, int minlevel, int maxlevel) void dHashSpaceGetLevels (dSpaceID space, int *minlevel, int *maxlevel) void dSpaceSetCleanup (dSpaceID space, int mode) int dSpaceGetCleanup (dSpaceID space) int dSpaceGetNumGeoms (dSpaceID) dGeomID dSpaceGetGeom (dSpaceID, int i) # Geom dGeomID dCreateSphere (dSpaceID space, dReal radius) dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz) dGeomID dCreatePlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) dGeomID dCreateCapsule (dSpaceID space, dReal radius, dReal length) dGeomID dCreateCylinder (dSpaceID space, dReal radius, dReal length) dGeomID dCreateGeomGroup (dSpaceID space) void dGeomSphereSetRadius (dGeomID sphere, dReal radius) void dGeomBoxSetLengths (dGeomID box, dReal lx, dReal ly, dReal lz) void dGeomPlaneSetParams (dGeomID plane, dReal a, dReal b, dReal c, dReal d) void dGeomCapsuleSetParams (dGeomID ccylinder, dReal radius, dReal length) void dGeomCylinderSetParams (dGeomID ccylinder, dReal radius, dReal length) dReal dGeomSphereGetRadius (dGeomID sphere) void dGeomBoxGetLengths (dGeomID box, dVector3 result) void dGeomPlaneGetParams (dGeomID plane, dVector4 result) void dGeomCapsuleGetParams (dGeomID ccylinder, dReal *radius, dReal *length) void dGeomCylinderGetParams (dGeomID ccylinder, dReal *radius, dReal *length) dReal dGeomSpherePointDepth (dGeomID sphere, dReal x, dReal y, dReal z) dReal dGeomBoxPointDepth (dGeomID box, dReal x, dReal y, dReal z) dReal dGeomPlanePointDepth (dGeomID plane, dReal x, dReal y, dReal z) dReal dGeomCapsulePointDepth (dGeomID ccylinder, dReal x, dReal y, dReal z) dGeomID dCreateRay (dSpaceID space, dReal length) void dGeomRaySetLength (dGeomID ray, dReal length) dReal dGeomRayGetLength (dGeomID ray) void dGeomRaySet (dGeomID ray, dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz) void dGeomRayGet (dGeomID ray, dVector3 start, dVector3 dir) void dGeomSetData (dGeomID, void *) void *dGeomGetData (dGeomID) void dGeomSetBody (dGeomID, dBodyID) dBodyID dGeomGetBody (dGeomID) void dGeomSetPosition (dGeomID, dReal x, dReal y, dReal z) void dGeomSetRotation (dGeomID, dMatrix3 R) void dGeomSetQuaternion (dGeomID, dQuaternion) dReal * dGeomGetPosition (dGeomID) dReal * dGeomGetRotation (dGeomID) void dGeomGetQuaternion (dGeomID, dQuaternion result) void dGeomSetOffsetPosition (dGeomID, dReal x, dReal y, dReal z) void dGeomSetOffsetRotation (dGeomID, dMatrix3 R) void dGeomClearOffset (dGeomID) dReal * dGeomGetOffsetPosition (dGeomID) dReal * dGeomGetOffsetRotation (dGeomID) void dGeomDestroy (dGeomID) void dGeomGetAABB (dGeomID, dReal aabb[6]) dReal *dGeomGetSpaceAABB (dGeomID) int dGeomIsSpace (dGeomID) dSpaceID dGeomGetSpace (dGeomID) int dGeomGetClass (dGeomID) void dGeomSetCategoryBits(dGeomID, unsigned long bits) void dGeomSetCollideBits(dGeomID, unsigned long bits) unsigned long dGeomGetCategoryBits(dGeomID) unsigned long dGeomGetCollideBits(dGeomID) void dGeomEnable (dGeomID) void dGeomDisable (dGeomID) int dGeomIsEnabled (dGeomID) void dGeomGroupAdd (dGeomID group, dGeomID x) void dGeomGroupRemove (dGeomID group, dGeomID x) int dGeomGroupGetNumGeoms (dGeomID group) dGeomID dGeomGroupGetGeom (dGeomID group, int i) dGeomID dCreateGeomTransform (dSpaceID space) void dGeomTransformSetGeom (dGeomID g, dGeomID obj) dGeomID dGeomTransformGetGeom (dGeomID g) void dGeomTransformSetCleanup (dGeomID g, int mode) int dGeomTransformGetCleanup (dGeomID g) void dGeomTransformSetInfo (dGeomID g, int mode) int dGeomTransformGetInfo (dGeomID g) int dCollide (dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, int skip) # Trimesh dTriMeshDataID dGeomTriMeshDataCreate() void dGeomTriMeshDataDestroy(dTriMeshDataID g) void dGeomTriMeshDataBuildSingle1 (dTriMeshDataID g, void* Vertices, int VertexStride, int VertexCount, void* Indices, int IndexCount, int TriStride, void* Normals) void dGeomTriMeshDataBuildSimple(dTriMeshDataID g, dReal* Vertices, int VertexCount, int* Indices, int IndexCount) dGeomID dCreateTriMesh (dSpaceID space, dTriMeshDataID Data, void* Callback, void* ArrayCallback, void* RayCallback) void dGeomTriMeshSetData (dGeomID g, dTriMeshDataID Data) void dGeomTriMeshClearTCCache (dGeomID g) void dGeomTriMeshGetTriangle (dGeomID g, int Index, dVector3 *v0, dVector3 *v1, dVector3 *v2) int dGeomTriMeshGetTriangleCount (dGeomID g) void dGeomTriMeshGetPoint (dGeomID g, int Index, dReal u, dReal v, dVector3 Out) void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable) int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass) # Heightfield dHeightfieldDataID dGeomHeightfieldDataCreate() void dGeomHeightfieldDataDestroy(dHeightfieldDataID g) void dGeomHeightfieldDataBuildCallback(dHeightfieldDataID d, void* pUserData, dHeightfieldGetHeight* pCallback, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap) dGeomID dCreateHeightfield (dSpaceID space, dHeightfieldDataID data, int bPlaceable) ode-0.14/bindings/python/ode.pyx0000644000000000000000000040040112635011627015334 0ustar rootroot###################################################################### # Python Open Dynamics Engine Wrapper # Copyright (C) 2004 PyODE developers (see file AUTHORS) # All rights reserved. # # This library is free software; you can redistribute it and/or # modify it under the terms of EITHER: # (1) The GNU Lesser General Public License as published by the Free # Software Foundation; either version 2.1 of the License, or (at # your option) any later version. The text of the GNU Lesser # General Public License is included with this library in the # file LICENSE. # (2) The BSD-style license that is included with this library in # the file LICENSE-BSD. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files # LICENSE and LICENSE-BSD for more details. ###################################################################### from ode cimport * paramLoStop = 0 paramHiStop = 1 paramVel = 2 paramFMax = 3 paramFudgeFactor = 4 paramBounce = 5 paramCFM = 6 paramStopERP = 7 paramStopCFM = 8 paramSuspensionERP = 9 paramSuspensionCFM = 10 ParamLoStop = 0 ParamHiStop = 1 ParamVel = 2 ParamFMax = 3 ParamFudgeFactor = 4 ParamBounce = 5 ParamCFM = 6 ParamStopERP = 7 ParamStopCFM = 8 ParamSuspensionERP = 9 ParamSuspensionCFM = 10 ParamLoStop2 = 256 + 0 ParamHiStop2 = 256 + 1 ParamVel2 = 256 + 2 ParamFMax2 = 256 + 3 ParamFudgeFactor2 = 256 + 4 ParamBounce2 = 256 + 5 ParamCFM2 = 256 + 6 ParamStopERP2 = 256 + 7 ParamStopCFM2 = 256 + 8 ParamSuspensionERP2 = 256 + 9 ParamSuspensionCFM2 = 256 + 10 ParamLoStop3 = 512 + 0 ParamHiStop3 = 512 + 1 ParamVel3 = 512 + 2 ParamFMax3 = 512 + 3 ParamFudgeFactor3 = 512 + 4 ParamBounce3 = 512 + 5 ParamCFM3 = 512 + 6 ParamStopERP3 = 512 + 7 ParamStopCFM3 = 512 + 8 ParamSuspensionERP3 = 512 + 9 ParamSuspensionCFM3 = 512 + 10 ParamGroup = 256 ContactMu2 = 0x001 ContactFDir1 = 0x002 ContactBounce = 0x004 ContactSoftERP = 0x008 ContactSoftCFM = 0x010 ContactMotion1 = 0x020 ContactMotion2 = 0x040 ContactSlip1 = 0x080 ContactSlip2 = 0x100 ContactApprox0 = 0x0000 ContactApprox1_1 = 0x1000 ContactApprox1_2 = 0x2000 ContactApprox1 = 0x3000 AMotorUser = dAMotorUser AMotorEuler = dAMotorEuler Infinity = dInfinity import weakref _geom_c2py_lut = weakref.WeakValueDictionary() cdef class Mass: """Mass parameters of a rigid body. This class stores mass parameters of a rigid body which can be accessed through the following attributes: - mass: The total mass of the body (float) - c: The center of gravity position in body frame (3-tuple of floats) - I: The 3x3 inertia tensor in body frame (3-tuple of 3-tuples) This class wraps the dMass structure from the C API. @ivar mass: The total mass of the body @ivar c: The center of gravity position in body frame (cx, cy, cz) @ivar I: The 3x3 inertia tensor in body frame ((I11, I12, I13), (I12, I22, I23), (I13, I23, I33)) @type mass: float @type c: 3-tuple of floats @type I: 3-tuple of 3-tuples of floats """ cdef dMass _mass def __cinit__(self): dMassSetZero(&self._mass) def setZero(self): """setZero() Set all the mass parameters to zero.""" dMassSetZero(&self._mass) def setParameters(self, mass, cgx, cgy, cgz, I11, I22, I33, I12, I13, I23): """setParameters(mass, cgx, cgy, cgz, I11, I22, I33, I12, I13, I23) Set the mass parameters to the given values. @param mass: Total mass of the body. @param cgx: Center of gravity position in the body frame (x component). @param cgy: Center of gravity position in the body frame (y component). @param cgz: Center of gravity position in the body frame (z component). @param I11: Inertia tensor @param I22: Inertia tensor @param I33: Inertia tensor @param I12: Inertia tensor @param I13: Inertia tensor @param I23: Inertia tensor @type mass: float @type cgx: float @type cgy: float @type cgz: float @type I11: float @type I22: float @type I33: float @type I12: float @type I13: float @type I23: float """ dMassSetParameters(&self._mass, mass, cgx, cgy, cgz, I11, I22, I33, I12, I13, I23) def setSphere(self, density, radius): """setSphere(density, radius) Set the mass parameters to represent a sphere of the given radius and density, with the center of mass at (0,0,0) relative to the body. @param density: The density of the sphere @param radius: The radius of the sphere @type density: float @type radius: float """ dMassSetSphere(&self._mass, density, radius) def setSphereTotal(self, total_mass, radius): """setSphereTotal(total_mass, radius) Set the mass parameters to represent a sphere of the given radius and mass, with the center of mass at (0,0,0) relative to the body. @param total_mass: The total mass of the sphere @param radius: The radius of the sphere @type total_mass: float @type radius: float """ dMassSetSphereTotal(&self._mass, total_mass, radius) def setCapsule(self, density, direction, radius, length): """setCapsule(density, direction, radius, length) Set the mass parameters to represent a capsule of the given parameters and density, with the center of mass at (0,0,0) relative to the body. The radius of the cylinder (and the spherical cap) is radius. The length of the cylinder (not counting the spherical cap) is length. The cylinder's long axis is oriented along the body's x, y or z axis according to the value of direction (1=x, 2=y, 3=z). The first function accepts the density of the object, the second accepts its total mass. @param density: The density of the capsule @param direction: The direction of the capsule's cylinder (1=x axis, 2=y axis, 3=z axis) @param radius: The radius of the capsule's cylinder @param length: The length of the capsule's cylinder (without the caps) @type density: float @type direction: int @type radius: float @type length: float """ dMassSetCapsule(&self._mass, density, direction, radius, length) def setCapsuleTotal(self, total_mass, direction, radius, length): """setCapsuleTotal(total_mass, direction, radius, length) Set the mass parameters to represent a capsule of the given parameters and mass, with the center of mass at (0,0,0) relative to the body. The radius of the cylinder (and the spherical cap) is radius. The length of the cylinder (not counting the spherical cap) is length. The cylinder's long axis is oriented along the body's x, y or z axis according to the value of direction (1=x, 2=y, 3=z). The first function accepts the density of the object, the second accepts its total mass. @param total_mass: The total mass of the capsule @param direction: The direction of the capsule's cylinder (1=x axis, 2=y axis, 3=z axis) @param radius: The radius of the capsule's cylinder @param length: The length of the capsule's cylinder (without the caps) @type total_mass: float @type direction: int @type radius: float @type length: float """ dMassSetCapsuleTotal(&self._mass, total_mass, direction, radius, length) def setCylinder(self, density, direction, r, h): """setCylinder(density, direction, r, h) Set the mass parameters to represent a flat-ended cylinder of the given parameters and density, with the center of mass at (0,0,0) relative to the body. The radius of the cylinder is r. The length of the cylinder is h. The cylinder's long axis is oriented along the body's x, y or z axis according to the value of direction (1=x, 2=y, 3=z). @param density: The density of the cylinder @param direction: The direction of the cylinder (1=x axis, 2=y axis, 3=z axis) @param r: The radius of the cylinder @param h: The length of the cylinder @type density: float @type direction: int @type r: float @type h: float """ dMassSetCylinder(&self._mass, density, direction, r, h) def setCylinderTotal(self, total_mass, direction, r, h): """setCylinderTotal(total_mass, direction, r, h) Set the mass parameters to represent a flat-ended cylinder of the given parameters and mass, with the center of mass at (0,0,0) relative to the body. The radius of the cylinder is r. The length of the cylinder is h. The cylinder's long axis is oriented along the body's x, y or z axis according to the value of direction (1=x, 2=y, 3=z). @param total_mass: The total mass of the cylinder @param direction: The direction of the cylinder (1=x axis, 2=y axis, 3=z axis) @param r: The radius of the cylinder @param h: The length of the cylinder @type total_mass: float @type direction: int @type r: float @type h: float """ dMassSetCylinderTotal(&self._mass, total_mass, direction, r, h) def setBox(self, density, lx, ly, lz): """setBox(density, lx, ly, lz) Set the mass parameters to represent a box of the given dimensions and density, with the center of mass at (0,0,0) relative to the body. The side lengths of the box along the x, y and z axes are lx, ly and lz. @param density: The density of the box @param lx: The length along the x axis @param ly: The length along the y axis @param lz: The length along the z axis @type density: float @type lx: float @type ly: float @type lz: float """ dMassSetBox(&self._mass, density, lx, ly, lz) def setBoxTotal(self, total_mass, lx, ly, lz): """setBoxTotal(total_mass, lx, ly, lz) Set the mass parameters to represent a box of the given dimensions and mass, with the center of mass at (0,0,0) relative to the body. The side lengths of the box along the x, y and z axes are lx, ly and lz. @param total_mass: The total mass of the box @param lx: The length along the x axis @param ly: The length along the y axis @param lz: The length along the z axis @type total_mass: float @type lx: float @type ly: float @type lz: float """ dMassSetBoxTotal(&self._mass, total_mass, lx, ly, lz) def adjust(self, newmass): """adjust(newmass) Adjust the total mass. Given mass parameters for some object, adjust them so the total mass is now newmass. This is useful when using the setXyz() methods to set the mass parameters for certain objects - they take the object density, not the total mass. @param newmass: The new total mass @type newmass: float """ dMassAdjust(&self._mass, newmass) def translate(self, t): """translate(t) Adjust mass parameters. Given mass parameters for some object, adjust them to represent the object displaced by (x,y,z) relative to the body frame. @param t: Translation vector (x, y, z) @type t: 3-tuple of floats """ dMassTranslate(&self._mass, t[0], t[1], t[2]) # def rotate(self, R): # """ # Given mass parameters for some object, adjust them to # represent the object rotated by R relative to the body frame. # """ # pass def add(self, Mass b): """add(b) Add the mass b to the mass object. Masses can also be added using the + operator. @param b: The mass to add to this mass @type b: Mass """ dMassAdd(&self._mass, &b._mass) def __getattr__(self, name): if name == "mass": return self._mass.mass elif name == "c": return self._mass.c[0], self._mass.c[1], self._mass.c[2] elif name == "I": return ((self._mass.I[0], self._mass.I[1], self._mass.I[2]), (self._mass.I[4], self._mass.I[5], self._mass.I[6]), (self._mass.I[8], self._mass.I[9], self._mass.I[10])) else: raise AttributeError("Mass object has no attribute '%s'" % name) def __setattr__(self, name, value): if name == "mass": self.adjust(value) elif name == "c": raise AttributeError("Use the setParameter() method to change c") elif name == "I": raise AttributeError("Use the setParameter() method to change I") else: raise AttributeError("Mass object has no attribute '%s" % name) def __add__(self, Mass b): self.add(b) return self def __str__(self): m = str(self._mass.mass) sc0 = str(self._mass.c[0]) sc1 = str(self._mass.c[1]) sc2 = str(self._mass.c[2]) I11 = str(self._mass.I[0]) I22 = str(self._mass.I[5]) I33 = str(self._mass.I[10]) I12 = str(self._mass.I[1]) I13 = str(self._mass.I[2]) I23 = str(self._mass.I[6]) return ("Mass=%s\n" "Cg=(%s, %s, %s)\n" "I11=%s I22=%s I33=%s\n" "I12=%s I13=%s I23=%s" % (m, sc0, sc1, sc2, I11, I22, I33, I12, I13, I23)) # return ("Mass=%s / " # "Cg=(%s, %s, %s) / " # "I11=%s I22=%s I33=%s " # "I12=%s I13=%s I23=%s" % # (m, sc0, sc1, sc2, I11, I22, I33, I12, I13, I23)) cdef class Contact: """This class represents a contact between two bodies in one point. A Contact object stores all the input parameters for a ContactJoint. This class wraps the ODE dContact structure which has 3 components:: struct dContact { dSurfaceParameters surface; dContactGeom geom; dVector3 fdir1; }; This wrapper class provides methods to get and set the items of those structures. """ cdef dContact _contact def __cinit__(self): self._contact.surface.mode = ContactBounce self._contact.surface.mu = dInfinity self._contact.surface.bounce = 0.1 # getMode def getMode(self): """getMode() -> flags Return the contact flags. """ return self._contact.surface.mode # setMode def setMode(self, flags): """setMode(flags) Set the contact flags. The argument m is a combination of the ContactXyz flags (ContactMu2, ContactBounce, ...). @param flags: Contact flags @type flags: int """ self._contact.surface.mode = flags # getMu def getMu(self): """getMu() -> float Return the Coulomb friction coefficient. """ return self._contact.surface.mu # setMu def setMu(self, mu): """setMu(mu) Set the Coulomb friction coefficient. @param mu: Coulomb friction coefficient (0..Infinity) @type mu: float """ self._contact.surface.mu = mu # getMu2 def getMu2(self): """getMu2() -> float Return the optional Coulomb friction coefficient for direction 2. """ return self._contact.surface.mu2 # setMu2 def setMu2(self, mu): """setMu2(mu) Set the optional Coulomb friction coefficient for direction 2. @param mu: Coulomb friction coefficient (0..Infinity) @type mu: float """ self._contact.surface.mu2 = mu # getBounce def getBounce(self): """getBounce() -> float Return the restitution parameter. """ return self._contact.surface.bounce # setBounce def setBounce(self, b): """setBounce(b) @param b: Restitution parameter (0..1) @type b: float """ self._contact.surface.bounce = b # getBounceVel def getBounceVel(self): """getBounceVel() -> float Return the minimum incoming velocity necessary for bounce. """ return self._contact.surface.bounce_vel # setBounceVel def setBounceVel(self, bv): """setBounceVel(bv) Set the minimum incoming velocity necessary for bounce. Incoming velocities below this will effectively have a bounce parameter of 0. @param bv: Velocity @type bv: float """ self._contact.surface.bounce_vel = bv # getSoftERP def getSoftERP(self): """getSoftERP() -> float Return the contact normal "softness" parameter. """ return self._contact.surface.soft_erp # setSoftERP def setSoftERP(self, erp): """setSoftERP(erp) Set the contact normal "softness" parameter. @param erp: Softness parameter @type erp: float """ self._contact.surface.soft_erp = erp # getSoftCFM def getSoftCFM(self): """getSoftCFM() -> float Return the contact normal "softness" parameter. """ return self._contact.surface.soft_cfm # setSoftCFM def setSoftCFM(self, cfm): """setSoftCFM(cfm) Set the contact normal "softness" parameter. @param cfm: Softness parameter @type cfm: float """ self._contact.surface.soft_cfm = cfm # getMotion1 def getMotion1(self): """getMotion1() -> float Get the surface velocity in friction direction 1. """ return self._contact.surface.motion1 # setMotion1 def setMotion1(self, m): """setMotion1(m) Set the surface velocity in friction direction 1. @param m: Surface velocity @type m: float """ self._contact.surface.motion1 = m # getMotion2 def getMotion2(self): """getMotion2() -> float Get the surface velocity in friction direction 2. """ return self._contact.surface.motion2 # setMotion2 def setMotion2(self, m): """setMotion2(m) Set the surface velocity in friction direction 2. @param m: Surface velocity @type m: float """ self._contact.surface.motion2 = m # getSlip1 def getSlip1(self): """getSlip1() -> float Get the coefficient of force-dependent-slip (FDS) for friction direction 1. """ return self._contact.surface.slip1 # setSlip1 def setSlip1(self, s): """setSlip1(s) Set the coefficient of force-dependent-slip (FDS) for friction direction 1. @param s: FDS coefficient @type s: float """ self._contact.surface.slip1 = s # getSlip2 def getSlip2(self): """getSlip2() -> float Get the coefficient of force-dependent-slip (FDS) for friction direction 2. """ return self._contact.surface.slip2 # setSlip2 def setSlip2(self, s): """setSlip2(s) Set the coefficient of force-dependent-slip (FDS) for friction direction 1. @param s: FDS coefficient @type s: float """ self._contact.surface.slip2 = s # getFDir1 def getFDir1(self): """getFDir1() -> (x, y, z) Get the "first friction direction" vector that defines a direction along which frictional force is applied. """ return (self._contact.fdir1[0], self._contact.fdir1[1], self._contact.fdir1[2]) # setFDir1 def setFDir1(self, fdir): """setFDir1(fdir) Set the "first friction direction" vector that defines a direction along which frictional force is applied. It must be of unit length and perpendicular to the contact normal (so it is typically tangential to the contact surface). @param fdir: Friction direction @type fdir: 3-sequence of floats """ self._contact.fdir1[0] = fdir[0] self._contact.fdir1[1] = fdir[1] self._contact.fdir1[2] = fdir[2] # getContactGeomParams def getContactGeomParams(self): """getContactGeomParams() -> (pos, normal, depth, geom1, geom2) Get the ContactGeom structure of the contact. The return value is a tuple (pos, normal, depth, geom1, geom2) where pos and normal are 3-tuples of floats and depth is a single float. geom1 and geom2 are the Geom objects of the geoms in contact. """ cdef long id1, id2 pos = (self._contact.geom.pos[0], self._contact.geom.pos[1], self._contact.geom.pos[2]) normal = (self._contact.geom.normal[0], self._contact.geom.normal[1], self._contact.geom.normal[2]) depth = self._contact.geom.depth id1 = self._contact.geom.g1 id2 = self._contact.geom.g2 g1 = _geom_c2py_lut[id1] g2 = _geom_c2py_lut[id2] return pos, normal, depth, g1, g2 # setContactGeomParams def setContactGeomParams(self, pos, normal, depth, g1=None, g2=None): """setContactGeomParams(pos, normal, depth, geom1=None, geom2=None) Set the ContactGeom structure of the contact. @param pos: Contact position, in global coordinates @type pos: 3-sequence of floats @param normal: Unit length normal vector @type normal: 3-sequence of floats @param depth: Depth to which the two bodies inter-penetrate @type depth: float @param geom1: Geometry object 1 that collided @type geom1: Geom @param geom2: Geometry object 2 that collided @type geom2: Geom """ cdef long id self._contact.geom.pos[0] = pos[0] self._contact.geom.pos[1] = pos[1] self._contact.geom.pos[2] = pos[2] self._contact.geom.normal[0] = normal[0] self._contact.geom.normal[1] = normal[1] self._contact.geom.normal[2] = normal[2] self._contact.geom.depth = depth if g1 != None: id = g1._id() self._contact.geom.g1 = id else: self._contact.geom.g1 = 0 if g2 != None: id = g2._id() self._contact.geom.g2 = id else: self._contact.geom.g2 = 0 # World cdef class World: """Dynamics world. The world object is a container for rigid bodies and joints. Constructor:: World() """ cdef dWorldID wid def __cinit__(self): self.wid = dWorldCreate() def __dealloc__(self): if self.wid != NULL: dWorldDestroy(self.wid) # setGravity def setGravity(self, gravity): """setGravity(gravity) Set the world's global gravity vector. @param gravity: Gravity vector @type gravity: 3-sequence of floats """ dWorldSetGravity(self.wid, gravity[0], gravity[1], gravity[2]) # getGravity def getGravity(self): """getGravity() -> 3-tuple Return the world's global gravity vector as a 3-tuple of floats. """ cdef dVector3 g dWorldGetGravity(self.wid, g) return g[0], g[1], g[2] # setERP def setERP(self, erp): """setERP(erp) Set the global ERP value, that controls how much error correction is performed in each time step. Typical values are in the range 0.1-0.8. The default is 0.2. @param erp: Global ERP value @type erp: float """ dWorldSetERP(self.wid, erp) # getERP def getERP(self): """getERP() -> float Get the global ERP value, that controls how much error correction is performed in each time step. Typical values are in the range 0.1-0.8. The default is 0.2. """ return dWorldGetERP(self.wid) # setCFM def setCFM(self, cfm): """setCFM(cfm) Set the global CFM (constraint force mixing) value. Typical values are in the range 10E-9 - 1. The default is 10E-5 if single precision is being used, or 10E-10 if double precision is being used. @param cfm: Constraint force mixing value @type cfm: float """ dWorldSetCFM(self.wid, cfm) # getCFM def getCFM(self): """getCFM() -> float Get the global CFM (constraint force mixing) value. Typical values are in the range 10E-9 - 1. The default is 10E-5 if single precision is being used, or 10E-10 if double precision is being used. """ return dWorldGetCFM(self.wid) # step def step(self, stepsize): """step(stepsize) Step the world. This uses a "big matrix" method that takes time on the order of O(m3) and memory on the order of O(m2), where m is the total number of constraint rows. For large systems this will use a lot of memory and can be very slow, but this is currently the most accurate method. @param stepsize: Time step @type stepsize: float """ dWorldStep(self.wid, stepsize) # quickStep def quickStep(self, stepsize): """quickStep(stepsize) Step the world. This uses an iterative method that takes time on the order of O(m*N) and memory on the order of O(m), where m is the total number of constraint rows and N is the number of iterations. For large systems this is a lot faster than dWorldStep, but it is less accurate. @param stepsize: Time step @type stepsize: float """ dWorldQuickStep(self.wid, stepsize) # setQuickStepNumIterations def setQuickStepNumIterations(self, num): """setQuickStepNumIterations(num) Set the number of iterations that the QuickStep method performs per step. More iterations will give a more accurate solution, but will take longer to compute. The default is 20 iterations. @param num: Number of iterations @type num: int """ dWorldSetQuickStepNumIterations(self.wid, num) # getQuickStepNumIterations def getQuickStepNumIterations(self): """getQuickStepNumIterations() -> int Get the number of iterations that the QuickStep method performs per step. More iterations will give a more accurate solution, but will take longer to compute. The default is 20 iterations. """ return dWorldGetQuickStepNumIterations(self.wid) # setQuickStepNumIterations def setContactMaxCorrectingVel(self, vel): """setContactMaxCorrectingVel(vel) Set the maximum correcting velocity that contacts are allowed to generate. The default value is infinity (i.e. no limit). Reducing this value can help prevent "popping" of deeply embedded objects. @param vel: Maximum correcting velocity @type vel: float """ dWorldSetContactMaxCorrectingVel(self.wid, vel) # getQuickStepNumIterations def getContactMaxCorrectingVel(self): """getContactMaxCorrectingVel() -> float Get the maximum correcting velocity that contacts are allowed to generate. The default value is infinity (i.e. no limit). Reducing this value can help prevent "popping" of deeply embedded objects. """ return dWorldGetContactMaxCorrectingVel(self.wid) # setContactSurfaceLayer def setContactSurfaceLayer(self, depth): """setContactSurfaceLayer(depth) Set the depth of the surface layer around all geometry objects. Contacts are allowed to sink into the surface layer up to the given depth before coming to rest. The default value is zero. Increasing this to some small value (e.g. 0.001) can help prevent jittering problems due to contacts being repeatedly made and broken. @param depth: Surface layer depth @type depth: float """ dWorldSetContactSurfaceLayer(self.wid, depth) # getContactSurfaceLayer def getContactSurfaceLayer(self): """getContactSurfaceLayer() Get the depth of the surface layer around all geometry objects. Contacts are allowed to sink into the surface layer up to the given depth before coming to rest. The default value is zero. Increasing this to some small value (e.g. 0.001) can help prevent jittering problems due to contacts being repeatedly made and broken. """ return dWorldGetContactSurfaceLayer(self.wid) # setAutoDisableFlag def setAutoDisableFlag(self, flag): """setAutoDisableFlag(flag) Set the default auto-disable flag for newly created bodies. @param flag: True = Do auto disable @type flag: bool """ dWorldSetAutoDisableFlag(self.wid, flag) # getAutoDisableFlag def getAutoDisableFlag(self): """getAutoDisableFlag() -> bool Get the default auto-disable flag for newly created bodies. """ return dWorldGetAutoDisableFlag(self.wid) # setAutoDisableLinearThreshold def setAutoDisableLinearThreshold(self, threshold): """setAutoDisableLinearThreshold(threshold) Set the default auto-disable linear threshold for newly created bodies. @param threshold: Linear threshold @type threshold: float """ dWorldSetAutoDisableLinearThreshold(self.wid, threshold) # getAutoDisableLinearThreshold def getAutoDisableLinearThreshold(self): """getAutoDisableLinearThreshold() -> float Get the default auto-disable linear threshold for newly created bodies. """ return dWorldGetAutoDisableLinearThreshold(self.wid) # setAutoDisableAngularThreshold def setAutoDisableAngularThreshold(self, threshold): """setAutoDisableAngularThreshold(threshold) Set the default auto-disable angular threshold for newly created bodies. @param threshold: Angular threshold @type threshold: float """ dWorldSetAutoDisableAngularThreshold(self.wid, threshold) # getAutoDisableAngularThreshold def getAutoDisableAngularThreshold(self): """getAutoDisableAngularThreshold() -> float Get the default auto-disable angular threshold for newly created bodies. """ return dWorldGetAutoDisableAngularThreshold(self.wid) # setAutoDisableSteps def setAutoDisableSteps(self, steps): """setAutoDisableSteps(steps) Set the default auto-disable steps for newly created bodies. @param steps: Auto disable steps @type steps: int """ dWorldSetAutoDisableSteps(self.wid, steps) # getAutoDisableSteps def getAutoDisableSteps(self): """getAutoDisableSteps() -> int Get the default auto-disable steps for newly created bodies. """ return dWorldGetAutoDisableSteps(self.wid) # setAutoDisableTime def setAutoDisableTime(self, time): """setAutoDisableTime(time) Set the default auto-disable time for newly created bodies. @param time: Auto disable time @type time: float """ dWorldSetAutoDisableTime(self.wid, time) # getAutoDisableTime def getAutoDisableTime(self): """getAutoDisableTime() -> float Get the default auto-disable time for newly created bodies. """ return dWorldGetAutoDisableTime(self.wid) # setLinearDamping def setLinearDamping(self, scale): """setLinearDamping(scale) Set the world's linear damping scale. @param scale The linear damping scale that is to be applied to bodies. Default is 0 (no damping). Should be in the interval [0, 1]. @type scale: float """ dWorldSetLinearDamping(self.wid, scale) # getLinearDamping def getLinearDamping(self): """getLinearDamping() -> float Get the world's linear damping scale. """ return dWorldGetLinearDamping(self.wid) # setAngularDamping def setAngularDamping(self, scale): """setAngularDamping(scale) Set the world's angular damping scale. @param scale The angular damping scale that is to be applied to bodies. Default is 0 (no damping). Should be in the interval [0, 1]. @type scale: float """ dWorldSetAngularDamping(self.wid, scale) # getAngularDamping def getAngularDamping(self): """getAngularDamping() -> float Get the world's angular damping scale. """ return dWorldGetAngularDamping(self.wid) # impulseToForce def impulseToForce(self, stepsize, impulse): """impulseToForce(stepsize, impulse) -> 3-tuple If you want to apply a linear or angular impulse to a rigid body, instead of a force or a torque, then you can use this function to convert the desired impulse into a force/torque vector before calling the dBodyAdd... function. @param stepsize: Time step @param impulse: Impulse vector @type stepsize: float @type impulse: 3-tuple of floats """ cdef dVector3 force dWorldImpulseToForce(self.wid, stepsize, impulse[0], impulse[1], impulse[2], force) return force[0], force[1], force[2] # createBody # def createBody(self): # return Body(self) # createBallJoint # def createBallJoint(self, jointgroup=None): # return BallJoint(self, jointgroup) # createHingeJoint # def createHingeJoint(self, jointgroup=None): # return HingeJoint(self, jointgroup) # createHinge2Joint # def createHinge2Joint(self, jointgroup=None): # return Hinge2Joint(self, jointgroup) # createSliderJoint # def createSliderJoint(self, jointgroup=None): # return SliderJoint(self, jointgroup) # createFixedJoint # def createFixedJoint(self, jointgroup=None): # return FixedJoint(self, jointgroup) # createContactJoint # def createContactJoint(self, jointgroup, contact): # return ContactJoint(self, jointgroup, contact) # Body cdef class Body: """The rigid body class encapsulating the ODE body. This class represents a rigid body that has a location and orientation in space and that stores the mass properties of an object. When creating a Body object you have to pass the world it belongs to as argument to the constructor:: >>> import ode >>> w = ode.World() >>> b = ode.Body(w) """ cdef dBodyID bid # A reference to the world so that the world won't be destroyed while # there are still joints using it. cdef object world # A dictionary with user attributes # (set via __getattr__ and __setattr__) cdef object userattribs def __cinit__(self, World world not None): self.bid = dBodyCreate(world.wid) def __init__(self, World world not None): """Constructor. @param world: The world in which the body should be created. @type world: World """ self.world = world self.userattribs = {} def __dealloc__(self): if self.bid != NULL: dBodyDestroy(self.bid) def __getattr__(self, name): try: return self.userattribs[name] except: raise AttributeError("Body object has no attribute '%s'" % name) def __setattr__(self, name, value): self.userattribs[name] = value def __delattr__(self, name): try: del self.userattribs[name] except: raise AttributeError("Body object has no attribute '%s'" % name) # setPosition def setPosition(self, pos): """setPosition(pos) Set the position of the body. @param pos: The new position @type pos: 3-sequence of floats """ dBodySetPosition(self.bid, pos[0], pos[1], pos[2]) # getPosition def getPosition(self): """getPosition() -> 3-tuple Return the current position of the body. """ cdef dReal* p # The "const" in the original return value is cast away p = dBodyGetPosition(self.bid) return p[0], p[1], p[2] # setRotation def setRotation(self, R): """setRotation(R) Set the orientation of the body. The rotation matrix must be given as a sequence of 9 floats which are the elements of the matrix in row-major order. @param R: Rotation matrix @type R: 9-sequence of floats """ cdef dMatrix3 m m[0] = R[0] m[1] = R[1] m[2] = R[2] m[3] = 0 m[4] = R[3] m[5] = R[4] m[6] = R[5] m[7] = 0 m[8] = R[6] m[9] = R[7] m[10] = R[8] m[11] = 0 dBodySetRotation(self.bid, m) # getRotation def getRotation(self): """getRotation() -> 9-tuple Return the current rotation matrix as a tuple of 9 floats (row-major order). """ cdef dReal* m # The "const" in the original return value is cast away m = dBodyGetRotation(self.bid) return m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10] # getQuaternion def getQuaternion(self): """getQuaternion() -> 4-tuple Return the current rotation as a quaternion. The return value is a list of 4 floats. """ cdef dReal* q q = dBodyGetQuaternion(self.bid) return q[0], q[1], q[2], q[3] # setQuaternion def setQuaternion(self, q): """setQuaternion(q) Set the orientation of the body. The quaternion must be given as a sequence of 4 floats. @param q: Quaternion @type q: 4-sequence of floats """ cdef dQuaternion w w[0] = q[0] w[1] = q[1] w[2] = q[2] w[3] = q[3] dBodySetQuaternion(self.bid, w) # setLinearVel def setLinearVel(self, vel): """setLinearVel(vel) Set the linear velocity of the body. @param vel: New velocity @type vel: 3-sequence of floats """ dBodySetLinearVel(self.bid, vel[0], vel[1], vel[2]) # getLinearVel def getLinearVel(self): """getLinearVel() -> 3-tuple Get the current linear velocity of the body. """ cdef dReal* p # The "const" in the original return value is cast away p = dBodyGetLinearVel(self.bid) return p[0], p[1], p[2] # setAngularVel def setAngularVel(self, vel): """setAngularVel(vel) Set the angular velocity of the body. @param vel: New angular velocity @type vel: 3-sequence of floats """ dBodySetAngularVel(self.bid, vel[0], vel[1], vel[2]) # getAngularVel def getAngularVel(self): """getAngularVel() -> 3-tuple Get the current angular velocity of the body. """ cdef dReal* p # The "const" in the original return value is cast away p = dBodyGetAngularVel(self.bid) return p[0], p[1], p[2] # setMass def setMass(self, Mass mass): """setMass(mass) Set the mass properties of the body. The argument mass must be an instance of a Mass object. @param mass: Mass properties @type mass: Mass """ dBodySetMass(self.bid, &mass._mass) # getMass def getMass(self): """getMass() -> mass Return the mass properties as a Mass object. """ cdef Mass m m = Mass() dBodyGetMass(self.bid, &m._mass) return m # addForce def addForce(self, f): """addForce(f) Add an external force f given in absolute coordinates. The force is applied at the center of mass. @param f: Force @type f: 3-sequence of floats """ dBodyAddForce(self.bid, f[0], f[1], f[2]) # addTorque def addTorque(self, t): """addTorque(t) Add an external torque t given in absolute coordinates. @param t: Torque @type t: 3-sequence of floats """ dBodyAddTorque(self.bid, t[0], t[1], t[2]) # addRelForce def addRelForce(self, f): """addRelForce(f) Add an external force f given in relative coordinates (relative to the body's own frame of reference). The force is applied at the center of mass. @param f: Force @type f: 3-sequence of floats """ dBodyAddRelForce(self.bid, f[0], f[1], f[2]) # addRelTorque def addRelTorque(self, t): """addRelTorque(t) Add an external torque t given in relative coordinates (relative to the body's own frame of reference). @param t: Torque @type t: 3-sequence of floats """ dBodyAddRelTorque(self.bid, t[0], t[1], t[2]) # addForceAtPos def addForceAtPos(self, f, p): """addForceAtPos(f, p) Add an external force f at position p. Both arguments must be given in absolute coordinates. @param f: Force @param p: Position @type f: 3-sequence of floats @type p: 3-sequence of floats """ dBodyAddForceAtPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2]) # addForceAtRelPos def addForceAtRelPos(self, f, p): """addForceAtRelPos(f, p) Add an external force f at position p. f is given in absolute coordinates and p in absolute coordinates. @param f: Force @param p: Position @type f: 3-sequence of floats @type p: 3-sequence of floats """ dBodyAddForceAtRelPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2]) # addRelForceAtPos def addRelForceAtPos(self, f, p): """addRelForceAtPos(f, p) Add an external force f at position p. f is given in relative coordinates and p in relative coordinates. @param f: Force @param p: Position @type f: 3-sequence of floats @type p: 3-sequence of floats """ dBodyAddRelForceAtPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2]) # addRelForceAtRelPos def addRelForceAtRelPos(self, f, p): """addRelForceAtRelPos(f, p) Add an external force f at position p. Both arguments must be given in relative coordinates. @param f: Force @param p: Position @type f: 3-sequence of floats @type p: 3-sequence of floats """ dBodyAddRelForceAtRelPos(self.bid, f[0], f[1], f[2], p[0], p[1], p[2]) # getForce def getForce(self): """getForce() -> 3-tuple Return the current accumulated force. """ cdef dReal* f # The "const" in the original return value is cast away f = dBodyGetForce(self.bid) return f[0], f[1], f[2] # getTorque def getTorque(self): """getTorque() -> 3-tuple Return the current accumulated torque. """ cdef dReal* f # The "const" in the original return value is cast away f = dBodyGetTorque(self.bid) return f[0], f[1], f[2] # setForce def setForce(self, f): """setForce(f) Set the body force accumulation vector. @param f: Force @type f: 3-tuple of floats """ dBodySetForce(self.bid, f[0], f[1], f[2]) # setTorque def setTorque(self, t): """setTorque(t) Set the body torque accumulation vector. @param t: Torque @type t: 3-tuple of floats """ dBodySetTorque(self.bid, t[0], t[1], t[2]) # getRelPointPos def getRelPointPos(self, p): """getRelPointPos(p) -> 3-tuple Utility function that takes a point p on a body and returns that point's position in global coordinates. The point p must be given in body relative coordinates. @param p: Body point (local coordinates) @type p: 3-sequence of floats """ cdef dVector3 res dBodyGetRelPointPos(self.bid, p[0], p[1], p[2], res) return res[0], res[1], res[2] # getRelPointVel def getRelPointVel(self, p): """getRelPointVel(p) -> 3-tuple Utility function that takes a point p on a body and returns that point's velocity in global coordinates. The point p must be given in body relative coordinates. @param p: Body point (local coordinates) @type p: 3-sequence of floats """ cdef dVector3 res dBodyGetRelPointVel(self.bid, p[0], p[1], p[2], res) return res[0], res[1], res[2] # getPointVel def getPointVel(self, p): """getPointVel(p) -> 3-tuple Utility function that takes a point p on a body and returns that point's velocity in global coordinates. The point p must be given in global coordinates. @param p: Body point (global coordinates) @type p: 3-sequence of floats """ cdef dVector3 res dBodyGetPointVel(self.bid, p[0], p[1], p[2], res) return res[0], res[1], res[2] # getPosRelPoint def getPosRelPoint(self, p): """getPosRelPoint(p) -> 3-tuple This is the inverse of getRelPointPos(). It takes a point p in global coordinates and returns the point's position in body-relative coordinates. @param p: Body point (global coordinates) @type p: 3-sequence of floats """ cdef dVector3 res dBodyGetPosRelPoint(self.bid, p[0], p[1], p[2], res) return res[0], res[1], res[2] # vectorToWorld def vectorToWorld(self, v): """vectorToWorld(v) -> 3-tuple Given a vector v expressed in the body coordinate system, rotate it to the world coordinate system. @param v: Vector in body coordinate system @type v: 3-sequence of floats """ cdef dVector3 res dBodyVectorToWorld(self.bid, v[0], v[1], v[2], res) return res[0], res[1], res[2] # vectorFromWorld def vectorFromWorld(self, v): """vectorFromWorld(v) -> 3-tuple Given a vector v expressed in the world coordinate system, rotate it to the body coordinate system. @param v: Vector in world coordinate system @type v: 3-sequence of floats """ cdef dVector3 res dBodyVectorFromWorld(self.bid, v[0], v[1], v[2], res) return res[0], res[1], res[2] # Enable def enable(self): """enable() Manually enable a body. """ dBodyEnable(self.bid) # Disable def disable(self): """disable() Manually disable a body. Note that a disabled body that is connected through a joint to an enabled body will be automatically re-enabled at the next simulation step. """ dBodyDisable(self.bid) # isEnabled def isEnabled(self): """isEnabled() -> bool Check if a body is currently enabled. """ return dBodyIsEnabled(self.bid) # setFiniteRotationMode def setFiniteRotationMode(self, mode): """setFiniteRotationMode(mode) This function controls the way a body's orientation is updated at each time step. The mode argument can be: - 0: An "infinitesimal" orientation update is used. This is fast to compute, but it can occasionally cause inaccuracies for bodies that are rotating at high speed, especially when those bodies are joined to other bodies. This is the default for every new body that is created. - 1: A "finite" orientation update is used. This is more costly to compute, but will be more accurate for high speed rotations. Note however that high speed rotations can result in many types of error in a simulation, and this mode will only fix one of those sources of error. @param mode: Rotation mode (0/1) @type mode: int """ dBodySetFiniteRotationMode(self.bid, mode) # getFiniteRotationMode def getFiniteRotationMode(self): """getFiniteRotationMode() -> mode (0/1) Return the current finite rotation mode of a body (0 or 1). See setFiniteRotationMode(). """ return dBodyGetFiniteRotationMode(self.bid) # setFiniteRotationAxis def setFiniteRotationAxis(self, a): """setFiniteRotationAxis(a) Set the finite rotation axis of the body. This axis only has a meaning when the finite rotation mode is set (see setFiniteRotationMode()). @param a: Axis @type a: 3-sequence of floats """ dBodySetFiniteRotationAxis(self.bid, a[0], a[1], a[2]) # getFiniteRotationAxis def getFiniteRotationAxis(self): """getFiniteRotationAxis() -> 3-tuple Return the current finite rotation axis of the body. """ cdef dVector3 p # The "const" in the original return value is cast away dBodyGetFiniteRotationAxis(self.bid, p) return p[0], p[1], p[2] # getNumJoints def getNumJoints(self): """getNumJoints() -> int Return the number of joints that are attached to this body. """ return dBodyGetNumJoints(self.bid) # setGravityMode def setGravityMode(self, mode): """setGravityMode(mode) Set whether the body is influenced by the world's gravity or not. If mode is True it is, otherwise it isn't. Newly created bodies are always influenced by the world's gravity. @param mode: Gravity mode @type mode: bool """ dBodySetGravityMode(self.bid, mode) # getGravityMode def getGravityMode(self): """getGravityMode() -> bool Return True if the body is influenced by the world's gravity. """ return dBodyGetGravityMode(self.bid) def setDynamic(self): """setDynamic() Set a body to the (default) "dynamic" state, instead of "kinematic". See setKinematic() for more information. """ dBodySetDynamic(self.bid) def setKinematic(self): """setKinematic() Set the kinematic state of the body (change it into a kinematic body) Kinematic bodies behave as if they had infinite mass. This means they don't react to any force (gravity, constraints or user-supplied); they simply follow velocity to reach the next position. [from ODE wiki] """ dBodySetKinematic(self.bid) def isKinematic(self): """isKinematic() -> bool Return True if the body is kinematic (not influenced by other forces). Kinematic bodies behave as if they had infinite mass. This means they don't react to any force (gravity, constraints or user-supplied); they simply follow velocity to reach the next position. [from ODE wiki] """ return dBodyIsKinematic(self.bid) def setMaxAngularSpeed(self, max_speed): """setMaxAngularSpeed(max_speed) You can also limit the maximum angular speed. In contrast to the damping functions, the angular velocity is affected before the body is moved. This means that it will introduce errors in joints that are forcing the body to rotate too fast. Some bodies have naturally high angular velocities (like cars' wheels), so you may want to give them a very high (like the default, dInfinity) limit. """ dBodySetMaxAngularSpeed(self.bid, max_speed) # JointGroup cdef class JointGroup: """Joint group. Constructor:: JointGroup() """ # JointGroup ID cdef dJointGroupID gid # A list of Python joints that were added to the group cdef object jointlist def __cinit__(self): self.gid = dJointGroupCreate(0) def __init__(self): self.jointlist = [] def __dealloc__(self): if self.gid != NULL: for j in self.jointlist: j._destroyed() dJointGroupDestroy(self.gid) # empty def empty(self): """empty() Destroy all joints in the group. """ dJointGroupEmpty(self.gid) for j in self.jointlist: j._destroyed() self.jointlist = [] def _addjoint(self, j): """_addjoint(j) Add a joint to the group. This is an internal method that is called by the joints. The group has to know the Python wrappers because it has to notify them when the group is emptied (so that the ODE joints won't get destroyed twice). The notification is done by calling _destroyed() on the Python joints. @param j: The joint to add @type j: Joint """ self.jointlist.append(j) ###################################################################### # Joint cdef class Joint: """Base class for all joint classes.""" # Joint id as returned by dJointCreateXxx() cdef dJointID jid # A reference to the world so that the world won't be destroyed while # there are still joints using it. cdef object world # The feedback buffer cdef dJointFeedback* feedback cdef object body1 cdef object body2 # A dictionary with user attributes # (set via __getattr__ and __setattr__) cdef object userattribs def __cinit__(self, *a, **kw): self.jid = NULL self.world = None self.feedback = NULL self.body1 = None self.body2 = None self.userattribs = {} def __init__(self, *a, **kw): raise NotImplementedError("Joint base class can't be used directly") def __dealloc__(self): self.setFeedback(False) if self.jid != NULL: dJointDestroy(self.jid) def __getattr__(self, name): try: return self.userattribs[name] except: raise AttributeError("Joint object has no attribute '%s'" % name) def __setattr__(self, name, value): self.userattribs[name] = value def __delattr__(self, name): try: del self.userattribs[name] except: raise AttributeError("Joint object has no attribute '%s'" % name) # _destroyed def _destroyed(self): """Notify the joint object about an external destruction of the ODE joint. This method has to be called when the underlying ODE object was destroyed by someone else (e.g. by a joint group). The Python wrapper will then refrain from destroying it again. """ self.jid = NULL # enable def enable(self): """enable() Enable the joint. Disabled joints are completely ignored during the simulation. Disabled joints don't lose the already computed information like anchors and axes. """ dJointEnable(self.jid) # disable def disable(self): """disable() Disable the joint. Disabled joints are completely ignored during the simulation. Disabled joints don't lose the already computed information like anchors and axes. """ dJointDisable(self.jid) # isEnabled def isEnabled(self): """isEnabled() -> bool Determine whether the joint is enabled. Disabled joints are completely ignored during the simulation. Disabled joints don't lose the already computed information like anchors and axes. """ return dJointIsEnabled(self.jid) # attach def attach(self, Body body1, Body body2): """attach(body1, body2) Attach the joint to some new bodies. A body can be attached to the environment by passing None as second body. @param body1: First body @param body2: Second body @type body1: Body @type body2: Body """ cdef dBodyID id1, id2 if body1 == None: id1 = NULL else: id1 = body1.bid if body2 == None: id2 = NULL else: id2 = body2.bid self.body1 = body1 self.body2 = body2 dJointAttach(self.jid, id1, id2) # getBody def getBody(self, index): """getBody(index) -> Body Return the bodies that this joint connects. If index is 0 the "first" body will be returned, corresponding to the body1 argument of the attach() method. If index is 1 the "second" body will be returned, corresponding to the body2 argument of the attach() method. @param index: Bodx index (0 or 1). @type index: int """ if index == 0: return self.body1 elif index == 1: return self.body2 else: raise IndexError() # setFeedback def setFeedback(self, flag=1): """setFeedback(flag=True) Create a feedback buffer. If flag is True then a buffer is allocated and the forces/torques applied by the joint can be read using the getFeedback() method. If flag is False the buffer is released. @param flag: Specifies whether a buffer should be created or released @type flag: bool """ if flag: # Was there already a buffer allocated? then we're finished if self.feedback != NULL: return # Allocate a buffer and pass it to ODE self.feedback = malloc(sizeof(dJointFeedback)) if self.feedback == NULL: raise MemoryError("can't allocate feedback buffer") dJointSetFeedback(self.jid, self.feedback) else: if self.feedback != NULL: # Free a previously allocated buffer dJointSetFeedback(self.jid, NULL) free(self.feedback) self.feedback = NULL # getFeedback def getFeedback(self): """getFeedback() -> (force1, torque1, force2, torque2) Get the forces/torques applied by the joint. If feedback is activated (i.e. setFeedback(True) was called) then this method returns a tuple (force1, torque1, force2, torque2) with the forces and torques applied to body 1 and body 2. The forces/torques are given as 3-tuples. If feedback is deactivated then the method always returns None. """ cdef dJointFeedback* fb fb = dJointGetFeedback(self.jid) if fb == NULL: return None f1 = (fb.f1[0], fb.f1[1], fb.f1[2]) t1 = (fb.t1[0], fb.t1[1], fb.t1[2]) f2 = (fb.f2[0], fb.f2[1], fb.f2[2]) t2 = (fb.t2[0], fb.t2[1], fb.t2[2]) return f1, t1, f2, t2 ###################################################################### # BallJoint cdef class BallJoint(Joint): """Ball joint. Constructor:: BallJoint(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateBall(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setAnchor def setAnchor(self, pos): """setAnchor(pos) Set the joint anchor point which must be specified in world coordinates. @param pos: Anchor position @type pos: 3-sequence of floats """ dJointSetBallAnchor(self.jid, pos[0], pos[1], pos[2]) # getAnchor def getAnchor(self): """getAnchor() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 1. If the joint is perfectly satisfied, this will be the same as the point on body 2. """ cdef dVector3 p dJointGetBallAnchor(self.jid, p) return p[0], p[1], p[2] # getAnchor2 def getAnchor2(self): """getAnchor2() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 2. If the joint is perfectly satisfied, this will be the same as the point on body 1. """ cdef dVector3 p dJointGetBallAnchor2(self.jid, p) return p[0], p[1], p[2] # setParam def setParam(self, param, value): pass # getParam def getParam(self, param): return 0.0 # HingeJoint cdef class HingeJoint(Joint): """Hinge joint. Constructor:: HingeJoint(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateHinge(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setAnchor def setAnchor(self, pos): """setAnchor(pos) Set the hinge anchor which must be given in world coordinates. @param pos: Anchor position @type pos: 3-sequence of floats """ dJointSetHingeAnchor(self.jid, pos[0], pos[1], pos[2]) # getAnchor def getAnchor(self): """getAnchor() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 1. If the joint is perfectly satisfied, this will be the same as the point on body 2. """ cdef dVector3 p dJointGetHingeAnchor(self.jid, p) return p[0], p[1], p[2] # getAnchor2 def getAnchor2(self): """getAnchor2() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 2. If the joint is perfectly satisfied, this will be the same as the point on body 1. """ cdef dVector3 p dJointGetHingeAnchor2(self.jid, p) return p[0], p[1], p[2] # setAxis def setAxis(self, axis): """setAxis(axis) Set the hinge axis. @param axis: Hinge axis @type axis: 3-sequence of floats """ dJointSetHingeAxis(self.jid, axis[0], axis[1], axis[2]) # getAxis def getAxis(self): """getAxis() -> 3-tuple of floats Get the hinge axis. """ cdef dVector3 a dJointGetHingeAxis(self.jid, a) return a[0], a[1], a[2] # getAngle def getAngle(self): """getAngle() -> float Get the hinge angle. The angle is measured between the two bodies, or between the body and the static environment. The angle will be between -pi..pi. When the hinge anchor or axis is set, the current position of the attached bodies is examined and that position will be the zero angle. """ return dJointGetHingeAngle(self.jid) # getAngleRate def getAngleRate(self): """getAngleRate() -> float Get the time derivative of the angle. """ return dJointGetHingeAngleRate(self.jid) # addTorque def addTorque(self, torque): """addTorque(torque) Applies the torque about the hinge axis. @param torque: Torque magnitude @type torque: float """ dJointAddHingeTorque(self.jid, torque) # setParam def setParam(self, param, value): """setParam(param, value) Set limit/motor parameters for the joint. param is one of ParamLoStop, ParamHiStop, ParamVel, ParamFMax, ParamFudgeFactor, ParamBounce, ParamCFM, ParamStopERP, ParamStopCFM, ParamSuspensionERP, ParamSuspensionCFM. These parameter names can be optionally followed by a digit (2 or 3) to indicate the second or third set of parameters. @param param: Selects the parameter to set @param value: Parameter value @type param: int @type value: float """ dJointSetHingeParam(self.jid, param, value) # getParam def getParam(self, param): """getParam(param) -> float Get limit/motor parameters for the joint. param is one of ParamLoStop, ParamHiStop, ParamVel, ParamFMax, ParamFudgeFactor, ParamBounce, ParamCFM, ParamStopERP, ParamStopCFM, ParamSuspensionERP, ParamSuspensionCFM. These parameter names can be optionally followed by a digit (2 or 3) to indicate the second or third set of parameters. @param param: Selects the parameter to read @type param: int """ return dJointGetHingeParam(self.jid, param) # SliderJoint cdef class SliderJoint(Joint): """Slider joint. Constructor:: SlideJoint(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateSlider(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setAxis def setAxis(self, axis): """setAxis(axis) Set the slider axis parameter. @param axis: Slider axis @type axis: 3-sequence of floats """ dJointSetSliderAxis(self.jid, axis[0], axis[1], axis[2]) # getAxis def getAxis(self): """getAxis() -> 3-tuple of floats Get the slider axis parameter. """ cdef dVector3 a dJointGetSliderAxis(self.jid, a) return a[0], a[1], a[2] # getPosition def getPosition(self): """getPosition() -> float Get the slider linear position (i.e. the slider's "extension"). When the axis is set, the current position of the attached bodies is examined and that position will be the zero position. """ return dJointGetSliderPosition(self.jid) # getPositionRate def getPositionRate(self): """getPositionRate() -> float Get the time derivative of the position. """ return dJointGetSliderPositionRate(self.jid) # addForce def addForce(self, force): """addForce(force) Applies the given force in the slider's direction. @param force: Force magnitude @type force: float """ dJointAddSliderForce(self.jid, force) # setParam def setParam(self, param, value): dJointSetSliderParam(self.jid, param, value) # getParam def getParam(self, param): return dJointGetSliderParam(self.jid, param) # UniversalJoint cdef class UniversalJoint(Joint): """Universal joint. Constructor:: UniversalJoint(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateUniversal(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setAnchor def setAnchor(self, pos): """setAnchor(pos) Set the universal anchor. @param pos: Anchor position @type pos: 3-sequence of floats """ dJointSetUniversalAnchor(self.jid, pos[0], pos[1], pos[2]) # getAnchor def getAnchor(self): """getAnchor() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 1. If the joint is perfectly satisfied, this will be the same as the point on body 2. """ cdef dVector3 p dJointGetUniversalAnchor(self.jid, p) return p[0], p[1], p[2] # getAnchor2 def getAnchor2(self): """getAnchor2() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 2. If the joint is perfectly satisfied, this will be the same as the point on body 1. """ cdef dVector3 p dJointGetUniversalAnchor2(self.jid, p) return p[0], p[1], p[2] # setAxis1 def setAxis1(self, axis): """setAxis1(axis) Set the first universal axis. Axis 1 and axis 2 should be perpendicular to each other. @param axis: Joint axis @type axis: 3-sequence of floats """ dJointSetUniversalAxis1(self.jid, axis[0], axis[1], axis[2]) # getAxis1 def getAxis1(self): """getAxis1() -> 3-tuple of floats Get the first univeral axis. """ cdef dVector3 a dJointGetUniversalAxis1(self.jid, a) return a[0], a[1], a[2] # setAxis2 def setAxis2(self, axis): """setAxis2(axis) Set the second universal axis. Axis 1 and axis 2 should be perpendicular to each other. @param axis: Joint axis @type axis: 3-sequence of floats """ dJointSetUniversalAxis2(self.jid, axis[0], axis[1], axis[2]) # getAxis2 def getAxis2(self): """getAxis2() -> 3-tuple of floats Get the second univeral axis. """ cdef dVector3 a dJointGetUniversalAxis2(self.jid, a) return a[0], a[1], a[2] # addTorques def addTorques(self, torque1, torque2): """addTorques(torque1, torque2) Applies torque1 about axis 1, and torque2 about axis 2. @param torque1: Torque 1 magnitude @param torque2: Torque 2 magnitude @type torque1: float @type torque2: float """ dJointAddUniversalTorques(self.jid, torque1, torque2) def getAngle1(self): return dJointGetUniversalAngle1(self.jid) def getAngle2(self): return dJointGetUniversalAngle2(self.jid) def getAngle1Rate(self): return dJointGetUniversalAngle1Rate(self.jid) def getAngle2Rate(self): return dJointGetUniversalAngle2Rate(self.jid) # setParam def setParam(self, param, value): dJointSetUniversalParam(self.jid, param, value) # getParam def getParam(self, param): return dJointGetUniversalParam(self.jid, param) # Hinge2Joint cdef class Hinge2Joint(Joint): """Hinge2 joint. Constructor:: Hinge2Joint(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateHinge2(world.wid, jgid) def __init__(self, World world, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setAnchor def setAnchor(self, pos): """setAnchor(pos) Set the hinge-2 anchor. @param pos: Anchor position @type pos: 3-sequence of floats """ dJointSetHinge2Anchor(self.jid, pos[0], pos[1], pos[2]) # getAnchor def getAnchor(self): """getAnchor() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 1. If the joint is perfectly satisfied, this will be the same as the point on body 2. """ cdef dVector3 p dJointGetHinge2Anchor(self.jid, p) return p[0], p[1], p[2] # getAnchor2 def getAnchor2(self): """getAnchor2() -> 3-tuple of floats Get the joint anchor point, in world coordinates. This returns the point on body 2. If the joint is perfectly satisfied, this will be the same as the point on body 1. """ cdef dVector3 p dJointGetHinge2Anchor2(self.jid, p) return p[0], p[1], p[2] # setAxis1 def setAxis1(self, axis): """setAxis1(axis) Set the first hinge-2 axis. Axis 1 and axis 2 must not lie along the same line. @param axis: Joint axis @type axis: 3-sequence of floats """ dJointSetHinge2Axis1(self.jid, axis[0], axis[1], axis[2]) # getAxis1 def getAxis1(self): """getAxis1() -> 3-tuple of floats Get the first hinge-2 axis. """ cdef dVector3 a dJointGetHinge2Axis1(self.jid, a) return a[0], a[1], a[2] # setAxis2 def setAxis2(self, axis): """setAxis2(axis) Set the second hinge-2 axis. Axis 1 and axis 2 must not lie along the same line. @param axis: Joint axis @type axis: 3-sequence of floats """ dJointSetHinge2Axis2(self.jid, axis[0], axis[1], axis[2]) # getAxis2 def getAxis2(self): """getAxis2() -> 3-tuple of floats Get the second hinge-2 axis. """ cdef dVector3 a dJointGetHinge2Axis2(self.jid, a) return a[0], a[1], a[2] # getAngle def getAngle1(self): """getAngle1() -> float Get the first hinge-2 angle (around axis 1). When the anchor or axis is set, the current position of the attached bodies is examined and that position will be the zero angle. """ return dJointGetHinge2Angle1(self.jid) # getAngle1Rate def getAngle1Rate(self): """getAngle1Rate() -> float Get the time derivative of the first hinge-2 angle. """ return dJointGetHinge2Angle1Rate(self.jid) # getAngle2Rate def getAngle2Rate(self): """getAngle2Rate() -> float Get the time derivative of the second hinge-2 angle. """ return dJointGetHinge2Angle2Rate(self.jid) # addTorques def addTorques(self, torque1, torque2): """addTorques(torque1, torque2) Applies torque1 about axis 1, and torque2 about axis 2. @param torque1: Torque 1 magnitude @param torque2: Torque 2 magnitude @type torque1: float @type torque2: float """ dJointAddHinge2Torques(self.jid, torque1, torque2) # setParam def setParam(self, param, value): dJointSetHinge2Param(self.jid, param, value) # getParam def getParam(self, param): return dJointGetHinge2Param(self.jid, param) # FixedJoint cdef class FixedJoint(Joint): """Fixed joint. Constructor:: FixedJoint(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateFixed(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setFixed def setFixed(self): """setFixed() Call this on the fixed joint after it has been attached to remember the current desired relative offset and desired relative rotation between the bodies. """ dJointSetFixed(self.jid) # ContactJoint cdef class ContactJoint(Joint): """Contact joint. Constructor:: ContactJoint(world, jointgroup, contact) """ def __cinit__(self, World world not None, jointgroup, Contact contact): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateContact(world.wid, jgid, &contact._contact) def __init__(self, World world not None, jointgroup, Contact contact): self.world = world if jointgroup != None: jointgroup._addjoint(self) # AMotor cdef class AMotor(Joint): """AMotor joint. Constructor:: AMotor(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateAMotor(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setMode def setMode(self, mode): """setMode(mode) Set the angular motor mode. mode must be either AMotorUser or AMotorEuler. @param mode: Angular motor mode @type mode: int """ dJointSetAMotorMode(self.jid, mode) # getMode def getMode(self): """getMode() Return the angular motor mode (AMotorUser or AMotorEuler). """ return dJointGetAMotorMode(self.jid) # setNumAxes def setNumAxes(self, int num): """setNumAxes(num) Set the number of angular axes that will be controlled by the AMotor. num may be in the range from 0 to 3. @param num: Number of axes (0-3) @type num: int """ dJointSetAMotorNumAxes(self.jid, num) # getNumAxes def getNumAxes(self): """getNumAxes() -> int Get the number of angular axes that are controlled by the AMotor. """ return dJointGetAMotorNumAxes(self.jid) # setAxis def setAxis(self, int anum, int rel, axis): """setAxis(anum, rel, axis) Set an AMotor axis. The anum argument selects the axis to change (0,1 or 2). Each axis can have one of three "relative orientation" modes, selected by rel: 0: The axis is anchored to the global frame. 1: The axis is anchored to the first body. 2: The axis is anchored to the second body. The axis vector is always specified in global coordinates regardless of the setting of rel. @param anum: Axis number @param rel: Relative orientation mode @param axis: Axis @type anum: int @type rel: int @type axis: 3-sequence of floats """ dJointSetAMotorAxis(self.jid, anum, rel, axis[0], axis[1], axis[2]) # getAxis def getAxis(self, int anum): """getAxis(anum) Get an AMotor axis. @param anum: Axis index (0-2) @type anum: int """ cdef dVector3 a dJointGetAMotorAxis(self.jid, anum, a) return a[0], a[1], a[2] # getAxisRel def getAxisRel(self, int anum): """getAxisRel(anum) -> int Get the relative mode of an axis. @param anum: Axis index (0-2) @type anum: int """ return dJointGetAMotorAxisRel(self.jid, anum) # setAngle def setAngle(self, int anum, angle): """setAngle(anum, angle) Tell the AMotor what the current angle is along axis anum. @param anum: Axis index @param angle: Angle @type anum: int @type angle: float """ dJointSetAMotorAngle(self.jid, anum, angle) # getAngle def getAngle(self, int anum): """getAngle(anum) -> float Return the current angle for axis anum. @param anum: Axis index @type anum: int """ return dJointGetAMotorAngle(self.jid, anum) # getAngleRate def getAngleRate(self, int anum): """getAngleRate(anum) -> float Return the current angle rate for axis anum. @param anum: Axis index @type anum: int """ return dJointGetAMotorAngleRate(self.jid, anum) # addTorques def addTorques(self, torque0, torque1, torque2): """addTorques(torque0, torque1, torque2) Applies torques about the AMotor's axes. @param torque0: Torque 0 magnitude @param torque1: Torque 1 magnitude @param torque2: Torque 2 magnitude @type torque0: float @type torque1: float @type torque2: float """ dJointAddAMotorTorques(self.jid, torque0, torque1, torque2) # setParam def setParam(self, param, value): dJointSetAMotorParam(self.jid, param, value) # getParam def getParam(self, param): return dJointGetAMotorParam(self.jid, param) # LMotor cdef class LMotor(Joint): """LMotor joint. Constructor:: LMotor(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreateLMotor(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) # setNumAxes def setNumAxes(self, int num): """setNumAxes(num) Set the number of angular axes that will be controlled by the LMotor. num may be in the range from 0 to 3. @param num: Number of axes (0-3) @type num: int """ dJointSetLMotorNumAxes(self.jid, num) # getNumAxes def getNumAxes(self): """getNumAxes() -> int Get the number of angular axes that are controlled by the LMotor. """ return dJointGetLMotorNumAxes(self.jid) # setAxis def setAxis(self, int anum, int rel, axis): """setAxis(anum, rel, axis) Set an LMotor axis. The anum argument selects the axis to change (0,1 or 2). Each axis can have one of three "relative orientation" modes, selected by rel: 0: The axis is anchored to the global frame. 1: The axis is anchored to the first body. 2: The axis is anchored to the second body. @param anum: Axis number @param rel: Relative orientation mode @param axis: Axis @type anum: int @type rel: int @type axis: 3-sequence of floats """ dJointSetLMotorAxis(self.jid, anum, rel, axis[0], axis[1], axis[2]) # getAxis def getAxis(self, int anum): """getAxis(anum) Get an LMotor axis. @param anum: Axis index (0-2) @type anum: int """ cdef dVector3 a dJointGetLMotorAxis(self.jid, anum, a) return a[0], a[1], a[2] # setParam def setParam(self, param, value): dJointSetLMotorParam(self.jid, param, value) # getParam def getParam(self, param): return dJointGetLMotorParam(self.jid, param) # Plane2DJoint cdef class Plane2DJoint(Joint): """Plane-2D Joint. Constructor:: Plane2DJoint(world, jointgroup=None) """ def __cinit__(self, World world not None, jointgroup=None): cdef JointGroup jg cdef dJointGroupID jgid jgid = NULL if jointgroup != None: jg = jointgroup jgid = jg.gid self.jid = dJointCreatePlane2D(world.wid, jgid) def __init__(self, World world not None, jointgroup=None): self.world = world if jointgroup != None: jointgroup._addjoint(self) def setXParam(self, param, value): dJointSetPlane2DXParam(self.jid, param, value) def setYParam(self, param, value): dJointSetPlane2DYParam(self.jid, param, value) def setAngleParam(self, param, value): dJointSetPlane2DAngleParam(self.jid, param, value) # Geom base class cdef class GeomObject: """This is the abstract base class for all geom objects. """ # The id of the geom object as returned by dCreateXxxx() cdef dGeomID gid # The space in which the geom was placed (or None). This reference # is kept so that the space won't be destroyed while there are still # geoms around that might use it. cdef object space # The body that the geom was attached to (or None). cdef object body # A dictionary with user defined attributes cdef object attribs cdef object __weakref__ def __cinit__(self, *a, **kw): self.gid = NULL self.space = None self.body = None self.attribs = {} def __init__(self, *a, **kw): raise NotImplementedError( "GeomObject base class can't be used directly") def __dealloc__(self): if self.gid != NULL: dGeomDestroy(self.gid) self.gid = NULL def __getattr__(self, name): if name in self.attribs: return self.attribs[name] else: raise AttributeError("geom has no attribute '%s'" % name) def __setattr__(self, name, val): self.attribs[name] = val def __delattr__(self, name): if name in self.attribs: del self.attribs[name] else: raise AttributeError("geom has no attribute '%s'" % name) def _id(self): """_id() -> int Return the internal id of the geom (dGeomID) as returned by the dCreateXyz() functions. This method has to be overwritten in derived methods. """ raise NotImplementedError("Bug: The _id() method is not implemented") def placeable(self): """placeable() -> bool Returns True if the geom object is a placeable geom. This method has to be overwritten in derived methods. """ return False def setBody(self, Body body): """setBody(body) Set the body associated with a placeable geom. @param body: The Body object or None. @type body: Body """ if not self.placeable(): raise ValueError( "Non-placeable geoms cannot have a body associated to them") if body == None: dGeomSetBody(self.gid, NULL) else: dGeomSetBody(self.gid, body.bid) self.body = body def getBody(self): """getBody() -> Body Get the body associated with this geom. """ if not self.placeable(): return environment return self.body def setPosition(self, pos): """setPosition(pos) Set the position of the geom. If the geom is attached to a body, the body's position will also be changed. @param pos: Position @type pos: 3-sequence of floats """ if not self.placeable(): raise ValueError("Cannot set a position on non-placeable geoms") dGeomSetPosition(self.gid, pos[0], pos[1], pos[2]) def getPosition(self): """getPosition() -> 3-tuple Get the current position of the geom. If the geom is attached to a body the returned value is the body's position. """ if not self.placeable(): raise ValueError("Non-placeable geoms do not have a position") cdef dReal* p p = dGeomGetPosition(self.gid) return p[0], p[1], p[2] def setRotation(self, R): """setRotation(R) Set the orientation of the geom. If the geom is attached to a body, the body's orientation will also be changed. @param R: Rotation matrix @type R: 9-sequence of floats """ if not self.placeable(): raise ValueError("Cannot set a rotation on non-placeable geoms") cdef dMatrix3 m m[0] = R[0] m[1] = R[1] m[2] = R[2] m[3] = 0 m[4] = R[3] m[5] = R[4] m[6] = R[5] m[7] = 0 m[8] = R[6] m[9] = R[7] m[10] = R[8] m[11] = 0 dGeomSetRotation(self.gid, m) def getRotation(self): """getRotation() -> 9-tuple Get the current orientation of the geom. If the geom is attached to a body the returned value is the body's orientation. """ if not self.placeable(): raise ValueError("Non-placeable geoms do not have a rotation") cdef dReal* m m = dGeomGetRotation(self.gid) return [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]] def getQuaternion(self): """getQuaternion() -> (w,x,y,z) Get the current orientation of the geom. If the geom is attached to a body the returned value is the body's orientation. """ if not self.placeable(): raise ValueError("Non-placeable geoms do not have an orientation") cdef dQuaternion q dGeomGetQuaternion(self.gid, q) return q[0], q[1], q[2], q[3] def setQuaternion(self, q): """setQuaternion(q) Set the orientation of the geom. If the geom is attached to a body, the body's orientation will also be changed. @param q: Quaternion (w,x,y,z) @type q: 4-sequence of floats """ if not self.placeable(): raise ValueError("Cannot set a quaternion on non-placeable geoms") cdef dQuaternion cq cq[0] = q[0] cq[1] = q[1] cq[2] = q[2] cq[3] = q[3] dGeomSetQuaternion(self.gid, cq) def setOffsetPosition(self, pos): """setOffsetPosition(pos) Set the offset position of the geom. The geom must be attached to a body. If the geom did not have an offset, it is automatically created. This sets up an additional (local) transformation for the geom, since geoms attached to a body share their global position and rotation. @param pos: Position @type pos: 3-sequence of floats """ if self.body == None: raise ValueError("Cannot set an offset position on a geom before " "calling setBody") dGeomSetOffsetPosition(self.gid, pos[0], pos[1], pos[2]) def getOffsetPosition(self): """getOffsetPosition() -> 3-tuple Get the offset position of the geom. """ cdef dReal* p p = dGeomGetOffsetPosition(self.gid) return (p[0],p[1],p[2]) def setOffsetRotation(self, R): """setOffsetRotation(R) Set the offset rotation of the geom. The geom must be attached to a body. If the geom did not have an offset, it is automatically created. This sets up an additional (local) transformation for the geom, since geoms attached to a body share their global position and rotation. @param R: Rotation matrix @type R: 9-sequence of floats """ if self.body == None: raise ValueError("Cannot set an offset rotation on a geom before " "calling setBody") cdef dMatrix3 m m[0] = R[0] m[1] = R[1] m[2] = R[2] m[3] = 0 m[4] = R[3] m[5] = R[4] m[6] = R[5] m[7] = 0 m[8] = R[6] m[9] = R[7] m[10] = R[8] m[11] = 0 dGeomSetOffsetRotation(self.gid, m) def getOffsetRotation(self): """getOffsetRotation() -> 9-tuple Get the offset rotation of the geom. """ cdef dReal* m m = dGeomGetOffsetRotation(self.gid) return [m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10]] def clearOffset(self): """clearOffset() Disable the offset transform of the geom. """ dGeomClearOffset(self.gid) def getAABB(self): """getAABB() -> 6-tuple Return an axis aligned bounding box that surrounds the geom. The return value is a 6-tuple (minx, maxx, miny, maxy, minz, maxz). """ cdef dReal aabb[6] dGeomGetAABB(self.gid, aabb) return aabb[0], aabb[1], aabb[2], aabb[3], aabb[4], aabb[5] def isSpace(self): """isSpace() -> bool Return 1 if the given geom is a space, or 0 if not.""" return dGeomIsSpace(self.gid) def getSpace(self): """getSpace() -> Space Return the space that the given geometry is contained in, or return None if it is not contained in any space.""" return self.space def setCollideBits(self, bits): """setCollideBits(bits) Set the "collide" bitfields for this geom. @param bits: Collide bit field @type bits: int/long """ dGeomSetCollideBits(self.gid, long(bits)) def setCategoryBits(self, bits): """setCategoryBits(bits) Set the "category" bitfields for this geom. @param bits: Category bit field @type bits: int/long """ dGeomSetCategoryBits(self.gid, long(bits)) def getCollideBits(self): """getCollideBits() -> long Return the "collide" bitfields for this geom. """ return dGeomGetCollideBits(self.gid) def getCategoryBits(self): """getCategoryBits() -> long Return the "category" bitfields for this geom. """ return dGeomGetCategoryBits(self.gid) def enable(self): """enable() Enable the geom.""" dGeomEnable(self.gid) def disable(self): """disable() Disable the geom.""" dGeomDisable(self.gid) def isEnabled(self): """isEnabled() -> bool Return True if the geom is enabled.""" return dGeomIsEnabled(self.gid) # _SpaceIterator class _SpaceIterator: """Iterates over the geoms inside a Space. """ def __init__(self, space): self.space = space self.idx = 0 def __iter__(self): return self def next(self): if self.idx >= self.space.getNumGeoms(): raise StopIteration else: res = self.space.getGeom(self.idx) self.idx = self.idx + 1 return res # SpaceBase cdef class SpaceBase(GeomObject): """Space class (container for geometry objects). A Space object is a container for geometry objects which are used to do collision detection. The space does high level collision culling, which means that it can identify which pairs of geometry objects are potentially touching. This Space class can be used for both, a SimpleSpace and a HashSpace (see ODE documentation). >>> space = Space(type=0) # Create a SimpleSpace >>> space = Space(type=1) # Create a HashSpace """ # The id of the space. Actually this is a copy of the value in self.gid # (as the Space is derived from GeomObject) which can be used without # casting whenever a *space* id is required. cdef dSpaceID sid # Dictionary with Geomobjects. Key is the ID (geom._id()) and the value # is the geom object (Python wrapper). This is used in collide_callback() # cdef object geom_dict def __cinit__(self, *a, **kw): pass def __init__(self, *a, **kw): raise NotImplementedError("The SpaceBase class can't be used directly") def __dealloc__(self): if self.gid != NULL: dSpaceDestroy(self.sid) self.sid = NULL self.gid = NULL # def _addgeom(self, geom): # """Insert the geom object into the dictionary (internal method). # # This method has to called in the constructor of a geom object. # """ # self.geom_dict[geom._id()]=geom # def _id2geom(self, id): # """Get the Python wrapper that corresponds to an ID. # # The ID is the integer value, as returned by geom._id(). # If the ID is unknown then None is returned. # """ # if id in self.geom_dict: # return self.geom_dict[id] # else: # return None def _id(self): cdef long id id = self.sid return id def __len__(self): return self.getNumGeoms() def __iter__(self): return _SpaceIterator(self) def add(self, GeomObject geom): """add(geom) Add a geom to a space. This does nothing if the geom is already in the space. @param geom: Geom object to add @type geom: GeomObject """ dSpaceAdd(self.sid, geom.gid) def remove(self, GeomObject geom): """remove(geom) Remove a geom from a space. @param geom: Geom object to remove @type geom: GeomObject """ dSpaceRemove(self.sid, geom.gid) def query(self, GeomObject geom): """query(geom) -> bool Return True if the given geom is in the space. @param geom: Geom object to check @type geom: GeomObject """ return dSpaceQuery(self.sid, geom.gid) def getNumGeoms(self): """getNumGeoms() -> int Return the number of geoms contained within the space. """ return dSpaceGetNumGeoms(self.sid) def getGeom(self, int idx): """getGeom(idx) -> GeomObject Return the geom with the given index contained within the space. @param idx: Geom index (0,1,...,getNumGeoms()-1) @type idx: int """ cdef dGeomID gid # Check the index if idx < 0 or idx >= dSpaceGetNumGeoms(self.sid): raise IndexError("geom index out of range") gid = dSpaceGetGeom(self.sid, idx) if gid not in _geom_c2py_lut: raise RuntimeError( "geom id cannot be translated to a Python object") return _geom_c2py_lut[gid] def collide(self, arg, callback): """collide(arg, callback) Call a callback function one or more times, for all potentially intersecting objects in the space. The callback function takes 3 arguments: def NearCallback(arg, geom1, geom2): The arg parameter is just passed on to the callback function. Its meaning is user defined. The geom1 and geom2 arguments are the geometry objects that may be near each other. The callback function can call the function collide() (not the Space method) on geom1 and geom2, perhaps first determining whether to collide them at all based on other information. @param arg: A user argument that is passed to the callback function @param callback: Callback function @type callback: callable """ cdef void* data cdef object tup tup = (callback, arg) data = tup dSpaceCollide(self.sid, data, collide_callback) # Callback function for the dSpaceCollide() call in the Space.collide() method # The data parameter is a tuple (Python-Callback, Arguments). # The function calls a Python callback function with 3 arguments: # def callback(UserArg, Geom1, Geom2) # Geom1 and Geom2 are instances of GeomXyz classes. cdef void collide_callback(void* data, dGeomID o1, dGeomID o2): cdef object tup # cdef Space space cdef long id1, id2 # if (dGeomGetBody(o1)==dGeomGetBody(o2)): # return tup = data callback, arg = tup id1 = o1 id2 = o2 g1 = _geom_c2py_lut[id1] g2 = _geom_c2py_lut[id2] callback(arg, g1, g2) # SimpleSpace cdef class SimpleSpace(SpaceBase): """Simple space. This does not do any collision culling - it simply checks every possible pair of geoms for intersection, and reports the pairs whose AABBs overlap. The time required to do intersection testing for n objects is O(n**2). This should not be used for large numbers of objects, but it can be the preferred algorithm for a small number of objects. This is also useful for debugging potential problems with the collision system. """ def __cinit__(self, space=None): cdef SpaceBase sp cdef dSpaceID parentid parentid = NULL if space != None: sp = space parentid = sp.sid self.sid = dSimpleSpaceCreate(parentid) # Copy the ID self.gid = self.sid dSpaceSetCleanup(self.sid, 0) _geom_c2py_lut[self.sid] = self def __init__(self, space=None): pass # HashSpace cdef class HashSpace(SpaceBase): """Multi-resolution hash table space. This uses an internal data structure that records how each geom overlaps cells in one of several three dimensional grids. Each grid has cubical cells of side lengths 2**i, where i is an integer that ranges from a minimum to a maximum value. The time required to do intersection testing for n objects is O(n) (as long as those objects are not clustered together too closely), as each object can be quickly paired with the objects around it. """ def __cinit__(self, space=None): cdef SpaceBase sp cdef dSpaceID parentid parentid = NULL if space != None: sp = space parentid = sp.sid self.sid = dHashSpaceCreate(parentid) # Copy the ID self.gid = self.sid dSpaceSetCleanup(self.sid, 0) _geom_c2py_lut[self.sid] = self def __init__(self, space=None): pass def setLevels(self, int minlevel, int maxlevel): """setLevels(minlevel, maxlevel) Sets the size of the smallest and largest cell used in the hash table. The actual size will be 2^minlevel and 2^maxlevel respectively. """ if minlevel > maxlevel: raise ValueError( "minlevel (%d) must be less than or equal to maxlevel (%d)" % (minlevel, maxlevel)) dHashSpaceSetLevels(self.sid, minlevel, maxlevel) def getLevels(self): """getLevels() -> (minlevel, maxlevel) Gets the size of the smallest and largest cell used in the hash table. The actual size is 2^minlevel and 2^maxlevel respectively. """ cdef int minlevel cdef int maxlevel dHashSpaceGetLevels(self.sid, &minlevel, &maxlevel) return minlevel, maxlevel # QuadTreeSpace cdef class QuadTreeSpace(SpaceBase): """Quadtree space. This uses a pre-allocated hierarchical grid-based AABB tree to quickly cull collision checks. It's exceptionally quick for large amounts of objects in landscape-shaped worlds. The amount of memory used is 4**depth * 32 bytes. Currently getGeom() is not implemented for the quadtree space. """ def __cinit__(self, center, extents, depth, space=None): cdef SpaceBase sp cdef dSpaceID parentid cdef dVector3 c cdef dVector3 e parentid = NULL if space != None: sp = space parentid = sp.sid c[0] = center[0] c[1] = center[1] c[2] = center[2] e[0] = extents[0] e[1] = extents[1] e[2] = extents[2] self.sid = dQuadTreeSpaceCreate(parentid, c, e, depth) # Copy the ID self.gid = self.sid dSpaceSetCleanup(self.sid, 0) _geom_c2py_lut[self.sid] = self def __init__(self, center, extents, depth, space=None): pass def Space(space_type=0): """Space factory function. Depending on the type argument this function either returns a SimpleSpace (space_type=0) or a HashSpace (space_type=1). This function is provided to remain compatible with previous versions of PyODE where there was only one Space class. >>> space = Space(space_type=0) # Create a SimpleSpace >>> space = Space(space_type=1) # Create a HashSpace """ if space_type == 0: return SimpleSpace() elif space_type == 1: return HashSpace() else: raise ValueError("Unknown space type (%d)" % space_type) # GeomSphere cdef class GeomSphere(GeomObject): """Sphere geometry. This class represents a sphere centered at the origin. Constructor:: GeomSphere(space=None, radius=1.0) """ def __cinit__(self, space=None, radius=1.0): cdef SpaceBase sp cdef dSpaceID sid sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreateSphere(sid, radius) # if space != None: # space._addgeom(self) _geom_c2py_lut[self.gid] = self def __init__(self, space=None, radius=1.0): self.space = space self.body = None def placeable(self): return True def _id(self): cdef long id id = self.gid return id def setRadius(self, radius): """setRadius(radius) Set the radius of the sphere. @param radius: New radius @type radius: float """ dGeomSphereSetRadius(self.gid, radius) def getRadius(self): """getRadius() -> float Return the radius of the sphere. """ return dGeomSphereGetRadius(self.gid) def pointDepth(self, p): """pointDepth(p) -> float Return the depth of the point p in the sphere. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. @param p: Point @type p: 3-sequence of floats """ return dGeomSpherePointDepth(self.gid, p[0], p[1], p[2]) # GeomBox cdef class GeomBox(GeomObject): """Box geometry. This class represents a box centered at the origin. Constructor:: GeomBox(space=None, lengths=(1.0, 1.0, 1.0)) """ def __cinit__(self, space=None, lengths=(1.0, 1.0, 1.0)): cdef SpaceBase sp cdef dSpaceID sid sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreateBox(sid, lengths[0], lengths[1], lengths[2]) # if space != None: # space._addgeom(self) _geom_c2py_lut[self.gid] = self def __init__(self, space=None, lengths=(1.0, 1.0, 1.0)): self.space = space self.body = None def placeable(self): return True def _id(self): cdef long id id = self.gid return id def setLengths(self, lengths): dGeomBoxSetLengths(self.gid, lengths[0], lengths[1], lengths[2]) def getLengths(self): cdef dVector3 res dGeomBoxGetLengths(self.gid, res) return res[0], res[1], res[2] def pointDepth(self, p): """pointDepth(p) -> float Return the depth of the point p in the box. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. @param p: Point @type p: 3-sequence of floats """ return dGeomBoxPointDepth(self.gid, p[0], p[1], p[2]) # GeomPlane cdef class GeomPlane(GeomObject): """Plane geometry. This class represents an infinite plane. The plane equation is: n.x*x + n.y*y + n.z*z = dist This object can't be attached to a body. If you call getBody() on this object it always returns ode.environment. Constructor:: GeomPlane(space=None, normal=(0,0,1), dist=0) """ def __cinit__(self, space=None, normal=(0, 0, 1), dist=0): cdef SpaceBase sp cdef dSpaceID sid sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreatePlane(sid, normal[0], normal[1], normal[2], dist) # if space != None: # space._addgeom(self) _geom_c2py_lut[self.gid] = self def __init__(self, space=None, normal=(0, 0, 1), dist=0): self.space = space def _id(self): cdef long id id = self.gid return id def setParams(self, normal, dist): dGeomPlaneSetParams(self.gid, normal[0], normal[1], normal[2], dist) def getParams(self): cdef dVector4 res dGeomPlaneGetParams(self.gid, res) return ((res[0], res[1], res[2]), res[3]) def pointDepth(self, p): """pointDepth(p) -> float Return the depth of the point p in the plane. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. @param p: Point @type p: 3-sequence of floats """ return dGeomPlanePointDepth(self.gid, p[0], p[1], p[2]) # GeomCapsule cdef class GeomCapsule(GeomObject): """Capped cylinder geometry. This class represents a capped cylinder aligned along the local Z axis and centered at the origin. Constructor:: GeomCapsule(space=None, radius=0.5, length=1.0) The length parameter does not include the caps. """ def __cinit__(self, space=None, radius=0.5, length=1.0): cdef SpaceBase sp cdef dSpaceID sid sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreateCapsule(sid, radius, length) # if space != None: # space._addgeom(self) _geom_c2py_lut[self.gid] = self def __init__(self, space=None, radius=0.5, length=1.0): self.space = space self.body = None def placeable(self): return True def _id(self): cdef long id id = self.gid return id def setParams(self, radius, length): dGeomCapsuleSetParams(self.gid, radius, length) def getParams(self): cdef dReal radius, length dGeomCapsuleGetParams(self.gid, &radius, &length) return radius, length def pointDepth(self, p): """pointDepth(p) -> float Return the depth of the point p in the cylinder. Points inside the geom will have positive depth, points outside it will have negative depth, and points on the surface will have zero depth. @param p: Point @type p: 3-sequence of floats """ return dGeomCapsulePointDepth(self.gid, p[0], p[1], p[2]) GeomCCylinder = GeomCapsule # backwards compatibility # GeomCylinder cdef class GeomCylinder(GeomObject): """Plain cylinder geometry. This class represents an uncapped cylinder aligned along the local Z axis and centered at the origin. Constructor:: GeomCylinder(space=None, radius=0.5, length=1.0) """ def __cinit__(self, space=None, radius=0.5, length=1.0): cdef SpaceBase sp cdef dSpaceID sid sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreateCylinder(sid, radius, length) # if space != None: # space._addgeom(self) _geom_c2py_lut[self.gid] = self def __init__(self, space=None, radius=0.5, length=1.0): self.space = space self.body = None def placeable(self): return True def _id(self): cdef long id id = self.gid return id def setParams(self, radius, length): dGeomCylinderSetParams(self.gid, radius, length) def getParams(self): cdef dReal radius, length dGeomCylinderGetParams(self.gid, &radius, &length) return radius, length ## dGeomCylinderPointDepth not implemented upstream in ODE 0.7 # GeomRay cdef class GeomRay(GeomObject): """Ray object. A ray is different from all the other geom classes in that it does not represent a solid object. It is an infinitely thin line that starts from the geom's position and extends in the direction of the geom's local Z-axis. Constructor:: GeomRay(space=None, rlen=1.0) """ def __cinit__(self, space=None, rlen=1.0): cdef SpaceBase sp cdef dSpaceID sid sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreateRay(sid, rlen) # if space != None: # space._addgeom(self) _geom_c2py_lut[self.gid] = self def __init__(self, space=None, rlen=1.0): self.space = space self.body = None def _id(self): cdef long id id = self.gid return id def placeable(self): return True def setLength(self, rlen): '''setLength(rlen) Set length of the ray. @param rlen: length of the ray @type rlen: float''' dGeomRaySetLength(self.gid, rlen) def getLength(self): '''getLength() -> length Get the length of the ray. @returns: length of the ray (float)''' return dGeomRayGetLength(self.gid) def set(self, p, u): '''set(p, u) Set the position and rotation of a ray. @param p: position @type p: 3-sequence of floats @param u: rotation @type u: 3-sequence of floats''' dGeomRaySet(self.gid, p[0], p[1], p[2], u[0], u[1], u[2]) def get(self): '''get() -> ((p[0], p[1], p[2]), (u[0], u[1], u[2])) Return the position and rotation as a pair of tuples. @returns: position and rotation''' cdef dVector3 start cdef dVector3 dir dGeomRayGet(self.gid, start, dir) return (start[0], start[1], start[2]), (dir[0], dir[1], dir[2]) # GeomTransform cdef class GeomTransform(GeomObject): """GeomTransform. A geometry transform "T" is a geom that encapsulates another geom "E", allowing E to be positioned and rotated arbitrarily with respect to its point of reference. Constructor:: GeomTransform(space=None) """ cdef object geom def __cinit__(self, space=None): cdef SpaceBase sp cdef dSpaceID sid sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreateGeomTransform(sid) # Set cleanup mode to 0 as a contained geom will be deleted # by its Python wrapper class dGeomTransformSetCleanup(self.gid, 0) # if space != None: # space._addgeom(self) _geom_c2py_lut[self.gid] = self def __init__(self, space=None): self.space = space self.body = None self.geom = None self.attribs = {} def placeable(self): return True def _id(self): cdef long id id = self.gid return id def setGeom(self, GeomObject geom not None): """setGeom(geom) Set the geom that the geometry transform encapsulates. A ValueError exception is thrown if a) the geom is not placeable, b) the geom was already inserted into a space or c) the geom is already associated with a body. @param geom: Geom object to encapsulate @type geom: GeomObject """ cdef long id if not geom.placeable(): raise ValueError( "Only placeable geoms can be encapsulated by a GeomTransform") if dGeomGetSpace(geom.gid) != 0: raise ValueError( "The encapsulated geom was already inserted into a space") if dGeomGetBody(geom.gid) != 0: raise ValueError( "The encapsulated geom is already associated with a body") id = geom._id() dGeomTransformSetGeom(self.gid, id) self.geom = geom def getGeom(self): """getGeom() -> GeomObject Get the geom that the geometry transform encapsulates. """ return self.geom def setInfo(self, int mode): """setInfo(mode) Set the "information" mode of the geometry transform. With mode 0, when a transform object is collided with another object, the geom field of the ContactGeom structure is set to the geom that is encapsulated by the transform object. With mode 1, the geom field of the ContactGeom structure is set to the transform object itself. @param mode: Information mode (0 or 1) @type mode: int """ if mode < 0 or mode > 1: raise ValueError( "Invalid information mode (%d). Must be either 0 or 1." % mode) dGeomTransformSetInfo(self.gid, mode) def getInfo(self): """getInfo() -> int Get the "information" mode of the geometry transform (0 or 1). With mode 0, when a transform object is collided with another object, the geom field of the ContactGeom structure is set to the geom that is encapsulated by the transform object. With mode 1, the geom field of the ContactGeom structure is set to the transform object itself. """ return dGeomTransformGetInfo(self.gid) ###################################################################### cdef class TriMeshData: """This class stores the mesh data. """ cdef dTriMeshDataID tmdid cdef dReal* vertex_buffer cdef int* face_buffer def __cinit__(self): self.tmdid = dGeomTriMeshDataCreate() self.vertex_buffer = NULL self.face_buffer = NULL def __dealloc__(self): if self.tmdid != NULL: dGeomTriMeshDataDestroy(self.tmdid) if self.vertex_buffer != NULL: free(self.vertex_buffer) if self.face_buffer != NULL: free(self.face_buffer) def build(self, verts, faces): """build(verts, faces) @param verts: Vertices @type verts: Sequence of 3-sequences of floats @param faces: Face definitions (three indices per face) @type faces: Sequence of 3-sequences of ints """ cdef int numverts cdef int numfaces cdef dReal* vp cdef int* fp cdef int a, b, c numverts = len(verts) numfaces = len(faces) # Allocate the vertex and face buffer self.vertex_buffer = malloc(numverts * 4 * sizeof(dReal)) self.face_buffer = malloc(numfaces * 3 * sizeof(int)) # Fill the vertex buffer vp = self.vertex_buffer for v in verts: vp[0] = v[0] vp[1] = v[1] vp[2] = v[2] vp[3] = 0 vp = vp + 4 # Fill the face buffer fp = self.face_buffer for f in faces: a = f[0] b = f[1] c = f[2] if (a < 0 or b < 0 or c < 0 or a >= numverts or b >= numverts or c >= numverts): raise ValueError("Vertex index out of range") fp[0] = a fp[1] = b fp[2] = c fp = fp + 3 # Pass the data to ODE dGeomTriMeshDataBuildSimple(self.tmdid, self.vertex_buffer, numverts, self.face_buffer, numfaces * 3) ###################################################################### # GeomTriMesh cdef class GeomTriMesh(GeomObject): """TriMesh object. To construct the trimesh geom you need a TriMeshData object that stores the actual mesh. This object has to be passed as first argument to the constructor. Constructor:: GeomTriMesh(data, space=None) """ # Keep a reference to the data cdef TriMeshData data def __cinit__(self, TriMeshData data not None, space=None): cdef SpaceBase sp cdef dSpaceID sid self.data = data sid = NULL if space != None: sp = space sid = sp.sid self.gid = dCreateTriMesh(sid, data.tmdid, NULL, NULL, NULL) _geom_c2py_lut[self.gid] = self def __init__(self, TriMeshData data not None, space=None): self.space = space self.body = None def placeable(self): return True def _id(self): cdef long id id = self.gid return id def clearTCCache(self): """clearTCCache() Clears the internal temporal coherence caches. """ dGeomTriMeshClearTCCache(self.gid) def getTriangle(self, int idx): """getTriangle(idx) -> (v0, v1, v2) @param idx: Triangle index @type idx: int """ cdef dVector3 v0, v1, v2 cdef dVector3* vp0 cdef dVector3* vp1 cdef dVector3* vp2 vp0 = v0 vp1 = v1 vp2 = v2 dGeomTriMeshGetTriangle(self.gid, idx, vp0, vp1, vp2) return ((v0[0], v0[1], v0[2]), (v1[0], v1[1], v1[2]), (v2[0], v2[1], v2[2])) def getTriangleCount(self): """getTriangleCount() -> n Returns the number of triangles in the TriMesh.""" return dGeomTriMeshGetTriangleCount(self.gid) ###################################################################### def collide(geom1, geom2): """collide(geom1, geom2) -> contacts Generate contact information for two objects. Given two geometry objects that potentially touch (geom1 and geom2), generate contact information for them. Internally, this just calls the correct class-specific collision functions for geom1 and geom2. [flags specifies how contacts should be generated if the objects touch. Currently the lower 16 bits of flags specifies the maximum number of contact points to generate. If this number is zero, this function just pretends that it is one - in other words you can not ask for zero contacts. All other bits in flags must be zero. In the future the other bits may be used to select other contact generation strategies.] If the objects touch, this returns a list of Contact objects, otherwise it returns an empty list. @param geom1: First Geom @type geom1: GeomObject @param geom2: Second Geom @type geom2: GeomObject @returns: Returns a list of Contact objects. """ cdef dContactGeom c[150] cdef long id1 cdef long id2 cdef int i, n cdef Contact cont id1 = geom1._id() id2 = geom2._id() n = dCollide(id1, id2, 150, c, sizeof(dContactGeom)) res = [] i = 0 while i < n: cont = Contact() cont._contact.geom = c[i] res.append(cont) i = i + 1 return res def collide2(geom1, geom2, arg, callback): """collide2(geom1, geom2, arg, callback) Calls the callback for all potentially intersecting pairs that contain one geom from geom1 and one geom from geom2. @param geom1: First Geom @type geom1: GeomObject @param geom2: Second Geom @type geom2: GeomObject @param arg: A user argument that is passed to the callback function @param callback: Callback function @type callback: callable """ cdef void* data cdef object tup cdef long id1 cdef long id2 id1 = geom1._id() id2 = geom2._id() tup = (callback, arg) data = tup # collide_callback is defined in space.pyx dSpaceCollide2(id1, id2, data, collide_callback) def areConnected(Body body1, Body body2): """areConnected(body1, body2) -> bool Return True if the two bodies are connected together by a joint, otherwise return False. @param body1: First body @type body1: Body @param body2: Second body @type body2: Body @returns: True if the bodies are connected """ if body1 is environment: return False if body2 is environment: return False return bool(dAreConnected( body1.bid, body2.bid)) def CloseODE(): """CloseODE() Deallocate some extra memory used by ODE that can not be deallocated using the normal destroy functions. """ dCloseODE() def InitODE(): '''InitODE() Initialize some ODE internals. This will be called for you when you "import ode", but you should call this again if you CloseODE().''' dInitODE() #environment = Body(None) environment = None InitODE() ode-0.14/bindings/python/setup.py0000644000000000000000000000335612635011627015545 0ustar rootroot#! /usr/bin/env python from distutils.core import setup from distutils.extension import Extension from subprocess import Popen, PIPE, CalledProcessError try: from Cython.Distutils import build_ext except ImportError: raise SystemExit("Requires Cython (http://cython.org/)") try: ode_cflags = Popen( ["pkg-config", "--cflags", "ode"], stdout=PIPE).stdout.read().decode('ascii').split() ode_libs = Popen( ["pkg-config", "--libs", "ode"], stdout=PIPE).stdout.read().decode('ascii').split() except (OSError, CalledProcessError): raise SystemExit("Failed to find ODE with 'pkg-config'. Please make sure " "that it is installed and available on your system path.") ode_ext = Extension("ode", ["ode.pyx"], extra_compile_args=ode_cflags, extra_link_args=ode_libs) if __name__ == "__main__": setup( name="Open Dynamics Engine", version="0.12", author="Gideon Klompje", # author_email="", # maintainer="", # maintainer_email="", url="http://www.ode.org", description="Bindings for the Open Dynamics Engine", long_description=( "A free, industrial quality library for simulating articulated " "rigid body dynamics - for example ground vehicles, legged " "creatures, and moving objects in VR environments. It's fast, " "flexible & robust. Built-in collision detection."), # download_url="https://opende.svn.sourceforge.net/svnroot/opende", # classifiers=[], # platforms=[], license="BSD License, GNU Lesser General Public License (LGPL)", cmdclass={"build_ext": build_ext}, ext_modules=[ode_ext] ) ode-0.14/bootstrap0000755000000000000000000000140612635011627012652 0ustar rootroot#!/bin/sh echo "Please make sure that you use automake 1.11 or later" echo "Warnings about underquoted definitions are harmless" if [ `uname -s` = Darwin ]; then echo "On OSX, install latest libtool, as the OS provided glibtoolize will not work" fi echo "Running aclocal" aclocal -I m4 --install || exit 1 echo "Running libtoolize" libtoolize --copy --automake --install || exit 1 echo "Running autoheader" autoheader || exit 1 echo "Running automake" automake --foreign --add-missing --copy || exit 1 echo "Running autoconf" autoconf || exit 1 echo "Running bootstrap in ou directory" (cd ou && ./bootstrap) if [ -d libccd ]; then echo "Running bootstrap in libccd directory" (cd libccd && ./bootstrap) fi; echo "Now you are ready to run ./configure" ode-0.14/build/0000775000000000000000000000000012635012023011776 5ustar rootrootode-0.14/build/config-default.h0000644000000000000000000001064712635011627015055 0ustar rootroot/* This file was autogenerated by Premake */ #ifndef _ODE_CONFIG_H_ #define _ODE_CONFIG_H_ /****************************************************************** * CONFIGURATON SETTINGS - you can change these, and then rebuild * ODE to modify the behavior of the library. * * dTRIMESH_ENABLED - enable/disable trimesh support * dTRIMESH_OPCODE - use the OPCODE trimesh engine * dTRIMESH_GIMPACT - use the GIMPACT trimesh engine * Only one trimesh engine should be enabled. * * dTRIMESH_16BIT_INDICES (todo: opcode only) * Setup the trimesh engine to use 16 bit * triangle indices. The default is to use * 32 bit indices. Use the dTriIndex type to * detect the correct index size. * * dTRIMESH_OPCODE_USE_NEWOLD_TRIMESH_TRIMESH_COLLIDER * Use old implementation of trimesh-trimesh collider * (for backward compatibility only) * * dOU_ENABLED * dATOMICS_ENABLED * dTLS_ENABLED * Use generic features of OU library, atomic API * and TLS API respectively. * Generic features and atomic API are always enabled, * unless threading interface support is disabled. * Using TLS for global variables allows calling ODE * collision detection functions from multiple threads. * * dBUILTIN_THREADING_IMPL_ENABLED * Include built-in multithreaded threading * implementation (still must be created and assigned * to be used). * ******************************************************************/ #define dTRIMESH_ENABLED 1 #define dTRIMESH_OPCODE 1 #define dTRIMESH_16BIT_INDICES 0 #define dTRIMESH_OPCODE_USE_OLD_TRIMESH_TRIMESH_COLLIDER 0 /* #define dOU_ENABLED 1 */ /* #define dATOMICS_ENABLED 1 */ /* #define dTLS_ENABLED 1 */ /* #define dTHREADING_INTF_DISABLED 1 */ /* #define dBUILTIN_THREADING_IMPL_ENABLED 1 */ /****************************************************************** * SYSTEM SETTINGS - you shouldn't need to change these. If you * run into an issue with these settings, please report it to * the ODE bug tracker at: * http://sf.net/tracker/?group_id=24884&atid=382799 ******************************************************************/ /* Try to identify the platform */ #if defined(_XENON) #define ODE_PLATFORM_XBOX360 #elif defined(SN_TARGET_PSP_HW) #define ODE_PLATFORM_PSP #elif defined(SN_TARGET_PS3) #define ODE_PLATFORM_PS3 #elif defined(_MSC_VER) || defined(__CYGWIN32__) || defined(__MINGW32__) #define ODE_PLATFORM_WINDOWS #elif defined(__linux__) #define ODE_PLATFORM_LINUX #elif defined(__APPLE__) && defined(__MACH__) #define ODE_PLATFORM_OSX #else #error "Need some help identifying the platform!" #endif /* Additional platform defines used in the code */ #if defined(ODE_PLATFORM_WINDOWS) && !defined(WIN32) #define WIN32 #endif #if defined(__CYGWIN32__) || defined(__MINGW32__) #define CYGWIN #endif #if defined(ODE_PLATFORM_OSX) #define macintosh #endif #if !defined(ODE_PLATFORM_OSX) && !defined(ODE_PLATFORM_PS3) #include #endif #if !defined(ODE_PLATFORM_WINDOWS) #include #endif #ifdef dSINGLE #define dEpsilon FLT_EPSILON #else #define dEpsilon DBL_EPSILON #endif /* An integer type that can be safely cast to a pointer. This definition * should be safe even on 64-bit systems */ typedef size_t intP; /* The efficient alignment. most platforms align data structures to some * number of bytes, but this is not always the most efficient alignment. * for example, many x86 compilers align to 4 bytes, but on a pentium it is * important to align doubles to 8 byte boundaries (for speed), and the 4 * floats in a SIMD register to 16 byte boundaries. many other platforms have * similar behavior. setting a larger alignment can waste a (very) small * amount of memory. NOTE: this number must be a power of two. */ #define EFFICIENT_ALIGNMENT 16 /* Basic OU functionality is required if either atomic API or TLS support * is enabled. */ #if dATOMICS_ENABLED || dTLS_ENABLED #undef dOU_ENABLED #define dOU_ENABLED 1 #endif #include "typedefs.h" #endif ode-0.14/build/premake4.exe0000644000000000000000000077700012635011627014233 0ustar rootrootMZ@ !L!This program cannot be run in DOS mode. $PELmL 8F`@@8Q 0 .textEF``.data`J@.rdatapL@@.bss .idata 0 @U]U1ۉu1=wC=r[$1҉T$d>tzt$л؋u]]=twJ=t؋u]]=t[=u$1t$>tjt$=$L$=v9l$ 1ɉL$=t0R$ ?$D$|=%$ \$b= 'US$]$@Br7m8E DU\$ `AD$T$L$ $ D,=0 Dtc`A2Dt 0 DD$2DK0 $<2Dt&0 D\$ 2DQP$<t&'<`A6f<L$ DT$ D$2<$ BD$2DB$U<2DJv'U$2D&U$2D&U 2D]t&U 2D]ᐐU]8UVuSjjVPfA uVqShpAV_ jV$e[^]ÐUW}VSjjWmjjWajPSAuWVh0pAW jWe[^_]ÐU@S2:Sh@@1҅t-t8\u/@8Pu&]ÐUS0]jjS 8ujEPR4:YZu E%@PjSX]ZÐUEЃ0Pu9Z1҅Yu UɉUS]jjS$P$S]ÐUW}VSjjWhH:Í@PV?SWC|e[^_]USju ZËYtP?S9]1US]jS 4PS]US]jS @PS]UVuSjVt X1;Zt913jV${uCP3>t؀{4.Cu܍e[^]ÐUVuSjjVjP> uV ShPpAVm jV2e[^]UWVSV}EuWf Y[juW\à j;S8^Zt)PSWS S1W Y[jWhppAWm jWjW jjWB PZtjW,jW Y[t CrEW9EZ<1e[^_]ÐUVuSjjVP= uVA ShpAV/  jV e[^]ÐUS@= DuhpAf=hpAPk= DE]P DEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPhpAS7HSu ]ÐUVuSjjV À/\ Шu$t t{:ujV 1e[^]ÐUWVSj=Rd6Y[t/)~SVwP6Ƅ+ V4rAP[6XZV Sjh5rAS6u >t5 De1[^_]UW}VS?1'$PRh$rAh=rAS8hqAhBrAS(h qAhErAS(hLrAS hurAhS&hrASl hrAhS (hrASN hrAhS hrAS3 hrAhS (jjS jjS 9}xU /uP-ux-u PGKE 4FS YXhrAhSh 9}%U 4FS XZjSZ@YPjS FhrA1hS' hsAhS =`AtL4`AS5"ZYujjjStjjS P(4XKF<`Ah sA1hS jjjS<tjfjS P3_Se[^_]ÐUWVSSjjjujjjuEo }1҅…tI}1щYэQ9|(VE)Pd3ZYPuw 1e[^_]U҉S~P D;Qs~Q~ Ajt @HtU,u$@`C@QX@@ BAX'AD@)ЉA9\[]UP;P(u@HB@ ]UVuS] NSCQAN[^]UU W@VuSN+F =@~1+~'F)9 RV_XZFV9BsBe[^_]UE 9EWUVSt=M)A~.1֋U EJXABSNCQAu[^_]UEP4E fP4]UEU HAXQX]US]SB@9BDrS {YSSCB]UU]B+B UM WVuSɋVx*~ 9sBB9؉rFD F[^_]UU VuS^9sQAAQACF[^]UU WVS]^slj9vSCK9PKSVFWG[^_]UW} VuSuF(9Fu h}CVY[XËNu*F@AB Fx~X@@tOBtIPRjSZYt hSXjS[]XUS]jjS1҉jS jSt1jSXZuzSjSjS1.jS?ZYujSZYu hXCSn[X]US]jSjSjjS PSR]US]jjS=jSljSjS]US]jjS jS9jS1jS$jS]US]jjSF PS!]UW}VShChCjWjjWP4CWƋC(tt#*jjWV$$$ CVW=V$$Wue[^_]US]jSLjSfYZPS|YZPS]US]jjSjSqjSu S]US]jjShSjSS]UVuSjVjCjVaSVSjV\(jVYЃ[e[^]US]jjS"hSAjS9jSf]U҉SøtSjS]UEVSV]PjS%jPjSMPuVS"ƒe[^]US]jjjSPSZ‰Y]mUVS]uhCjSjStjjS jSYZu=jSYZt"jSXZuE ]e[^]h*CS[^e1[^]UVS]jhOCjScjjSjSO$VjhD@Se‰[^]UWVuSjjjVVSVtVYjjV Ve)[^_]US]jSmjSt ]]jhWCjSPhiCS]UWVSjjujju)ju$ZY ju ju^1_9@)؍x~WuZYuhlCu]Sju|؃ C9|e[^_]UW}VSWjW u#jjW 8#uFPW2jW"ÅXZy9~hCjW )؍e[^_]US]jSjjSNH$SPS jSYX]]US]jSjSjSjjjSp(PSQjS]]US]jShhCjSjSjZYt.tK[ttOjjS P#jSjSUZCYuCRSt[X?jhCS& -jSZYPjSZYPSZYPhCS]UVuSjVjVgjVjV[HZu*jjVujVPjVhV$LjVZYt$hVjVnjV|uhCjV jVH[XjV[e[^]USӃp19tDSZt Ht1*EPjS" SY҃B]UVuSjVYÅXuhCjV@ ډu4CVe[^]UWVSMuWdZYu hCVYXt4ChCV]uWVWVuW!9w2W$Í@PV u h CV]XZSVWN jVWAe[^_]UVuSjV!ÅXZuhCjVH VHډ$ÅXyjV jV-jCVPV؍e[^]UVuShVVS$ډ y0jVZYtjV$jVjVVYe[^]UVS]SjS ujSZYth;CjSS jSajVSe[^]US]SjhvK@SY]US]Sy$S7]US]S ZtS[]UVSju PjuSVjSe[^]US]hSYXhQChS hChQCS jhTCS h\ChS غeChC@h)D@^XZlChkC@hC@FYXjjSA jSXZjSYXjhrCSP huCjS, jhH@S h|ChS hpChCS]ÐU1҉8uxuxu]UVS]@ )Ӎ4C1)=~hCq \XZ? ‰e[^]UUBB]U@ -tL]UWVSu}E t-u0 Éډuuډ[^_]@[^_]Uҋ@ ~A?DyA]UVSӃt'ډ?tډ?1[^]UV1S]Ѓ?u@t9t?? ډ Ѓ[^]UVSӃthډYډߍe[^]UWVSӃt2ډu ډljFZtuuډ [ɍe[^_]US]S=u C PSa]UEMU ;Hu]͉ME M]qUVuS^$] @K9~~hCv YYXXKe[^]UVu S]VSs$e[^]Uu @29|I$]U: u]R]UWVS @RvEP? x{(u!}E fEm]mEF(@F(@;C(~!hCC(hjPsumC;{(}SDG;{(|F(}COWHP~@tCt PSuH V(BF(Ѝe[^_]UEM UREMUE EEUR]UWVSPEu }E u$^H E@?% ‰RuM^H E@ ‰^G$%?? ‰E }X[^_]X[^_]UES]  u S@ %C#u KP % []UR?u@]UEHE RD]UWVS0ËP php}C C @;F,~!hCF,hjPv s~kF CV [uvFPW V;VEEuVt=> t WYjUjkjUjEZSWEWuËVuPxuVuSgFEF Fe[^_]UVSu ]VS$jSC$HEe[^]UVuS] SV; XZu#CS9CuF29| RSVCe[^]UU MB9Bt]량U M]zUVS0u ]VSXZt}w uz{(quECUEEEP-uv vSI EUREȉYF F=VSe[^]UWVS ÉUEu FE@E wt$tCqmڞztoZڞzt\U]$EXEZ$Ƀ\$$ u z UZv؃}1҃}1t VSVY_uSIY9EZ~U UWujuSUB e[^_]UVS E Eu]EE]t YXuIV@ ?u6؉t ^H G ‰FGVSXZu }Lu }?u }2u }%u }u } u }e[^_]u} E u} EDu} Eu} E!u} Eu} Ee[^_]e[^_]UVSE u]$C] ue[^]SVXZtwHtt tV-C jډYPCPV sVXZC-] ue[^]xu] ue[^]e[^]US] uuC  ]UWVuS]u S\U U{$jSVSYZPE pWj S؃$%E x e[^_]UWVSu ]}t4wtmt7 tJaFEe[^_]WSjvPj(WSvPjSWSPv vj Se؉[^_]uU2WEV} uSHXEu1SPWj"VjPWj"VF pGF$e[^_]ÐUhuƾɸUS]jSjSuSX]US]jS谾Zƒ YuhYCjSH jSżjSZYPS]UjuɸUS]jjSjS}jSu hoCS[X]UVSuPcSjV e[^]UVSuPSjVe[^]UVSjP½ZYujS)؍e[^]U9ЉSujP[jS jPR ujSs]UUWVSt]xjNjEhCPSuƋE@PS脽Ut)EPBPSZYPW u[SBPSZYu4VhCSjjSƋE@PS蒼 jWS6 hCE@EPVW uhCEPS9jjS`jSVtOuC=ECP-uC@uC1uCjlVWZYtuغ CXjuV9ZYtuCYjnVYZt uCuCXZjLVZYth(CYjfV^Zth4C؉[e[^_]UUWVSt]uwSNjE@PVZYPW Euh9C@PVGPVZYPSW tjVWuSVKjV趺 V諾e[^_]UUW}VSt]WƋE@PS\ZYPVz Euh9C@PSCJtt ECNuC Ut _t݋M؍T1E9}EE9EC UEEe[^_]UEP,h;ZUtЋQ|uC]UWVS uEE UEUBxxXEPǍFPSU t CVYƒ? $CCUCo9}`g؁UC?CCt EC؁UC1e[^_]UWVSE E}E8>uE UMBP@QEG`tUkR(ЉE@E}EE EuWGCG$GCG CGGG GCjCHd1CPC@[^]USE] UHyu []\CQ$ЈC[]UU EHbA(BQ(]UEM @PH@$AEA]UVuS] NAYS¨uAu=yu)CSx~(@t tPSV= A$ˆSe[^]ÐU=$CVuS Ct)jsV3VGjjV< {Սe[^]ÐUWVSۋ8tjVILVn}XtW詴$uhCVJW荴$hCV1 WV`e[^_]UVSJ0S$uhCSjjSm PVSʓe[^]UVS]jSٕjSEhChStjSYZtjjS蚄 u S與Z>u j hCjhCS踇 e[^]UVShCjP{ 8u hCVY^e[^]UVSjPhChSSjSme[^]US]SjhCS#]UVSuhCjV0u1Ee[^]UVSuhCjV觓0r1Ee[^]USjP݉h)CjS~jS}ZYSЋ]US]jS7Z@YujhS׈ ؋]US]hCjS 8t}]1US]hCjSܒ uj h1CS Ph?CS~ ]UWVSS}jjW蛓EjhICjW输É!Su赱$uE1҉Ee[^_]e[^_]UWVSV}jjW5EjhICjWXÉSu菲$uE1҉Ee[^_] e[^_]UVSuu=uE1[^][^]UWVSRhPyhVzy1e[^]UWVS]PUxZE@SWzZYu5Et%SWN|$hCuA~Eu9EPSWsE tuujP藫;EuEuMC}qj]e[^_]US]gE‰[]US]_E‰[]UWVSu=hChCjVQjjV蛍4CPWҪ(tEe[1^_]W螪$Vp}e[^_]UWVS]hCjjS܋hjS#P4CjW8E,1҅e[^_]9US]KPY1҅E؋]US]5P©Z1҅E؋]UW}VS7~jVNxWhVKjV7xjV8u jV`e[^_]UVSjjP&jVS'}h)CjS/e[^]US]hCS贈XZjSwYXhCjS hCjS غ@hSvhChCS藎غ@_hC2Djh!C2Dj 2D$h(Cj@jSuhCjSv}@jS$jSqu]ÐUWVS1PuCE}1IQuVPH Cƒ P~ʍe[^_]UVuS] @2D8u2DX j SAZYtSh`CShiCv4$Ce[^]UWVSP]jPu} F@PS$WvShlCv4$ }t:E-w16F< uV;[ZPWhvCv4s$jv4e[^_]UWVSSX~+OmS8H@t B@B RY -t -S8H@t B@B RZ [u1‹C<@xR1/C<@_ 1҃ …AS8H@t B@B Rm^ 뿉]xPU@[hhCS S8H@t B@B RY ==S8H@t B@B RߕZ S8H@t B@B R賕_ =<pS8H@t B@B R胕^ DS8H@t B@B RWY =>S8H@t B@B R'Z S8H@t B@B R_ =~S8H@t B@B R˔^ S8H@t B@B R薔Y 9 t @t t\t$hhh:CS K8H@t A@A Q-Z‰btJ t Bu tlat!}rtB ft'nt,jtt9vt>^  غ 2D8u2DP jR1Y^E1k S8pЋH@t B@B R)ZE }(2D8u2DH jQɛZYu~hhLCS /S8H@t B@B R裒^ 9;S8H@t B@B RqY SWYUe[^_]ÐUWtVSĀ芕jhWjPjh聕t WVidXZShDVd e[^_]USh)DjupË tPG1]UWVSRh2Dh<DPqdhSeY_jS__ZtjSbZYdjS]_XjSmZYh)DhSre jShYXVh2Dh<DScjS^XZhSfYX?uVDu7t&uR1u jPSc1e[^_]UVuSjjVpjjVpPډÃ۸t'VXbjVG]KADtFDPVbe[^]UWVSQQ]hKDhMDRPUEvShuEPdjjun`(uShODum jhmDub ;;uC1;t3j;S$^_u߃1эt)PSua tuuhnDjju_ Puuju\hpDS蹍ZYu*ShrDu'bju[juYjLPX1e[^_]UVSjjPf_ PVjjSW_ PhDS~le[^]UVuSjjVnhD‰ttPVwZYt ډe[^]UVSj-RZYtXhDhMDSVtPhDV`e[^_]UVS]jjS[mhDhSdajS6[ t hDSjYXVjS>ajS[uVhDS_ e[^]UWVS]jjSljSYh0DhS` VjS`jS\t)jS]Z=DYJVh8DS j 6hcDhS`jSeZt hkDSiY_jhmDS_^ WjS`jS*ZujjSi\ PVhDSiVS]^jjSRdjSYt%jSsZYZt jSfjSXXGZhDSw_VjSaVS^jjSc(jSYZYt VjSa VjS_jS\=DujS^jS$YVjSWae[^_]UWVSp]jjS/kSKWh0DxhS/_VWS'_(jSXZYtAjS'WjVhSmtVhDSLh@jSXVWS`hDjS^jSXt jSVY^mjSVXZjSEXYXhDjSr` VS\XZhDjSY` j.V\ZYu@)PVSM\ hDjS)` jSW^uXVjS t!VhDS tjSXZYt hDSVgY^jOSWXZjSaY^jSUXZ9#VFSoWYXjSeWXZjjSa 1e[^_]US]jjSijS^ujjS=^jSWjS`hSWhDjS1_]1UWVSuu Zu VST[)hDh DPS/oVhDPS"o jSWU^XhVjA= Шuj\V趉ZYu hDSf(Vh.DjjSX PSnjST^XWjSb^e[^_]UVuS1h)DVfjhſ@V#[h0DjV+^ hDh5DVljVUhVUjjV\(=Dt&j4DCVZSjV^<DhcDjV]h=DDhwD|hDDhDfj hDVY(hDjVs]jh0DhVJjhDjVT](jjV(\hDjV:]hVT hDjVkjVJSe[^]ÐU1ɉEv@Av  ]UUSЉt HZ[]UE=vD]U1S]M S;Qu6t'Ұt)tu 9[]UWVuSS]V} S{EZ19YttTW耀$uhDV!UWVSTe[^_]US]jjjSmbP?$S!T]UVSujjV b PZ1҅]e[^]GUVS]jjSajjSaPV诃YZ1҅ue[^]UVS]SurYu hDV^ SVSe[^]US]jjS\a PS$SS]UP$5D$uSɸUVSuPSSjVWe[^]UWVSRjPTjV-OtjVP_X]yWhDV/^ jVL؍e[^_]UWVS]jhDjS`jSjN_Z j(Y9jSaٽXZ f٭۝٭>!u PFāP謁Xu SQ`hDV_}ZYj jST7DwDwDw DGD@PvG DlP^GD@PMGD@Ptg>%u~u+E9rRdX.FWEEPhSJPSPdF딍PcXe[^_]UVS0]jSnL^Z j,jjS]jSJjDMEȺDjXtZSPw0| w0WoBW1X _0j‰X4s$$S|lY^wjX4ZVPSl{C2 CJSk T S‰Y,C=uݺ=-t Dž1ҍPRkXZ6Ww0X_ u;uDž1! wMjSVl 1҃…tP F2Dž!u SV8sY[ SVrXF2ZPVo W[|R_0 uP %?@jDž Y1;ÉW0B2B$u_wW4B4HfB4e[^_]UWVS]UEu׉E1IQRV Pu SVdd@JSغVde[^_]UWVSLQU P<(}t(jh DV? ‰jXN01ۋ9GJ~)tvF=t=uBS‰XC:V$h DV ‰SCZYGJ h! DVXZJu,눉ډ WJA2(ЈGIA2PQhY)[VP@u h XF0Z@,{4@9~!h: DC4hjPsv4CS49}CG9|􋍨A,K@B,@tCt PSv4 1ۋA,HPjj$Qj P_xHt;]1Ҁ]jPjCRk@H9|ōe[^_]UWVS(EЉUbUЋB-t#tC=t 51ujŰEűESp0q7= +={= =tp =tU=t =t&jE̺XUЋEBXUЋErU]jLjCj:EЋX0xJuhR Du^_`Jjjjj%SiPE [:ŰE6uYUЋErUjXZŰE uXEЋP^E-*%m1+f< tl/S >ItL#t@ $ t| t Q?` D;EvIuЍ]űUWr0r?a DPElSƋEuWp0p$uEЋP4B4HfB4e[^_]Uj-UVu؉S }uEVs0jEe[^]UVSPVs0l e[]^]xUWVSL@0UP$EUu+Ex~h} DE[Uԉ UԉrU]B= EPu>lƉډSu*lZUYPVBpj ugUEP$e[^_]UVS{ ~F0h} D'^C C$e[^]UWVS8Ӌx0@jjjj WEfP EEEE]jE1Sv0j${~}}Et1PWj}2XEZuj2EupWBrEF[t=UuV~ =UXuUĉ2,lq;X]u}j{~}YM[tRUčBw%jQW^c EjupWqM"t QWiXZuEupWnqp Eu ËEp Eu?% ËEe[^_]UWVSVGs0,i؉YX,Vuۍe[^_]UWVS(x0UЋ@E̋F{tk (t=tdyE;Ft h DV舺XZV~)Xu E]ԉPjSWb u̺)j(UԉQ$vUԉVCY[ h DVZEЃMԋXAvt EPW+hXZW$jBPSjWc PEuWbCG$e[^_]UWVSD@0EF(t =t18V^Y0S)j(%XZWv0c h DVLY[F:tW(t}.t{tn[t|=t^sW]uwgډSWumV]ډgSWumtWuf[e[^_]UWVSHBUv h DV{Y[,E}E}ue^01ɋUC$҉EtSz u&G9Bu EBG9Bu EBu΅tjws$jSajS.^XZF4@4)9U~h DF0XEU@PXI=}H;EtWUPs;]_X~+]F0)X$ Wv0_WF0]Ժ @$HPSEPv0le[^_]UWVuԉS V}s0Tee[^_]UUVSËp0jCe[^]UVSPƺde[^]UWVSX0U(-}thuj S_S`_jǍUU u S\/WS[}thujS_u juj!S_uS^}GPuS_^PS[e[^_]ÐUVShjjR hjC(CjVC0C$CpSSC C,-BC@CC C@Be[^]UVSjkB0Pr(VjC,Ps Vze[^]UWVSP]CڍsHE3jjS"CHFsjj~`S"F`Gj S= S2Sjh DSH UBDB@e[^_]U]P@ @,@p@D@8@<@9@@@h@0f@6f@4@@@(@@t@PUVSpp P蹔S轞jSBP2SEjvFPxWXP$:e[^_]U卅WV1S]PjS4ǍPS7;s7E9rRn:XC>FPVXP9e[^_]U卅WVS]PjSR4jS5ƍPS 7N~WP: ፅP(9e[^_]UEWVSVVPju3jjuE5U %Pju5] 9v19O)x>9h! Du0Y[h! DWu2 ~EtFPuM%XKZue[^_]UWVS}WMPW5 ;JVW4Z9Yth7 DVW0 E9rR8XF뮍P7e[^_]Uuu u{81UVS]jjS2jSVS75Vh@S,,(t hE DS/[XV]7e[^]UVSC%t[tN;uDhc Dv/Y^31;^À;uh Dvd/XZC<%u<;]u׍C؍e[^]UVSRTYaV$ D2D8u2DX%"h2D8u2DX j 2D8u2DXj2D8u2DXj2D8u2DXj2D8u2DXnjb2D8u2DXPjD2D8u2DX%0h!2D8u2DX% hSN[Z 1932D8u2Dp jVNZYu1҅‰Ѝe[^]UWVSӀz^uf1CC;]sD<%uCt({-uS;UsB999u1[^_]UVSuȃ.t%t,[t%)R[^]FE[^]G9[^]UWVSuE%*$(<(t )t'-~)ujFjFPEUFB Hx M|thDEp6,[ZUÉ+DDEVXYMD~Vƒbt ft~~^t{uh(DEp+XZ1:u=WEE[]X9s;EuIuB;EB1҅҉>[th;DUrZ+Y[EEM1;9tG]KSZS[uY2D҃8u2DP jRKZYF1xU;B } Mƒ|uh^DEp*Y[MA\)9rSWt4O t1҅҉~uU;zE1EM;ysuZtU+t=*t.~-tF?uttEW@PE2YuluF5uV 1tUuWVEDE@PEZu.M;Ysu_tCυu1 uGe[^_]UWVSp Ã~htDp\)XZ|E DFuC {YuK e[^_]UWVS1C;GsUu ZuxE @P.YuK1e[^_]UWVSËU;{ E |#u)PRYE ^DCEe[^_](tuhDs(YX!uD+@E CEe[^_]Vts e[^_]UWVSQH Uɉƒ} ШuhtD1Sw* 9}uFu&XZe[^_]UWVS4PjO*Pj5*jj , gǃOy19v߃j[^uhDKZY)to9v ^O)'WC@PSK t܉+)ƅFVPK u+CPSDž8^uMDž@:+CP+Vj1҉DžƅXtgVډW$C;s te[^_]UE]uU1҉E]gU卅WVSPhujhuEhua ;wZڍDžƅXt31)9Pu4hu8VڍFC1e[^_]US]jjS&jjS&jS! jSjh AS]UhDu5$U卅WVS@Pju&jju&jurË @PjuQ( Dž8^uDž@DžCƒ ШuthDju# Pu(_UX9WDž][jSpZY" 7'1Pj ;]<%u3C2D8u2DP jRCZYu# 9rW*Y D<0u)PVW* !Ѓ1V*XZWU+XCHjS<YX$PS 1ҍVXZjS&YXjSCYZujSMXZ)PVS-jSZYu"jSZYPSZYPhDSR! W*X19…t5;s:9rRO)XF)PVS8)Sk(u;e[^_]U1҉WVSƈэQ\fDl\D[^_]U卅WVS`PjuDž"ƋPu%;>%uF>%u,E9rRN([FGtPhD?ZYu)vhDuY[2D8u2DP jR@[Z2D8u2DP jRh@ZY?.u[2DG8u2DP jR5@Y[2D8u2DP jR@[Z2D8u2DP jR?ZYth8DuY[)C%APVFQ> Dg>eWXECG:ctJdqE itqous7xu!ٽXZ f٭۝٭P1uO!_ٽX f٭۝٭Lu!ٽZ f٭߽٭YPSu $PP<PuWE 9rS%X"H@ tH tK "t\uN 9;rS$X\@9rS$X7jheDjhhDS$ 9rS]$XP 9rS2$X"PuKj.ÍP{;u%cvu P$NSPPK; FPhmDu_:1эIQRP# P"e[^_]US]h DhDS_"ha DjSh[ DjSq$jjSE jh DSh jS XZjSzYXjSh XZjS YXhDjS jSD X]ZÐUSSSEuzS'KE EJE1҉ESZY[]UVSQQBtIt5@tt4r2^ZCKH#J(KH# K21HKe[^]URRxu"D]EP$ztɉUWVSSu} ~~R;GMHP$FO U AQAVFQFAVFVCPZYu{ u~~9Cu +GG[uhDu*bY1[_P9}G |BF9؉|_+W9}-EGM|% BM9|1e[^_]USH1=wPD]UVuSӍF=wPBPr Q>QZC S9}DB9|se[^]UWVSQ]uBDE|CPWZ@E~ hDV`[XMC=wPjjV袦V胦YG~$1ɉڋGȃ @J@@uE_G_e[^_]UVuSj jjV?jPV要CډCCC CCDu ue[^]UVuS] SDtj KPRVjCPs V謥jj SV补e[^]UPPU MB;AsQ B?;R$$]ZYzuBEzt͋RuDUSU] JH#CBxu9Xt @uD[]UVSSSu MVt ҸDte<u76QTD]UR$uz RQ+'VCP,ZYu[uDe[^]UWVS]u }SV^F=DYZu>CuhDuzt hDWG^XZ]e[^_]Se[^_]UWVS}EBUM9ljEIRMU~ WUEk^u UE;}[EU܉xMU܋A |t#FPQu KSHPEF;u|ÍG=weMWuq uL u+YUB MNx9U{t"CPuu KSHP Nyҁ}DtM jPuu͢e[^_]UWVSU|xu =D]WOBG9vWztBG҉1D@~DžpDžxDžtt1G9~9ÉG;tG @C9~pxѥtt@x~DžlpDžhOUKt0GxtUhlK uՋEUhMplEDž\F9\EDž`DžXDžd}vdD~2`ȉә9`P~X`\U9`Pt%d әP9ЉT+\X|VQM|XZuW|zS9t)9Xt@pj SV1C C CFsMQCSACy~@tGtW|W{_X؍e[^_]UVSu] VSEY=DZuVE$$EE]e[^]U1VSU u]zDtJE ][^]sUVSu] VS0Y=DZuuEPEEe[^]UEWVSHt:p |u+1ۃv  |uӉ)؃މzUȉ΍yzDu-eSuxYZu݉ىe[^_]ÐUWVS]jjS$jS2jjS 9GjS+VSYVjSjjS (jS5YZtjFS_XZ1e[^_]US]jjSjjSSDjSjSjSjjS& $jSZYtjSYXjSt YZu]USQQ]jjS]#SI7jSjSaujS EXZv]jS ZYuuuS ]US]jjS jSZYPS]US]jjS}hDSQ jS]UWVSjjuNjuZXuZttL>EEULD>MD9xreEUECjBCBC KMI Mgt ]DCExht uPG^XMċUJWRw:M Y[]C@CG GʞvٞGUG8U_0O UĉME_PtWWTYZuhD@{tGPS7ÅXZuhD!Myt"G PQYE[uhDuP4XZG]/EčEG O0W$]ĉGPG(WTWGXGWDWG@GW4UGHZG0GAG`B%PQR=E U@ E̋M̋BY8@ۉBt!Y(A0Q4A Q$MċMăEju]C)pC@Cu UċUĉƒ(k2MD0;AE~ PQuK 8uMuu KSHP{~@tE@t PuS_XNWuDY[UB@KHr MQuqCX1ۃ ;]}@EċЃ?uMDDEPuCDXZEC뻉7]EGSCB@9BDrS/RYUR UM]IHES+AMRI)H}EuKEUċ]P@+A9 uQ5XZEU@ MUE̍A1;uk1;u}$UE )ًQ;AT;D;D;F;u|*e[^_]USP]EPs sS tEuKHACЋ]US];uSZ@t KC]UU EBEBBEB ]UW}VuSt3WY@u'9vSwu ) _] )1e[^_]UMVu S]V9v-w CwSR6QvQuZ^e[^]ÐUDQ@Dr]ÐUSX5 PX1Щ 1Ӂft @ Dt @ Dt @ Dt @ Dt @ D t @ D@ t @ D=v+@ D@t @ Dt&[]à @ DM[ @ D]ÐU]ÐU`A8t `AQA`AuÍ&USUAt)t'UAKu$IAjY[]1=UA @UAu뾍'USP Du5UA P Dt$tt&UAKu$IAX[]1=UA @UAuÐU D]HUBSdT$U1ۉT$$p2D uFJx|*Au Jy; 1 then i = i - 1 end return p:sub(1, i) else return "." end end function path.getdrive(p) local ch1 = p:sub(1,1) local ch2 = p:sub(2,2) if ch2 == ":" then return ch1 end end function path.getextension(p) local i = p:findlast(".", true) if (i) then return p:sub(i) else return "" end end function path.getname(p) local i = p:findlast("[/\\]") if (i) then return p:sub(i + 1) else return p end end function path.getrelative(src, dst) src = path.getabsolute(src) dst = path.getabsolute(dst) if (src == dst) then return "." end if dst:startswith("$") then return dst end src = src .. "/" dst = dst .. "/" local idx = 0 while (true) do local tst = src:find("/", idx + 1, true) if tst then if src:sub(1,tst) == dst:sub(1,tst) then idx = tst else break end else break end end local first = src:find("/", 0, true) if idx <= first then return dst:sub(1, -2) end src = src:sub(idx + 1) dst = dst:sub(idx + 1) local result = "" idx = src:find("/") while (idx) do result = result .. "../" idx = src:find("/", idx + 1) end result = result .. dst return result:sub(1, -2) end function path.iscfile(fname) local extensions = { ".c", ".s", ".m" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.iscppfile(fname) local extensions = { ".cc", ".cpp", ".cxx", ".c", ".s", ".m", ".mm" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.isresourcefile(fname) local extensions = { ".rc" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.join(leading, trailing) leading = leading or "" if (not trailing) then return leading end if (path.isabsolute(trailing)) then return trailing end if (leading == ".") then leading = "" end if (leading:len() > 0 and not leading:endswith("/")) then leading = leading .. "/" end return leading .. trailing end function path.rebase(p, oldbase, newbase) p = path.getabsolute(path.join(oldbase, p)) p = path.getrelative(newbase, p) return p end function path.translate(p, sep) if (type(p) == "table") then local result = { } for _, value in ipairs(p) do table.insert(result, path.translate(value)) end return result else if (not sep) then if (os.is("windows")) then sep = "\\" else sep = "/" end end local result = p:gsub("[/\\]", sep) return result end end function path.wildcards(pattern) pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1") pattern = pattern:gsub("%*%*", "\001") pattern = pattern:gsub("%*", "\002") pattern = pattern:gsub("\001", ".*") pattern = pattern:gsub("\002", "[^/]*") return pattern end function string.explode(s, pattern, plain) if (pattern == '') then return false end local pos = 0 local arr = { } for st,sp in function() return s:find(pattern, pos, plain) end do table.insert(arr, s:sub(pos, st-1)) pos = sp + 1 end table.insert(arr, s:sub(pos)) return arr end function string.findlast(s, pattern, plain) local curr = 0 repeat local next = s:find(pattern, curr + 1, plain) if (next) then curr = next end until (not next) if (curr > 0) then return curr end end function string.startswith(haystack, needle) return (haystack:find(needle, 1, true) == 1) end function table.contains(t, value) for _,v in pairs(t) do if (v == value) then return true end end return false end function table.extract(arr, fname) local result = { } for _,v in ipairs(arr) do table.insert(result, v[fname]) end return result end function table.flatten(arr) local result = { } local function flatten(arr) for _, v in ipairs(arr) do if type(v) == "table" then flatten(v) else table.insert(result, v) end end end flatten(arr) return result end function table.implode(arr, before, after, between) local result = "" for _,v in ipairs(arr) do if (result ~= "" and between) then result = result .. between end result = result .. before .. v .. after end return result end function table.isempty(t) return not next(t) end function table.join(...) local result = { } for _,t in ipairs(arg) do if type(t) == "table" then for _,v in ipairs(t) do table.insert(result, v) end else table.insert(result, t) end end return result end function table.keys(tbl) local keys = {} for k, _ in pairs(tbl) do table.insert(keys, k) end return keys end function table.translate(arr, translation) local result = { } for _, value in ipairs(arr) do local tvalue if type(translation) == "function" then tvalue = translation(value) else tvalue = translation[value] end if (tvalue) then table.insert(result, tvalue) end end return result end function io.capture() io.captured = '' end function io.endcapture() local captured = io.captured io.captured = nil return captured end local builtin_open = io.open function io.open(fname, mode) if (mode) then if (mode:find("w")) then local dir = path.getdirectory(fname) ok, err = os.mkdir(dir) if (not ok) then error(err, 0) end end end return builtin_open(fname, mode) end function io.printf(msg, ...) if (not io.eol) then io.eol = "\n" end local s if type(msg) == "number" then s = string.rep("\t", msg) .. string.format(unpack(arg)) else s = string.format(msg, unpack(arg)) end if io.captured then io.captured = io.captured .. s .. io.eol else io.write(s) io.write(io.eol) end end _p = io.printf premake = { } premake.platforms = { Native = { cfgsuffix = "", }, x32 = { cfgsuffix = "32", }, x64 = { cfgsuffix = "64", }, Universal = { cfgsuffix = "univ", }, Universal32 = { cfgsuffix = "univ32", }, Universal64 = { cfgsuffix = "univ64", }, PS3 = { cfgsuffix = "ps3", iscrosscompiler = true, nosharedlibs = true, namestyle = "PS3", }, Xbox360 = { cfgsuffix = "xbox360", iscrosscompiler = true, namestyle = "windows", }, } local builtin_dofile = dofile function dofile(fname) local oldcwd = os.getcwd() local oldfile = _SCRIPT if (not os.isfile(fname)) then local path = os.pathsearch(fname, _OPTIONS["scripts"], os.getenv("PREMAKE_PATH")) if (path) then fname = path.."/"..fname end end _SCRIPT = path.getabsolute(fname) local newcwd = path.getdirectory(_SCRIPT) os.chdir(newcwd) local a, b, c, d, e, f = builtin_dofile(_SCRIPT) _SCRIPT = oldfile os.chdir(oldcwd) return a, b, c, d, e, f end function iif(expr, trueval, falseval) if (expr) then return trueval else return falseval end end function include(fname) return dofile(fname .. "/premake4.lua") end function printf(msg, ...) print(string.format(msg, unpack(arg))) end local builtin_type = type function type(t) local mt = getmetatable(t) if (mt) then if (mt.__type) then return mt.__type end end return builtin_type(t) end premake.action = { } premake.action.list = { } function premake.action.add(a) local missing for _, field in ipairs({"description", "trigger"}) do if (not a[field]) then missing = field end end if (missing) then error("action needs a " .. missing, 3) end premake.action.list[a.trigger] = a end function premake.action.call(name) local a = premake.action.list[name] for sln in premake.solution.each() do if a.onsolution then a.onsolution(sln) end for prj in premake.solution.eachproject(sln) do if a.onproject then a.onproject(prj) end end end if a.execute then a.execute() end end function premake.action.current() return premake.action.get(_ACTION) end function premake.action.get(name) return premake.action.list[name] end function premake.action.each() local keys = { } for _, action in pairs(premake.action.list) do table.insert(keys, action.trigger) end table.sort(keys) local i = 0 return function() i = i + 1 return premake.action.list[keys[i]] end end function premake.action.set(name) _ACTION = name local action = premake.action.get(name) if action then _OS = action.os or _OS end end function premake.action.supports(action, feature) if not action then return false end if action.valid_languages then if table.contains(action.valid_languages, feature) then return true end end if action.valid_kinds then if table.contains(action.valid_kinds, feature) then return true end end return false end premake.option = { } premake.option.list = { } function premake.option.add(opt) local missing for _, field in ipairs({ "description", "trigger" }) do if (not opt[field]) then missing = field end end if (missing) then error("option needs a " .. missing, 3) end premake.option.list[opt.trigger] = opt end function premake.option.get(name) return premake.option.list[name] end function premake.option.each() local keys = { } for _, option in pairs(premake.option.list) do table.insert(keys, option.trigger) end table.sort(keys) local i = 0 return function() i = i + 1 return premake.option.list[keys[i]] end end function premake.option.validate(values) for key, value in pairs(values) do local opt = premake.option.get(key) if (not opt) then return false, "invalid option '" .. key .. "'" end if (opt.value and value == "") then return false, "no value specified for option '" .. key .. "'" end if (opt.allowed) then for _, match in ipairs(opt.allowed) do if (match[1] == value) then return true end end return false, "invalid value '" .. value .. "' for option '" .. key .. "'" end end return true end premake.tree = { } local tree = premake.tree function premake.tree.new(n) local t = { name = n, children = { } } return t end function premake.tree.add(tr, p) if p == "." then return tr end local parentnode = tree.add(tr, path.getdirectory(p)) local childname = path.getname(p) if childname == ".." then return parentnode end local childnode = parentnode.children[childname] if not childnode or childnode.path ~= p then childnode = tree.insert(parentnode, tree.new(childname)) childnode.path = p end return childnode end function premake.tree.insert(parent, child) table.insert(parent.children, child) if child.name then parent.children[child.name] = child end child.parent = parent return child end function premake.tree.getlocalpath(node) if node.parent.path then return node.name else return node.path end end function premake.tree.remove(node) local children = node.parent.children for i = 1, #children do if children[i] == node then table.remove(children, i) end end node.children = {} end function premake.tree.sort(tr) tree.traverse(tr, { onnode = function(node) table.sort(node.children, function(a,b) return a.name < b.name end) end }, true) end function premake.tree.traverse(t, fn, includeroot) local donode, dochildren donode = function(node, fn, depth) if node.isremoved then return end if fn.onnode then fn.onnode(node, depth) end if #node.children > 0 then if fn.onbranch then fn.onbranch(node, depth) end dochildren(node, fn, depth + 1) else if fn.onleaf then fn.onleaf(node, depth) end end end dochildren = function(parent, fn, depth) local i = 1 while i <= #parent.children do local node = parent.children[i] donode(node, fn, depth) if node == parent.children[i] then i = i + 1 end end end if includeroot then donode(t, fn, 0) else dochildren(t, fn, 0) end end premake.solution = { } premake.solution.list = { } function premake.solution.new(name) local sln = { } table.insert(premake.solution.list, sln) premake.solution.list[name] = sln setmetatable(sln, { __type="solution" }) sln.name = name sln.basedir = os.getcwd() sln.projects = { } sln.blocks = { } sln.configurations = { } return sln end function premake.solution.each() local i = 0 return function () i = i + 1 if i <= #premake.solution.list then return premake.solution.list[i] end end end function premake.solution.eachproject(sln) local i = 0 return function () i = i + 1 if (i <= #sln.projects) then return premake.solution.getproject(sln, i) end end end function premake.solution.get(key) return premake.solution.list[key] end function premake.solution.getproject(sln, idx) local prj = sln.projects[idx] local cfg = premake.getconfig(prj) cfg.name = prj.name return cfg end premake.project = { } function premake.project.buildsourcetree(prj) local tr = premake.tree.new(prj.name) for _, fname in ipairs(prj.files) do local node = premake.tree.add(tr, fname) end premake.tree.sort(tr) tr.project = prj return tr end function premake.eachconfig(prj, platform) if prj.project then prj = prj.project end local cfgs = prj.solution.configurations local i = 0 return function () i = i + 1 if i <= #cfgs then return premake.getconfig(prj, cfgs[i], platform) end end end function premake.eachfile(prj) if not prj.project then prj = premake.getconfig(prj) end local i = 0 local t = prj.files return function () i = i + 1 if (i <= #t) then return prj.__fileconfigs[t[i]] end end end function premake.esc(value) if (type(value) == "table") then local result = { } for _,v in ipairs(value) do table.insert(result, premake.esc(v)) end return result else value = value:gsub('&', "&") value = value:gsub('"', """) value = value:gsub("'", "'") value = value:gsub('<', "<") value = value:gsub('>', ">") value = value:gsub('\r', " ") value = value:gsub('\n', " ") return value end end function premake.filterplatforms(sln, map, default) local result = { } local keys = { } if sln.platforms then for _, p in ipairs(sln.platforms) do if map[p] and not table.contains(keys, map[p]) then table.insert(result, p) table.insert(keys, map[p]) end end end if #result == 0 and default then table.insert(result, default) end return result end function premake.findproject(name) for sln in premake.solution.each() do for prj in premake.solution.eachproject(sln) do if (prj.name == name) then return prj end end end end function premake.findfile(prj, extension) for _, fname in ipairs(prj.files) do if fname:endswith(extension) then return fname end end end function premake.getconfig(prj, cfgname, pltname) prj = prj.project or prj if pltname == "Native" or not table.contains(prj.solution.platforms or {}, pltname) then pltname = nil end local key = (cfgname or "") if pltname then key = key .. pltname end return prj.__configs[key] end function premake.getconfigname(cfgname, platform, useshortname) if cfgname then local name = cfgname if platform and platform ~= "Native" then if useshortname then name = name .. premake.platforms[platform].cfgsuffix else name = name .. "|" .. platform end end return iif(useshortname, name:lower(), name) end end function premake.getdependencies(prj) prj = prj.project or prj local results = { } for _, cfg in pairs(prj.__configs) do for _, link in ipairs(cfg.links) do local dep = premake.findproject(link) if dep and not table.contains(results, dep) then table.insert(results, dep) end end end return results end function premake.project.getfilename(prj, pattern) local fname = pattern:gsub("%%%%", prj.name) fname = path.join(prj.location, fname) return path.getrelative(os.getcwd(), fname) end function premake.getlinks(cfg, kind, part) local result = iif (part == "directory" and kind == "all", cfg.libdirs, {}) local cfgname = iif(cfg.name == cfg.project.name, "", cfg.name) local pathstyle = premake.getpathstyle(cfg) local namestyle = premake.getnamestyle(cfg) local function canlink(source, target) if (target.kind ~= "SharedLib" and target.kind ~= "StaticLib") then return false end if premake.iscppproject(source) then return premake.iscppproject(target) elseif premake.isdotnetproject(source) then return premake.isdotnetproject(target) end end for _, link in ipairs(cfg.links) do local item local prj = premake.findproject(link) if prj and kind ~= "system" then local prjcfg = premake.getconfig(prj, cfgname, cfg.platform) if kind == "dependencies" or canlink(cfg, prjcfg) then if (part == "directory") then item = path.rebase(prjcfg.linktarget.directory, prjcfg.location, cfg.location) elseif (part == "basename") then item = prjcfg.linktarget.basename elseif (part == "fullpath") then item = path.rebase(prjcfg.linktarget.fullpath, prjcfg.location, cfg.location) elseif (part == "object") then item = prjcfg end end elseif not prj and (kind == "system" or kind == "all") then if (part == "directory") then local dir = path.getdirectory(link) if (dir ~= ".") then item = dir end elseif (part == "fullpath") then item = link if namestyle == "windows" then if premake.iscppproject(cfg) then item = item .. ".lib" elseif premake.isdotnetproject(cfg) then item = item .. ".dll" end end if item:find("/", nil, true) then item = path.getrelative(cfg.basedir, item) end else item = link end end if item then if pathstyle == "windows" and part ~= "object" then item = path.translate(item, "\\") end if not table.contains(result, item) then table.insert(result, item) end end end return result end function premake.getnamestyle(cfg) return premake.platforms[cfg.platform].namestyle or premake.gettool(cfg).namestyle or "posix" end function premake.getpathstyle(cfg) if premake.action.current().os == "windows" then return "windows" else return "posix" end end function premake.gettarget(cfg, direction, pathstyle, namestyle, system) if system == "bsd" or system == "solaris" then system = "linux" end local kind = cfg.kind if premake.iscppproject(cfg) then if (namestyle == "windows" or system == "windows") and kind == "SharedLib" and direction == "link" then kind = "StaticLib" end if namestyle == "posix" and system == "windows" and kind ~= "StaticLib" then namestyle = "windows" end end local field = iif(direction == "build", "target", "implib") local name = cfg[field.."name"] or cfg.targetname or cfg.project.name local dir = cfg[field.."dir"] or cfg.targetdir or path.getrelative(cfg.location, cfg.basedir) local prefix = "" local suffix = "" local ext = "" local bundlepath, bundlename if namestyle == "windows" then if kind == "ConsoleApp" or kind == "WindowedApp" then ext = ".exe" elseif kind == "SharedLib" then ext = ".dll" elseif kind == "StaticLib" then ext = ".lib" end elseif namestyle == "posix" then if kind == "WindowedApp" and system == "macosx" then bundlename = name .. ".app" bundlepath = path.join(dir, bundlename) dir = path.join(bundlepath, "Contents/MacOS") elseif kind == "SharedLib" then prefix = "lib" ext = iif(system == "macosx", ".dylib", ".so") elseif kind == "StaticLib" then prefix = "lib" ext = ".a" end elseif namestyle == "PS3" then if kind == "ConsoleApp" or kind == "WindowedApp" then ext = ".elf" elseif kind == "StaticLib" then prefix = "lib" ext = ".a" end end prefix = cfg[field.."prefix"] or cfg.targetprefix or prefix suffix = cfg[field.."suffix"] or cfg.targetsuffix or suffix ext = cfg[field.."extension"] or cfg.targetextension or ext local result = { } result.basename = name .. suffix result.name = prefix .. name .. suffix .. ext result.directory = dir result.prefix = prefix result.suffix = suffix result.fullpath = path.join(result.directory, result.name) result.bundlepath = bundlepath or result.fullpath if pathstyle == "windows" then result.directory = path.translate(result.directory, "\\") result.fullpath = path.translate(result.fullpath, "\\") end return result end function premake.gettool(cfg) if premake.iscppproject(cfg) then if _OPTIONS.cc then return premake[_OPTIONS.cc] end local action = premake.action.current() if action.valid_tools then return premake[action.valid_tools.cc[1]] end return premake.gcc else return premake.dotnet end end function premake.hascppproject(sln) for prj in premake.solution.eachproject(sln) do if premake.iscppproject(prj) then return true end end end function premake.hasdotnetproject(sln) for prj in premake.solution.eachproject(sln) do if premake.isdotnetproject(prj) then return true end end end function premake.iscppproject(prj) return (prj.language == "C" or prj.language == "C++") end function premake.isdotnetproject(prj) return (prj.language == "C#") end local function walksources(cfg, fn, group, nestlevel, finished) local grouplen = group:len() local gname = iif(group:endswith("/"), group:sub(1, -2), group) if (nestlevel >= 0) then fn(cfg, gname, "GroupStart", nestlevel) end for _,fname in ipairs(cfg.files) do if (fname:startswith(group)) then local _,split = fname:find("[^\.]/", grouplen + 1) if (split) then local subgroup = fname:sub(1, split) if (not finished[subgroup]) then finished[subgroup] = true walksources(cfg, fn, subgroup, nestlevel + 1, finished) end end end end for _,fname in ipairs(cfg.files) do if (fname:startswith(group) and not fname:find("[^\.]/", grouplen + 1)) then fn(cfg, fname, "GroupItem", nestlevel + 1) end end if (nestlevel >= 0) then fn(cfg, gname, "GroupEnd", nestlevel) end end function premake.walksources(cfg, fn) walksources(cfg, fn, "", -1, {}) end premake.config = { } function premake.config.isdebugbuild(cfg) if cfg.flags.Optimize or cfg.flags.OptimizeSize or cfg.flags.OptimizeSpeed then return false end if not cfg.flags.Symbols then return false end return true end local nocopy = { blocks = true, keywords = true, projects = true, __configs = true, } local nofixup = { basedir = true, location = true, } function premake.getactiveterms() local terms = { _ACTION:lower(), os.get() } for key, value in pairs(_OPTIONS) do if value ~= "" then table.insert(terms, value:lower()) else table.insert(terms, key:lower()) end end return terms end function premake.iskeywordmatch(keyword, terms) if keyword:startswith("not ") then return not premake.iskeywordmatch(keyword:sub(5), terms) end for _, pattern in ipairs(keyword:explode(" or ")) do for termkey, term in pairs(terms) do if term:match(pattern) == term then return termkey end end end end function premake.iskeywordsmatch(keywords, terms) local hasrequired = false for _, keyword in ipairs(keywords) do local matched = premake.iskeywordmatch(keyword, terms) if not matched then return false end if matched == "required" then hasrequired = true end end if terms.required and not hasrequired then return false else return true end end local function adjustpaths(location, obj) for name, value in pairs(obj) do local field = premake.fields[name] if field and value and not nofixup[name] then if field.kind == "path" then obj[name] = path.getrelative(location, value) elseif field.kind == "dirlist" or field.kind == "filelist" then for i, p in ipairs(value) do value[i] = path.getrelative(location, p) end end end end end local function mergeobject(dest, src) if not src then return end for field, value in pairs(src) do if not nocopy[field] then if type(value) == "table" then local tbl = dest[field] or { } for _, item in ipairs(value) do if not tbl[item] then table.insert(tbl, item) tbl[item] = item end end dest[field] = tbl else dest[field] = value end end end end local function merge(dest, obj, basis, terms, cfgname, pltname) local key = cfgname or "" pltname = pltname or "Native" if pltname ~= "Native" then key = key .. pltname end terms.config = (cfgname or ""):lower() terms.platform = pltname:lower() local cfg = {} mergeobject(cfg, basis[key]) adjustpaths(obj.location, cfg) mergeobject(cfg, obj) for _, blk in ipairs(obj.blocks) do if (premake.iskeywordsmatch(blk.keywords, terms)) then mergeobject(cfg, blk) end end cfg.name = cfgname cfg.platform = pltname cfg.terms = terms dest[key] = cfg end local function collapse(obj, basis) local result = {} basis = basis or {} local sln = obj.solution or obj local terms = premake.getactiveterms() merge(result, obj, basis, terms) if result[""].kind then terms.kind = result[""].kind:lower() end for _, cfgname in ipairs(sln.configurations) do merge(result, obj, basis, terms, cfgname, "Native") for _, pltname in ipairs(sln.platforms or {}) do if pltname ~= "Native" then merge(result, obj, basis, terms, cfgname, pltname) end end end return result end local function postprocess(prj, cfg) cfg.project = prj cfg.shortname = premake.getconfigname(cfg.name, cfg.platform, true) cfg.longname = premake.getconfigname(cfg.name, cfg.platform) cfg.location = cfg.location or cfg.basedir local platform = premake.platforms[cfg.platform] if platform.iscrosscompiler then cfg.system = cfg.platform else cfg.system = os.get() end if cfg.kind == "SharedLib" and platform.nosharedlibs then cfg.kind = "StaticLib" end local files = { } for _, fname in ipairs(cfg.files) do local excluded = false for _, exclude in ipairs(cfg.excludes) do excluded = (fname == exclude) if (excluded) then break end end if (not excluded) then table.insert(files, fname) end end cfg.files = files for name, field in pairs(premake.fields) do if field.isflags then local values = cfg[name] for _, flag in ipairs(values) do values[flag] = true end end end cfg.__fileconfigs = { } for _, fname in ipairs(cfg.files) do cfg.terms.required = fname:lower() local fcfg = {} for _, blk in ipairs(cfg.project.blocks) do if (premake.iskeywordsmatch(blk.keywords, cfg.terms)) then mergeobject(fcfg, blk) end end fcfg.name = fname cfg.__fileconfigs[fname] = fcfg table.insert(cfg.__fileconfigs, fcfg) end end local function builduniquedirs() local num_variations = 4 local cfg_dirs = {} local hit_counts = {} for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do for _, cfg in pairs(prj.__configs) do local dirs = { } dirs[1] = path.getabsolute(path.join(cfg.location, cfg.objdir or cfg.project.objdir or "obj")) dirs[2] = path.join(dirs[1], iif(cfg.platform == "Native", "", cfg.platform)) dirs[3] = path.join(dirs[2], cfg.name) dirs[4] = path.join(dirs[3], cfg.project.name) cfg_dirs[cfg] = dirs local start = iif(cfg.name, 2, 1) for v = start, num_variations do local d = dirs[v] hit_counts[d] = (hit_counts[d] or 0) + 1 end end end end for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do for _, cfg in pairs(prj.__configs) do local dir local start = iif(cfg.name, 2, 1) for v = start, num_variations do dir = cfg_dirs[cfg][v] if hit_counts[dir] == 1 then break end end cfg.objectsdir = path.getrelative(cfg.location, dir) end end end end local function buildtargets() for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do for _, cfg in pairs(prj.__configs) do local pathstyle = premake.getpathstyle(cfg) local namestyle = premake.getnamestyle(cfg) cfg.buildtarget = premake.gettarget(cfg, "build", pathstyle, namestyle, cfg.system) cfg.linktarget = premake.gettarget(cfg, "link", pathstyle, namestyle, cfg.system) if pathstyle == "windows" then cfg.objectsdir = path.translate(cfg.objectsdir, "\\") end end end end end function premake.buildconfigs() for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do prj.location = prj.location or sln.location or prj.basedir adjustpaths(prj.location, prj) for _, blk in ipairs(prj.blocks) do adjustpaths(prj.location, blk) end end sln.location = sln.location or sln.basedir end for sln in premake.solution.each() do local basis = collapse(sln) for _, prj in ipairs(sln.projects) do prj.__configs = collapse(prj, basis) for _, cfg in pairs(prj.__configs) do postprocess(prj, cfg) end end end builduniquedirs() buildtargets(cfg) end premake.fields = { basedir = { kind = "path", scope = "container", }, buildaction = { kind = "string", scope = "config", allowed = { "Compile", "Copy", "Embed", "None" } }, buildoptions = { kind = "list", scope = "config", }, configurations = { kind = "list", scope = "solution", }, defines = { kind = "list", scope = "config", }, deploymentoptions = { kind = "list", scope = "config", }, excludes = { kind = "filelist", scope = "config", }, files = { kind = "filelist", scope = "config", }, flags = { kind = "list", scope = "config", isflags = true, allowed = { "EnableSSE", "EnableSSE2", "ExtraWarnings", "FatalWarnings", "FloatFast", "FloatStrict", "Managed", "MFC", "NativeWChar", "No64BitChecks", "NoEditAndContinue", "NoExceptions", "NoFramePointer", "NoImportLib", "NoManifest", "NoMinimalRebuild", "NoNativeWChar", "NoPCH", "NoRTTI", "Optimize", "OptimizeSize", "OptimizeSpeed", "SEH", "StaticRuntime", "Symbols", "Unicode", "Unsafe", "WinMain" } }, framework = { kind = "string", scope = "container", allowed = { "1.0", "1.1", "2.0", "3.0", "3.5", "4.0" } }, imagepath = { kind = "path", scope = "config", }, imageoptions = { kind = "list", scope = "config", }, implibdir = { kind = "path", scope = "config", }, implibextension = { kind = "string", scope = "config", }, implibname = { kind = "string", scope = "config", }, implibprefix = { kind = "string", scope = "config", }, implibsuffix = { kind = "string", scope = "config", }, includedirs = { kind = "dirlist", scope = "config", }, kind = { kind = "string", scope = "config", allowed = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" } }, language = { kind = "string", scope = "container", allowed = { "C", "C++", "C#" } }, libdirs = { kind = "dirlist", scope = "config", }, linkoptions = { kind = "list", scope = "config", }, links = { kind = "list", scope = "config", allowed = function(value) if value:find('/', nil, true) then value = path.getabsolute(value) end return value end }, location = { kind = "path", scope = "container", }, objdir = { kind = "path", scope = "config", }, pchheader = { kind = "string", scope = "config", }, pchsource = { kind = "path", scope = "config", }, platforms = { kind = "list", scope = "solution", allowed = table.keys(premake.platforms), }, postbuildcommands = { kind = "list", scope = "config", }, prebuildcommands = { kind = "list", scope = "config", }, prelinkcommands = { kind = "list", scope = "config", }, resdefines = { kind = "list", scope = "config", }, resincludedirs = { kind = "dirlist", scope = "config", }, resoptions = { kind = "list", scope = "config", }, targetdir = { kind = "path", scope = "config", }, targetextension = { kind = "string", scope = "config", }, targetname = { kind = "string", scope = "config", }, targetprefix = { kind = "string", scope = "config", }, targetsuffix = { kind = "string", scope = "config", }, trimpaths = { kind = "dirlist", scope = "config", }, uuid = { kind = "string", scope = "container", allowed = function(value) local ok = true if (#value ~= 36) then ok = false end for i=1,36 do local ch = value:sub(i,i) if (not ch:find("[ABCDEFabcdef0123456789-]")) then ok = false end end if (value:sub(9,9) ~= "-") then ok = false end if (value:sub(14,14) ~= "-") then ok = false end if (value:sub(19,19) ~= "-") then ok = false end if (value:sub(24,24) ~= "-") then ok = false end if (not ok) then return nil, "invalid UUID" end return value:upper() end }, } function premake.checkvalue(value, allowed) if (allowed) then if (type(allowed) == "function") then return allowed(value) else for _,v in ipairs(allowed) do if (value:lower() == v:lower()) then return v end end return nil, "invalid value '" .. value .. "'" end else return value end end function premake.getobject(t) local container if (t == "container" or t == "solution") then container = premake.CurrentContainer else container = premake.CurrentConfiguration end if t == "solution" then if type(container) == "project" then container = container.solution end if type(container) ~= "solution" then container = nil end end local msg if (not container) then if (t == "container") then msg = "no active solution or project" elseif (t == "solution") then msg = "no active solution" else msg = "no active solution, project, or configuration" end end return container, msg end function premake.setarray(ctype, fieldname, value, allowed) local container, err = premake.getobject(ctype) if (not container) then error(err, 4) end if (not container[fieldname]) then container[fieldname] = { } end local function doinsert(value, depth) if (type(value) == "table") then for _,v in ipairs(value) do doinsert(v, depth + 1) end else value, err = premake.checkvalue(value, allowed) if (not value) then error(err, depth) end table.insert(container[fieldname], value) end end if (value) then doinsert(value, 5) end return container[fieldname] end local function domatchedarray(ctype, fieldname, value, matchfunc) local result = { } function makeabsolute(value, depth) if (type(value) == "table") then for _, item in ipairs(value) do makeabsolute(item, depth + 1) end elseif type(value) == "string" then if value:find("*") then makeabsolute(matchfunc(value), depth + 1) else table.insert(result, path.getabsolute(value)) end else error("Invalid value in list: expected string, got " .. type(value), depth) end end makeabsolute(value, 3) return premake.setarray(ctype, fieldname, result) end function premake.setdirarray(ctype, fieldname, value) return domatchedarray(ctype, fieldname, value, os.matchdirs) end function premake.setfilearray(ctype, fieldname, value) return domatchedarray(ctype, fieldname, value, os.matchfiles) end function premake.setstring(ctype, fieldname, value, allowed) local container, err = premake.getobject(ctype) if (not container) then error(err, 4) end if (value) then value, err = premake.checkvalue(value, allowed) if (not value) then error(err, 4) end container[fieldname] = value end return container[fieldname] end local function accessor(name, value) local kind = premake.fields[name].kind local scope = premake.fields[name].scope local allowed = premake.fields[name].allowed if ((kind == "string" or kind == "path") and value) then if type(value) ~= "string" then error("string value expected", 3) end end if (kind == "string") then return premake.setstring(scope, name, value, allowed) elseif (kind == "path") then if value then value = path.getabsolute(value) end return premake.setstring(scope, name, value) elseif (kind == "list") then return premake.setarray(scope, name, value, allowed) elseif (kind == "dirlist") then return premake.setdirarray(scope, name, value) elseif (kind == "filelist") then return premake.setfilearray(scope, name, value) end end for name,_ in pairs(premake.fields) do _G[name] = function(value) return accessor(name, value) end end function configuration(terms) if not terms then return premake.CurrentConfiguration end local container, err = premake.getobject("container") if (not container) then error(err, 2) end local cfg = { } cfg.terms = table.flatten({terms}) table.insert(container.blocks, cfg) premake.CurrentConfiguration = cfg cfg.keywords = { } for _, word in ipairs(cfg.terms) do table.insert(cfg.keywords, path.wildcards(word):lower()) end for name, field in pairs(premake.fields) do if (field.kind ~= "string" and field.kind ~= "path") then cfg[name] = { } end end return cfg end function project(name) if not name then return iif(type(premake.CurrentContainer) == "project", premake.CurrentContainer, nil) end local sln if (type(premake.CurrentContainer) == "project") then sln = premake.CurrentContainer.solution else sln = premake.CurrentContainer end if (type(sln) ~= "solution") then error("no active solution", 2) end premake.CurrentContainer = sln.projects[name] if (not premake.CurrentContainer) then local prj = { } premake.CurrentContainer = prj table.insert(sln.projects, prj) sln.projects[name] = prj setmetatable(prj, { __type = "project", }) prj.solution = sln prj.name = name prj.basedir = os.getcwd() prj.uuid = os.uuid() prj.blocks = { } end configuration { } return premake.CurrentContainer end function solution(name) if not name then if type(premake.CurrentContainer) == "project" then return premake.CurrentContainer.solution else return premake.CurrentContainer end end premake.CurrentContainer = premake.solution.get(name) if (not premake.CurrentContainer) then premake.CurrentContainer = premake.solution.new(name) end configuration { } return premake.CurrentContainer end function newaction(a) premake.action.add(a) end function newoption(opt) premake.option.add(opt) end newoption { trigger = "cc", value = "VALUE", description = "Choose a C/C++ compiler set", allowed = { { "gcc", "GNU GCC (gcc/g++)" }, { "ow", "OpenWatcom" }, } } newoption { trigger = "dotnet", value = "VALUE", description = "Choose a .NET compiler set", allowed = { { "msnet", "Microsoft .NET (csc)" }, { "mono", "Novell Mono (mcs)" }, { "pnet", "Portable.NET (cscc)" }, } } newoption { trigger = "file", value = "FILE", description = "Read FILE as a Premake script; default is 'premake4.lua'" } newoption { trigger = "help", description = "Display this information" } newoption { trigger = "os", value = "VALUE", description = "Generate files for a different operating system", allowed = { { "bsd", "OpenBSD, NetBSD, or FreeBSD" }, { "linux", "Linux" }, { "macosx", "Apple Mac OS X" }, { "solaris", "Solaris" }, { "windows", "Microsoft Windows" }, } } newoption { trigger = "platform", value = "VALUE", description = "Add target architecture (if supported by action)", allowed = { { "x32", "32-bit" }, { "x64", "64-bit" }, { "universal", "Mac OS X Universal, 32- and 64-bit" }, { "universal32", "Mac OS X Universal, 32-bit only" }, { "universal64", "Mac OS X Universal, 64-bit only" }, { "ps3", "Playstation 3 (experimental)" }, { "xbox360", "Xbox 360 (experimental)" }, } } newoption { trigger = "scripts", value = "path", description = "Search for additional scripts on the given path" } newoption { trigger = "version", description = "Display version information" } premake.dotnet = { } premake.dotnet.namestyle = "windows" local flags = { FatalWarning = "/warnaserror", Optimize = "/optimize", OptimizeSize = "/optimize", OptimizeSpeed = "/optimize", Symbols = "/debug", Unsafe = "/unsafe" } function premake.dotnet.getbuildaction(fcfg) local ext = path.getextension(fcfg.name):lower() if fcfg.buildaction == "Compile" or ext == ".cs" then return "Compile" elseif fcfg.buildaction == "Embed" or ext == ".resx" then return "EmbeddedResource" elseif fcfg.buildaction == "Copy" or ext == ".asax" or ext == ".aspx" then return "Content" else return "None" end end function premake.dotnet.getcompilervar(cfg) if (_OPTIONS.dotnet == "msnet") then return "csc" elseif (_OPTIONS.dotnet == "mono") then if (cfg.framework <= "1.1") then return "mcs" elseif (cfg.framework >= "4.0") then return "dmcs" else return "gmcs" end else return "cscc" end end function premake.dotnet.getflags(cfg) local result = table.translate(cfg.flags, flags) return result end function premake.dotnet.getkind(cfg) if (cfg.kind == "ConsoleApp") then return "Exe" elseif (cfg.kind == "WindowedApp") then return "WinExe" elseif (cfg.kind == "SharedLib") then return "Library" end endpremake.gcc = { } premake.gcc.cc = "gcc" premake.gcc.cxx = "g++" premake.gcc.ar = "ar" local cflags = { EnableSSE = "-msse", EnableSSE2 = "-msse2", ExtraWarnings = "-Wall", FatalWarnings = "-Werror", FloatFast = "-ffast-math", FloatStrict = "-ffloat-store", NoFramePointer = "-fomit-frame-pointer", Optimize = "-O2", OptimizeSize = "-Os", OptimizeSpeed = "-O3", Symbols = "-g", } local cxxflags = { NoExceptions = "-fno-exceptions", NoRTTI = "-fno-rtti", } premake.gcc.platforms = { Native = { cppflags = "-MMD -MP", }, x32 = { cppflags = "-MMD -MP", flags = "-m32", ldflags = "-L/usr/lib32", }, x64 = { cppflags = "-MMD -MP", flags = "-m64", ldflags = "-L/usr/lib64", }, Universal = { cppflags = "", flags = "-arch i386 -arch x86_64 -arch ppc -arch ppc64", }, Universal32 = { cppflags = "", flags = "-arch i386 -arch ppc", }, Universal64 = { cppflags = "", flags = "-arch x86_64 -arch ppc64", }, PS3 = { cc = "ppu-lv2-g++", cxx = "ppu-lv2-g++", ar = "ppu-lv2-ar", cppflags = "-MMD -MP", } } local platforms = premake.gcc.platforms function premake.gcc.getcppflags(cfg) local result = { } table.insert(result, platforms[cfg.platform].cppflags) return result end function premake.gcc.getcflags(cfg) local result = table.translate(cfg.flags, cflags) table.insert(result, platforms[cfg.platform].flags) if cfg.system ~= "windows" and cfg.kind == "SharedLib" then table.insert(result, "-fPIC") end return result end function premake.gcc.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.gcc.getldflags(cfg) local result = { } if not cfg.flags.Symbols then if cfg.system == "macosx" then table.insert(result, "-Wl,-x") else table.insert(result, "-s") end end if cfg.kind == "SharedLib" then if cfg.system == "macosx" then result = table.join(result, { "-dynamiclib", "-flat_namespace" }) else table.insert(result, "-shared") end if cfg.system == "windows" and not cfg.flags.NoImportLib then table.insert(result, '-Wl,--out-implib="' .. cfg.linktarget.fullpath .. '"') end end if cfg.kind == "WindowedApp" and cfg.system == "windows" then table.insert(result, "-mwindows") end local platform = platforms[cfg.platform] table.insert(result, platform.flags) table.insert(result, platform.ldflags) return result end function premake.gcc.getlibdirflags(cfg) local result = { } for _, value in ipairs(premake.getlinks(cfg, "all", "directory")) do table.insert(result, '-L' .. _MAKE.esc(value)) end return result end function premake.gcc.getlinkflags(cfg) local result = { } for _, value in ipairs(premake.getlinks(cfg, "all", "basename")) do if path.getextension(value) == ".framework" then table.insert(result, '-framework ' .. _MAKE.esc(path.getbasename(value))) else table.insert(result, '-l' .. _MAKE.esc(value)) end end return result end function premake.gcc.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, '-D' .. def) end return result end function premake.gcc.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, "-I" .. _MAKE.esc(dir)) end return result end premake.msc = { } premake.msc.namestyle = "windows" premake.ow = { } premake.ow.namestyle = "windows" premake.ow.cc = "WCL386" premake.ow.cxx = "WCL386" premake.ow.ar = "ar" local cflags = { ExtraWarnings = "-wx", FatalWarning = "-we", FloatFast = "-omn", FloatStrict = "-op", Optimize = "-ox", OptimizeSize = "-os", OptimizeSpeed = "-ot", Symbols = "-d2", } local cxxflags = { NoExceptions = "-xd", NoRTTI = "-xr", } premake.ow.platforms = { Native = { flags = "" }, } function premake.ow.getcppflags(cfg) return {} end function premake.ow.getcflags(cfg) local result = table.translate(cfg.flags, cflags) if (cfg.flags.Symbols) then table.insert(result, "-hw") -- Watcom debug format for Watcom debugger end return result end function premake.ow.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.ow.getldflags(cfg) local result = { } if (cfg.flags.Symbols) then table.insert(result, "op symf") end return result end function premake.ow.getlinkflags(cfg) local result = { } return result end function premake.ow.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, '-D' .. def) end return result end function premake.ow.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, '-I "' .. dir .. '"') end return result end function premake.checkprojects() local action = premake.action.current() for sln in premake.solution.each() do if (#sln.projects == 0) then return nil, "solution '" .. sln.name .. "' needs at least one project" end if (#sln.configurations == 0) then return nil, "solution '" .. sln.name .. "' needs configurations" end for prj in premake.solution.eachproject(sln) do if (not prj.language) then return nil, "project '" ..prj.name .. "' needs a language" end if (action.valid_languages) then if (not table.contains(action.valid_languages, prj.language)) then return nil, "the " .. action.shortname .. " action does not support " .. prj.language .. " projects" end end for cfg in premake.eachconfig(prj) do if (not cfg.kind) then return nil, "project '" ..prj.name .. "' needs a kind in configuration '" .. cfg.name .. "'" end if (action.valid_kinds) then if (not table.contains(action.valid_kinds, cfg.kind)) then return nil, "the " .. action.shortname .. " action does not support " .. cfg.kind .. " projects" end end end if action.oncheckproject then action.oncheckproject(prj) end end end return true end function premake.checktools() local action = premake.action.current() if (not action.valid_tools) then return true end for tool, values in pairs(action.valid_tools) do if (_OPTIONS[tool]) then if (not table.contains(values, _OPTIONS[tool])) then return nil, "the " .. action.shortname .. " action does not support /" .. tool .. "=" .. _OPTIONS[tool] .. " (yet)" end else _OPTIONS[tool] = values[1] end end return true end function premake.showhelp() printf("Premake %s, a build script generator", _PREMAKE_VERSION) printf(_PREMAKE_COPYRIGHT) printf("%s %s", _VERSION, _COPYRIGHT) printf("") printf("Usage: premake4 [options] action [arguments]") printf("") printf("OPTIONS") printf("") for option in premake.option.each() do local trigger = option.trigger local description = option.description if (option.value) then trigger = trigger .. "=" .. option.value end if (option.allowed) then description = description .. "; one of:" end printf(" --%-15s %s", trigger, description) if (option.allowed) then for _, value in ipairs(option.allowed) do printf(" %-14s %s", value[1], value[2]) end end printf("") end printf("ACTIONS") printf("") for action in premake.action.each() do printf(" %-17s %s", action.trigger, action.description) end printf("") printf("For additional information, see http://industriousone.com/premake") end function premake.generate(obj, filename, callback) filename = premake.project.getfilename(obj, filename) printf("Generating %s...", filename) local f, err = io.open(filename, "wb") if (not f) then error(err, 0) end io.output(f) callback(obj) f:close() end newaction { trigger = "codeblocks", shortname = "Code::Blocks", description = "Generate Code::Blocks project files", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc", "ow" }, }, onsolution = function(sln) premake.generate(sln, "%%.workspace", premake.codeblocks_workspace) end, onproject = function(prj) premake.generate(prj, "%%.cbp", premake.codeblocks_cbp) end, oncleansolution = function(sln) premake.clean.file(sln, "%%.workspace") end, oncleanproject = function(prj) premake.clean.file(prj, "%%.cbp") premake.clean.file(prj, "%%.depend") premake.clean.file(prj, "%%.layout") end } function premake.codeblocks_workspace(sln) _p('') _p('') _p(1,'', sln.name) for prj in premake.solution.eachproject(sln) do local fname = path.join(path.getrelative(sln.location, prj.location), prj.name) local active = iif(prj.project == sln.projects[1], ' active="1"', '') _p(2,'', fname, active) for _,dep in ipairs(premake.getdependencies(prj)) do _p(3,'', path.join(path.getrelative(sln.location, dep.location), dep.name)) end _p(2,'') end _p(1,'') _p('') end function premake.codeblocks_cbp(prj) local cc = premake.gettool(prj) _p('') _p('') _p(1,'') _p(1,'') _p(2,'') _p('') _p('') end newaction { trigger = "codelite", shortname = "CodeLite", description = "Generate CodeLite project files", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, onsolution = function(sln) premake.generate(sln, "%%.workspace", premake.codelite_workspace) end, onproject = function(prj) premake.generate(prj, "%%.project", premake.codelite_project) end, oncleansolution = function(sln) premake.clean.file(sln, "%%.workspace") premake.clean.file(sln, "%%_wsp.mk") premake.clean.file(sln, "%%.tags") end, oncleanproject = function(prj) premake.clean.file(prj, "%%.project") premake.clean.file(prj, "%%.mk") premake.clean.file(prj, "%%.list") premake.clean.file(prj, "%%.out") end } function premake.codelite_workspace(sln) _p('') _p('', premake.esc(sln.name), premake.esc(sln.name)) for i,prj in ipairs(sln.projects) do local name = premake.esc(prj.name) local fname = path.join(path.getrelative(sln.location, prj.location), prj.name) local active = iif(i==1, "Yes", "No") _p(' ', name, fname, active) end local platforms = premake.filterplatforms(sln, premake[_OPTIONS.cc].platforms, "Native") for i = #platforms, 1, -1 do if premake.platforms[platforms[i]].iscrosscompiler then table.remove(platforms, i) end end _p(' ') for _, platform in ipairs(platforms) do for _, cfgname in ipairs(sln.configurations) do local name = premake.getconfigname(cfgname, platform) _p(' ', name) for _,prj in ipairs(sln.projects) do _p(' ', prj.name, name) end _p(' ') end end _p(' ') _p('') end function premake.codelite_project(prj) _p('') _p('', premake.esc(prj.name)) premake.walksources(prj, premake.codelite_files) local types = { ConsoleApp = "Executable", WindowedApp = "Executable", StaticLib = "Static Library", SharedLib = "Dynamic Library", } _p(' ', types[prj.kind]) local platforms = premake.filterplatforms(prj.solution, premake[_OPTIONS.cc].platforms, "Native") for i = #platforms, 1, -1 do if premake.platforms[platforms[i]].iscrosscompiler then table.remove(platforms, i) end end for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do local name = premake.esc(cfg.longname) local compiler = iif(cfg.language == "C", "gcc", "g++") _p(' ', name, compiler, types[cfg.kind]) local fname = premake.esc(cfg.buildtarget.fullpath) local objdir = premake.esc(cfg.objectsdir) local runcmd = cfg.buildtarget.name local rundir = cfg.buildtarget.directory local pause = iif(cfg.kind == "WindowedApp", "no", "yes") _p(' ', fname, objdir, runcmd, rundir, pause) local flags = premake.esc(table.join(premake.gcc.getcflags(cfg), premake.gcc.getcxxflags(cfg), cfg.buildoptions)) _p(' ', table.concat(flags, ";")) for _,v in ipairs(cfg.includedirs) do _p(' ', premake.esc(v)) end for _,v in ipairs(cfg.defines) do _p(' ', premake.esc(v)) end _p(' ') flags = premake.esc(table.join(premake.gcc.getldflags(cfg), cfg.linkoptions)) _p(' ', table.concat(flags, ";")) for _,v in ipairs(premake.getlinks(cfg, "all", "directory")) do _p(' ', premake.esc(v)) end for _,v in ipairs(premake.getlinks(cfg, "all", "basename")) do _p(' ', premake.esc(v)) end _p(' ') if premake.findfile(cfg, ".rc") then local defines = table.implode(table.join(cfg.defines, cfg.resdefines), "-D", ";", "") local options = table.concat(cfg.resoptions, ";") _p(' ', defines, options) for _,v in ipairs(table.join(cfg.includedirs, cfg.resincludedirs)) do _p(' ', premake.esc(v)) end _p(' ') else _p(' ') end if #cfg.prebuildcommands > 0 then _p(' ') for _,v in ipairs(cfg.prebuildcommands) do _p(' %s', premake.esc(v)) end _p(' ') end if #cfg.postbuildcommands > 0 then _p(' ') for _,v in ipairs(cfg.postbuildcommands) do _p(' %s', premake.esc(v)) end _p(' ') end _p(' ') _p(' ') _p(' ') _p(' ') _p(' ') _p(' None') _p(' ') _p(' ') _p(' ') _p(' ') _p(' ') _p(' ') _p(' ') end end _p(' ') for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do _p(' ', cfg.longname) for _,dep in ipairs(premake.getdependencies(prj)) do _p(' ', dep.name) end _p(' ') end end _p('') end function premake.codelite_files(prj, fname, state, nestlevel) local indent = string.rep(" ", nestlevel + 1) if (state == "GroupStart") then io.write(indent .. '\n') elseif (state == "GroupEnd") then io.write(indent .. '\n') else io.write(indent .. '\n') end end _MAKE = { } premake.make = { } function _MAKE.esc(value) local result if (type(value) == "table") then result = { } for _,v in ipairs(value) do table.insert(result, _MAKE.esc(v)) end return result else result = value:gsub("\\", "\\\\") result = result:gsub(" ", "\\ ") result = result:gsub("%(", "\\%(") result = result:gsub("%)", "\\%)") result = result:gsub("$\\%((.-)\\%)", "$%(%1%)") return result end end function premake.make_copyrule(source, target) _p('%s: %s', target, source) _p('\t@echo Copying $(notdir %s)', target) _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) cp -fR %s %s', source, target) _p('else') _p('\t$(SILENT) copy /Y $(subst /,\\\\,%s) $(subst /,\\\\,%s)', source, target) _p('endif') end function premake.make_mkdirrule(var) _p('\t@echo Creating %s', var) _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) mkdir -p %s', var) _p('else') _p('\t$(SILENT) mkdir $(subst /,\\\\,%s)', var) _p('endif') _p('') end function _MAKE.getmakefilename(this, searchprjs) local count = 0 for sln in premake.solution.each() do if (sln.location == this.location) then count = count + 1 end if (searchprjs) then for _,prj in ipairs(sln.projects) do if (prj.location == this.location) then count = count + 1 end end end end if (count == 1) then return "Makefile" else return this.name .. ".make" end end function _MAKE.getnames(tbl) local result = table.extract(tbl, "name") for k,v in pairs(result) do result[k] = _MAKE.esc(v) end return result end newaction { trigger = "gmake", shortname = "GNU Make", description = "Generate GNU makefiles for POSIX, MinGW, and Cygwin", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "gcc" }, dotnet = { "mono", "msnet", "pnet" }, }, onsolution = function(sln) premake.generate(sln, _MAKE.getmakefilename(sln, false), premake.make_solution) end, onproject = function(prj) local makefile = _MAKE.getmakefilename(prj, true) if premake.isdotnetproject(prj) then premake.generate(prj, makefile, premake.make_csharp) else premake.generate(prj, makefile, premake.make_cpp) end end, oncleansolution = function(sln) premake.clean.file(sln, _MAKE.getmakefilename(sln, false)) end, oncleanproject = function(prj) premake.clean.file(prj, _MAKE.getmakefilename(prj, true)) end } function premake.make_solution(sln) local cc = premake[_OPTIONS.cc] local platforms = premake.filterplatforms(sln, cc.platforms, "Native") _p('# %s solution makefile autogenerated by Premake', premake.action.current().shortname) _p('# Type "make help" for usage help') _p('') _p('ifndef config') _p(' config=%s', _MAKE.esc(premake.getconfigname(sln.configurations[1], platforms[1], true))) _p('endif') _p('export config') _p('') _p('PROJECTS := %s', table.concat(_MAKE.esc(table.extract(sln.projects, "name")), " ")) _p('') _p('.PHONY: all clean help $(PROJECTS)') _p('') _p('all: $(PROJECTS)') _p('') for _, prj in ipairs(sln.projects) do _p('%s: %s', _MAKE.esc(prj.name), table.concat(_MAKE.esc(table.extract(premake.getdependencies(prj), "name")), " ")) _p('\t@echo "==== Building %s ($(config)) ===="', prj.name) _p('\t@${MAKE} --no-print-directory -C %s -f %s', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(_MAKE.getmakefilename(prj, true))) _p('') end _p('clean:') for _ ,prj in ipairs(sln.projects) do _p('\t@${MAKE} --no-print-directory -C %s -f %s clean', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(_MAKE.getmakefilename(prj, true))) end _p('') _p('help:') _p(1,'@echo "Usage: make [config=name] [target]"') _p(1,'@echo ""') _p(1,'@echo "CONFIGURATIONS:"') local cfgpairs = { } for _, platform in ipairs(platforms) do for _, cfgname in ipairs(sln.configurations) do _p(1,'@echo " %s"', premake.getconfigname(cfgname, platform, true)) end end _p(1,'@echo ""') _p(1,'@echo "TARGETS:"') _p(1,'@echo " all (default)"') _p(1,'@echo " clean"') for _, prj in ipairs(sln.projects) do _p(1,'@echo " %s"', prj.name) end _p(1,'@echo ""') _p(1,'@echo "For more information, see http://industriousone.com/premake/quick-start"') end premake.make.cpp = { } local _ = premake.make.cpp function premake.make_cpp(prj) local cc = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native") premake.gmake_cpp_header(prj, cc, platforms) for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do premake.gmake_cpp_config(cfg, cc) end end _p('OBJECTS := \\') for _, file in ipairs(prj.files) do if path.iscppfile(file) then _p('\t$(OBJDIR)/%s.o \\', _MAKE.esc(path.getbasename(file))) end end _p('') _p('RESOURCES := \\') for _, file in ipairs(prj.files) do if path.isresourcefile(file) then _p('\t$(OBJDIR)/%s.res \\', _MAKE.esc(path.getbasename(file))) end end _p('') _p('SHELLTYPE := msdos') _p('ifeq (,$(ComSpec)$(COMSPEC))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('') _p('.PHONY: clean prebuild prelink') _p('') if os.is("MacOSX") and prj.kind == "WindowedApp" then _p('all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist') else _p('all: $(TARGETDIR) $(OBJDIR) prebuild prelink $(TARGET)') end _p('\t@:') _p('') _p('$(TARGET): $(GCH) $(OBJECTS) $(LDDEPS) $(RESOURCES)') _p('\t@echo Linking %s', prj.name) _p('\t$(SILENT) $(LINKCMD)') _p('\t$(POSTBUILDCMDS)') _p('') _p('$(TARGETDIR):') premake.make_mkdirrule("$(TARGETDIR)") _p('$(OBJDIR):') premake.make_mkdirrule("$(OBJDIR)") if os.is("MacOSX") and prj.kind == "WindowedApp" then _p('$(dir $(TARGETDIR))PkgInfo:') _p('$(dir $(TARGETDIR))Info.plist:') _p('') end _p('clean:') _p('\t@echo Cleaning %s', prj.name) _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) rm -f $(TARGET)') _p('\t$(SILENT) rm -rf $(OBJDIR)') _p('else') _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))') _p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))') _p('endif') _p('') _p('prebuild:') _p('\t$(PREBUILDCMDS)') _p('') _p('prelink:') _p('\t$(PRELINKCMDS)') _p('') _.pchrules(prj) for _, file in ipairs(prj.files) do if path.iscppfile(file) then _p('$(OBJDIR)/%s.o: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) _p('\t@echo $(notdir $<)') if (path.iscfile(file)) then _p('\t$(SILENT) $(CC) $(CFLAGS) -o "$@" -c "$<"') else _p('\t$(SILENT) $(CXX) $(CXXFLAGS) -o "$@" -c "$<"') end elseif (path.getextension(file) == ".rc") then _p('$(OBJDIR)/%s.res: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) _p('\t@echo $(notdir $<)') _p('\t$(SILENT) windres $< -O coff -o "$@" $(RESFLAGS)') end end _p('') _p('-include $(OBJECTS:%%.o=%%.d)') end function premake.gmake_cpp_header(prj, cc, platforms) _p('# %s project makefile autogenerated by Premake', premake.action.current().shortname) _p('ifndef config') _p(' config=%s', _MAKE.esc(premake.getconfigname(prj.solution.configurations[1], platforms[1], true))) _p('endif') _p('') _p('ifndef verbose') _p(' SILENT = @') _p('endif') _p('') _p('ifndef CC') _p(' CC = %s', cc.cc) _p('endif') _p('') _p('ifndef CXX') _p(' CXX = %s', cc.cxx) _p('endif') _p('') _p('ifndef AR') _p(' AR = %s', cc.ar) _p('endif') _p('') end function premake.gmake_cpp_config(cfg, cc) _p('ifeq ($(config),%s)', _MAKE.esc(cfg.shortname)) local platform = cc.platforms[cfg.platform] if platform.cc then _p(' CC = %s', platform.cc) end if platform.cxx then _p(' CXX = %s', platform.cxx) end if platform.ar then _p(' AR = %s', platform.ar) end _p(' OBJDIR = %s', _MAKE.esc(cfg.objectsdir)) _p(' TARGETDIR = %s', _MAKE.esc(cfg.buildtarget.directory)) _p(' TARGET = $(TARGETDIR)/%s', _MAKE.esc(cfg.buildtarget.name)) _p(' DEFINES += %s', table.concat(cc.getdefines(cfg.defines), " ")) _p(' INCLUDES += %s', table.concat(cc.getincludedirs(cfg.includedirs), " ")) _p(' CPPFLAGS += %s $(DEFINES) $(INCLUDES)', table.concat(cc.getcppflags(cfg), " ")) _.pchconfig(cfg) _p(' CFLAGS += $(CPPFLAGS) $(ARCH) %s', table.concat(table.join(cc.getcflags(cfg), cfg.buildoptions), " ")) _p(' CXXFLAGS += $(CFLAGS) %s', table.concat(cc.getcxxflags(cfg), " ")) _p(' LDFLAGS += %s', table.concat(table.join(cc.getldflags(cfg), cfg.linkoptions, cc.getlibdirflags(cfg)), " ")) _p(' LIBS += %s', table.concat(cc.getlinkflags(cfg), " ")) _p(' RESFLAGS += $(DEFINES) $(INCLUDES) %s', table.concat(table.join(cc.getdefines(cfg.resdefines), cc.getincludedirs(cfg.resincludedirs), cfg.resoptions), " ")) _p(' LDDEPS += %s', table.concat(_MAKE.esc(premake.getlinks(cfg, "siblings", "fullpath")), " ")) if cfg.kind == "StaticLib" then if cfg.platform:startswith("Universal") then _p(' LINKCMD = libtool -o $(TARGET) $(OBJECTS)') else _p(' LINKCMD = $(AR) -rcs $(TARGET) $(OBJECTS)') end else _p(' LINKCMD = $(%s) -o $(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(ARCH) $(LIBS)', iif(cfg.language == "C", "CC", "CXX")) end _p(' define PREBUILDCMDS') if #cfg.prebuildcommands > 0 then _p('\t@echo Running pre-build commands') _p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t")) end _p(' endef') _p(' define PRELINKCMDS') if #cfg.prelinkcommands > 0 then _p('\t@echo Running pre-link commands') _p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t")) end _p(' endef') _p(' define POSTBUILDCMDS') if #cfg.postbuildcommands > 0 then _p('\t@echo Running post-build commands') _p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t")) end _p(' endef') _p('endif') _p('') end function _.pchconfig(cfg) if not cfg.flags.NoPCH and cfg.pchheader then _p(' PCH = %s', _MAKE.esc(path.getrelative(cfg.location, cfg.pchheader))) _p(' GCH = $(OBJDIR)/%s.gch', _MAKE.esc(path.getname(cfg.pchheader))) _p(' CPPFLAGS += -I$(OBJDIR) -include $(OBJDIR)/%s', _MAKE.esc(path.getname(cfg.pchheader))) end end function _.pchrules(prj) _p('ifneq (,$(PCH))') _p('$(GCH): $(PCH)') _p('\t@echo $(notdir $<)') _p('\t-$(SILENT) cp $< $(OBJDIR)') if prj.language == "C" then _p('\t$(SILENT) $(CC) $(CFLAGS) -o "$@" -c "$<"') else _p('\t$(SILENT) $(CXX) $(CXXFLAGS) -o "$@" -c "$<"') end _p('endif') _p('') end local function getresourcefilename(cfg, fname) if path.getextension(fname) == ".resx" then local name = cfg.buildtarget.basename .. "." local dir = path.getdirectory(fname) if dir ~= "." then name = name .. path.translate(dir, ".") .. "." end return "$(OBJDIR)/" .. _MAKE.esc(name .. path.getbasename(fname)) .. ".resources" else return fname end end function premake.make_csharp(prj) local csc = premake.dotnet local cfglibs = { } local cfgpairs = { } local anycfg for cfg in premake.eachconfig(prj) do anycfg = cfg cfglibs[cfg] = premake.getlinks(cfg, "siblings", "fullpath") cfgpairs[cfg] = { } for _, fname in ipairs(cfglibs[cfg]) do if path.getdirectory(fname) ~= cfg.buildtarget.directory then cfgpairs[cfg]["$(TARGETDIR)/" .. _MAKE.esc(path.getname(fname))] = _MAKE.esc(fname) end end end local sources = {} local embedded = { } local copypairs = { } for fcfg in premake.eachfile(prj) do local action = csc.getbuildaction(fcfg) if action == "Compile" then table.insert(sources, fcfg.name) elseif action == "EmbeddedResource" then table.insert(embedded, fcfg.name) elseif action == "Content" then copypairs["$(TARGETDIR)/" .. _MAKE.esc(path.getname(fcfg.name))] = _MAKE.esc(fcfg.name) elseif path.getname(fcfg.name):lower() == "app.config" then copypairs["$(TARGET).config"] = _MAKE.esc(fcfg.name) end end local paths = table.translate(prj.libdirs, function(v) return path.join(prj.basedir, v) end) paths = table.join({prj.basedir}, paths) for _, libname in ipairs(premake.getlinks(prj, "system", "fullpath")) do local libdir = os.pathsearch(libname..".dll", unpack(paths)) if (libdir) then local target = "$(TARGETDIR)/" .. _MAKE.esc(path.getname(libname)) local source = path.getrelative(prj.basedir, path.join(libdir, libname))..".dll" copypairs[target] = _MAKE.esc(source) end end _p('# %s project makefile autogenerated by Premake', premake.action.current().shortname) _p('') _p('ifndef config') _p(' config=%s', _MAKE.esc(prj.configurations[1]:lower())) _p('endif') _p('') _p('ifndef verbose') _p(' SILENT = @') _p('endif') _p('') _p('ifndef CSC') _p(' CSC=%s', csc.getcompilervar(prj)) _p('endif') _p('') _p('ifndef RESGEN') _p(' RESGEN=resgen') _p('endif') _p('') local platforms = premake.filterplatforms(prj.solution, premake[_OPTIONS.cc].platforms) table.insert(platforms, 1, "") for cfg in premake.eachconfig(prj) do premake.gmake_cs_config(cfg, csc, cfglibs) end _p('# To maintain compatibility with VS.NET, these values must be set at the project level') _p('TARGET := $(TARGETDIR)/%s', _MAKE.esc(prj.buildtarget.name)) _p('FLAGS += /t:%s %s', csc.getkind(prj):lower(), table.implode(_MAKE.esc(prj.libdirs), "/lib:", "", " ")) _p('REFERENCES += %s', table.implode(_MAKE.esc(premake.getlinks(prj, "system", "basename")), "/r:", ".dll", " ")) _p('') _p('SOURCES := \\') for _, fname in ipairs(sources) do _p('\t%s \\', _MAKE.esc(path.translate(fname))) end _p('') _p('EMBEDFILES := \\') for _, fname in ipairs(embedded) do _p('\t%s \\', getresourcefilename(prj, fname)) end _p('') _p('COPYFILES += \\') for target, source in pairs(cfgpairs[anycfg]) do _p('\t%s \\', target) end for target, source in pairs(copypairs) do _p('\t%s \\', target) end _p('') _p('SHELLTYPE := msdos') _p('ifeq (,$(ComSpec)$(COMSPEC))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('') _p('.PHONY: clean prebuild prelink') _p('') _p('all: $(TARGETDIR) $(OBJDIR) prebuild $(EMBEDFILES) $(COPYFILES) prelink $(TARGET)') _p('') _p('$(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS)') _p('\t$(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) $(SOURCES) $(patsubst %%,/resource:%%,$(EMBEDFILES))') _p('\t$(POSTBUILDCMDS)') _p('') _p('$(TARGETDIR):') premake.make_mkdirrule("$(TARGETDIR)") _p('$(OBJDIR):') premake.make_mkdirrule("$(OBJDIR)") _p('clean:') _p('\t@echo Cleaning %s', prj.name) _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) rm -f $(TARGETDIR)/%s.* $(COPYFILES)', prj.buildtarget.basename) _p('\t$(SILENT) rm -rf $(OBJDIR)') _p('else') _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGETDIR)/%s.*) del $(subst /,\\\\,$(TARGETDIR)/%s.*)', prj.buildtarget.basename, prj.buildtarget.basename) for target, source in pairs(cfgpairs[anycfg]) do _p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target) end for target, source in pairs(copypairs) do _p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target) end _p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))') _p('endif') _p('') _p('prebuild:') _p('\t$(PREBUILDCMDS)') _p('') _p('prelink:') _p('\t$(PRELINKCMDS)') _p('') _p('# Per-configuration copied file rules') for cfg in premake.eachconfig(prj) do _p('ifneq (,$(findstring %s,$(config)))', _MAKE.esc(cfg.name:lower())) for target, source in pairs(cfgpairs[cfg]) do premake.make_copyrule(source, target) end _p('endif') _p('') end _p('# Copied file rules') for target, source in pairs(copypairs) do premake.make_copyrule(source, target) end _p('# Embedded file rules') for _, fname in ipairs(embedded) do if path.getextension(fname) == ".resx" then _p('%s: %s', getresourcefilename(prj, fname), _MAKE.esc(fname)) _p('\t$(SILENT) $(RESGEN) $^ $@') end _p('') end end function premake.gmake_cs_config(cfg, csc, cfglibs) _p('ifneq (,$(findstring %s,$(config)))', _MAKE.esc(cfg.name:lower())) _p(' TARGETDIR := %s', _MAKE.esc(cfg.buildtarget.directory)) _p(' OBJDIR := %s', _MAKE.esc(cfg.objectsdir)) _p(' DEPENDS := %s', table.concat(_MAKE.esc(premake.getlinks(cfg, "dependencies", "fullpath")), " ")) _p(' REFERENCES := %s', table.implode(_MAKE.esc(cfglibs[cfg]), "/r:", "", " ")) _p(' FLAGS += %s %s', table.implode(cfg.defines, "/d:", "", " "), table.concat(table.join(csc.getflags(cfg), cfg.buildoptions), " ")) _p(' define PREBUILDCMDS') if #cfg.prebuildcommands > 0 then _p('\t@echo Running pre-build commands') _p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t")) end _p(' endef') _p(' define PRELINKCMDS') if #cfg.prelinkcommands > 0 then _p('\t@echo Running pre-link commands') _p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t")) end _p(' endef') _p(' define POSTBUILDCMDS') if #cfg.postbuildcommands > 0 then _p('\t@echo Running post-build commands') _p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t")) end _p(' endef') _p('endif') _p('') end _VS = { } -- deprecated, will remove eventually premake.vstudio = { } local vstudio = premake.vstudio premake.vstudio_platforms = { any = "Any CPU", mixed = "Mixed Platforms", Native = "Win32", x32 = "Win32", x64 = "x64", PS3 = "PS3", Xbox360 = "Xbox 360", } function _VS.arch(prj) if (prj.language == "C#") then if (_ACTION < "vs2005") then return ".NET" else return "Any CPU" end else return "Win32" end end function _VS.bool(value) if (_ACTION < "vs2005") then return iif(value, "TRUE", "FALSE") else return iif(value, "true", "false") end end function premake.vstudio_buildconfigs(sln) local cfgs = { } local platforms = premake.filterplatforms(sln, premake.vstudio_platforms, "Native") local hascpp = premake.hascppproject(sln) local hasdotnet = premake.hasdotnetproject(sln) if hasdotnet then table.insert(platforms, 1, "any") end if hasdotnet and hascpp then table.insert(platforms, 2, "mixed") end for _, buildcfg in ipairs(sln.configurations) do for _, platform in ipairs(platforms) do local entry = { } entry.src_buildcfg = buildcfg entry.src_platform = platform if platform ~= "PS3" then entry.buildcfg = buildcfg entry.platform = premake.vstudio_platforms[platform] else entry.buildcfg = platform .. " " .. buildcfg entry.platform = "Win32" end entry.name = entry.buildcfg .. "|" .. entry.platform entry.isreal = (platform ~= "any" and platform ~= "mixed") table.insert(cfgs, entry) end end return cfgs end function _VS.cfgtype(cfg) if (cfg.kind == "SharedLib") then return 2 elseif (cfg.kind == "StaticLib") then return 4 else return 1 end end function premake.vstudio.cleansolution(sln) premake.clean.file(sln, "%%.sln") premake.clean.file(sln, "%%.suo") premake.clean.file(sln, "%%.ncb") premake.clean.file(sln, "%%.userprefs") premake.clean.file(sln, "%%.usertasks") end function premake.vstudio.cleanproject(prj) local fname = premake.project.getfilename(prj, "%%") os.remove(fname .. ".vcproj") os.remove(fname .. ".vcproj.user") os.remove(fname .. ".vcxproj") os.remove(fname .. ".vcxproj.user") os.remove(fname .. ".vcxproj.filters") os.remove(fname .. ".csproj") os.remove(fname .. ".csproj.user") os.remove(fname .. ".pidb") os.remove(fname .. ".sdf") end function premake.vstudio.cleantarget(name) os.remove(name .. ".pdb") os.remove(name .. ".idb") os.remove(name .. ".ilk") os.remove(name .. ".vshost.exe") os.remove(name .. ".exe.manifest") end local function output(indent, value) _p(indent .. value) end local function attrib(indent, name, value) _p(indent .. "\t" .. name .. '="' .. value .. '"') end function _VS.files(prj, fname, state, nestlevel) local indent = string.rep("\t", nestlevel + 2) if (state == "GroupStart") then output(indent, "") elseif (state == "GroupEnd") then output(indent, "") else output(indent, "") if (not prj.flags.NoPCH and prj.pchsource == fname) then for _, cfginfo in ipairs(prj.solution.vstudio_configs) do if cfginfo.isreal then local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) output(indent, "\t") output(indent, "\t\t") output(indent, "\t") end end end output(indent, "") end end function _VS.optimization(cfg) local result = 0 for _, value in ipairs(cfg.flags) do if (value == "Optimize") then result = 3 elseif (value == "OptimizeSize") then result = 1 elseif (value == "OptimizeSpeed") then result = 2 end end return result end function _VS.projectfile(prj) local extension if (prj.language == "C#") then extension = ".csproj" elseif (_ACTION == "vs2010" and prj.language == "C++" )then extension = ".vcxproj" elseif (_ACTION == "vs2010" and prj.language == "C" )then extension = ".vcxproj" else extension = ".vcproj" end local fname = path.join(prj.location, prj.name) return fname..extension end function _VS.tool(prj) if (prj.language == "C#") then return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC" else return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" end end newaction { trigger = "vs2002", shortname = "Visual Studio 2002", description = "Generate Microsoft Visual Studio 2002 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", premake.vs2002_solution) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", premake.vs2002_csproj) premake.generate(prj, "%%.csproj.user", premake.vs2002_csproj_user) else premake.generate(prj, "%%.vcproj", premake.vs200x_vcproj) end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget } newaction { trigger = "vs2003", shortname = "Visual Studio 2003", description = "Generate Microsoft Visual Studio 2003 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", premake.vs2003_solution) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", premake.vs2002_csproj) premake.generate(prj, "%%.csproj.user", premake.vs2002_csproj_user) else premake.generate(prj, "%%.vcproj", premake.vs200x_vcproj) end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget } newaction { trigger = "vs2005", shortname = "Visual Studio 2005", description = "Generate Microsoft Visual Studio 2005 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", premake.vs2005_solution) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", premake.vs2005_csproj) premake.generate(prj, "%%.csproj.user", premake.vs2005_csproj_user) else premake.generate(prj, "%%.vcproj", premake.vs200x_vcproj) end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget } newaction { trigger = "vs2008", shortname = "Visual Studio 2008", description = "Generate Microsoft Visual Studio 2008 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", premake.vs2005_solution) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", premake.vs2005_csproj) premake.generate(prj, "%%.csproj.user", premake.vs2005_csproj_user) else premake.generate(prj, "%%.vcproj", premake.vs200x_vcproj) end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget } newaction { trigger = "vs2010", shortname = "Visual Studio 2010", description = "Generate Visual Studio 2010 project files (experimental)", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib" }, valid_languages = { "C++","C"}, valid_tools = { cc = { "msc" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", premake.vs_generic_solution) end, onproject = function(prj) premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", premake.vs2010_vcxproj_filters) end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget }function premake.vs2002_solution(sln) io.eol = '\r\n' sln.vstudio_configs = premake.vstudio_buildconfigs(sln) _p('Microsoft Visual Studio Solution File, Format Version 7.00') for prj in premake.solution.eachproject(sln) do local projpath = path.translate(path.getrelative(sln.location, _VS.projectfile(prj))) _p('Project("{%s}") = "%s", "%s", "{%s}"', _VS.tool(prj), prj.name, projpath, prj.uuid) _p('EndProject') end _p('Global') _p(1,'GlobalSection(SolutionConfiguration) = preSolution') for i, cfgname in ipairs(sln.configurations) do _p(2,'ConfigName.%d = %s', i - 1, cfgname) end _p(1,'EndGlobalSection') _p(1,'GlobalSection(ProjectDependencies) = postSolution') _p(1,'EndGlobalSection') _p(1,'GlobalSection(ProjectConfiguration) = postSolution') for prj in premake.solution.eachproject(sln) do for _, cfgname in ipairs(sln.configurations) do _p(2,'{%s}.%s.ActiveCfg = %s|%s', prj.uuid, cfgname, cfgname, _VS.arch(prj)) _p(2,'{%s}.%s.Build.0 = %s|%s', prj.uuid, cfgname, cfgname, _VS.arch(prj)) end end _p(1,'EndGlobalSection') _p(1,'GlobalSection(ExtensibilityGlobals) = postSolution') _p(1,'EndGlobalSection') _p(1,'GlobalSection(ExtensibilityAddIns) = postSolution') _p(1,'EndGlobalSection') _p('EndGlobal') end local function getelements(prj, action, fname) if action == "Compile" and fname:endswith(".cs") then return "SubTypeCode" end if action == "EmbeddedResource" and fname:endswith(".resx") then local basename = fname:sub(1, -6) local testname = path.getname(basename .. ".cs") if premake.findfile(prj, testname) then return "Dependency", testname end end return "None" end function premake.vs2002_csproj(prj) io.eol = "\r\n" _p('') _p(1,'') _p(2,'') _p(3,'') for cfg in premake.eachconfig(prj) do _p(4,'') end _p(3,'') _p(3,'') for _, ref in ipairs(premake.getlinks(prj, "siblings", "object")) do _p(4,'') end for _, linkname in ipairs(premake.getlinks(prj, "system", "fullpath")) do _p(4,'') end _p(3,'') _p(2,'') _p(2,'') _p(3,'') for fcfg in premake.eachfile(prj) do local action = premake.dotnet.getbuildaction(fcfg) local fname = path.translate(premake.esc(fcfg.name), "\\") local elements, dependency = getelements(prj, action, fcfg.name) _p(4,'') end _p(3,'') _p(2,'') _p(1,'') _p('') end function premake.vs2002_csproj_user(prj) io.eol = "\r\n" _p('') _p(1,'') _p(2,'') local refpaths = table.translate(prj.libdirs, function(v) return path.getabsolute(prj.location .. "/" .. v) end) _p(3,'', path.translate(table.concat(refpaths, ";"), "\\")) for cfg in premake.eachconfig(prj) do _p(4,'') end _p(3,'') _p(2,'') _p(2,'') _p(1,'') _p('') end premake.vstudio.vcproj = { } local vcproj = premake.vstudio.vcproj function vcproj.Configuration(name, cfg) _p(2,'') end function premake.vs200x_vcproj_platforms(prj) local used = { } _p(1,'') for _, cfg in ipairs(prj.solution.vstudio_configs) do if cfg.isreal and not table.contains(used, cfg.platform) then table.insert(used, cfg.platform) _p(2,'') end end _p(1,'') end function premake.vs200x_vcproj_symbols(cfg) if (not cfg.flags.Symbols) then return 0 else if cfg.flags.NoEditAndContinue or _VS.optimization(cfg) ~= 0 or cfg.flags.Managed or cfg.platform == "x64" then return 3 else return 4 end end end function premake.vs200x_vcproj_VCCLCompilerTool(cfg) _p(3,' 0 then _p(4,'AdditionalOptions="%s"', table.concat(premake.esc(cfg.buildoptions), " ")) end _p(4,'Optimization="%s"', _VS.optimization(cfg)) if cfg.flags.NoFramePointer then _p(4,'OmitFramePointers="%s"', _VS.bool(true)) end if #cfg.includedirs > 0 then _p(4,'AdditionalIncludeDirectories="%s"', premake.esc(path.translate(table.concat(cfg.includedirs, ";"), '\\'))) end if #cfg.defines > 0 then _p(4,'PreprocessorDefinitions="%s"', premake.esc(table.concat(cfg.defines, ";"))) end if premake.config.isdebugbuild(cfg) and not cfg.flags.NoMinimalRebuild and not cfg.flags.Managed then _p(4,'MinimalRebuild="%s"', _VS.bool(true)) end if cfg.flags.NoExceptions then _p(4,'ExceptionHandling="%s"', iif(_ACTION < "vs2005", "FALSE", 0)) elseif cfg.flags.SEH and _ACTION > "vs2003" then _p(4,'ExceptionHandling="2"') end if _VS.optimization(cfg) == 0 and not cfg.flags.Managed then _p(4,'BasicRuntimeChecks="3"') end if _VS.optimization(cfg) ~= 0 then _p(4,'StringPooling="%s"', _VS.bool(true)) end local runtime if premake.config.isdebugbuild(cfg) then runtime = iif(cfg.flags.StaticRuntime, 1, 3) else runtime = iif(cfg.flags.StaticRuntime, 0, 2) end _p(4,'RuntimeLibrary="%s"', runtime) _p(4,'EnableFunctionLevelLinking="%s"', _VS.bool(true)) if _ACTION > "vs2003" and cfg.platform ~= "Xbox360" and cfg.platform ~= "x64" then if cfg.flags.EnableSSE then _p(4,'EnableEnhancedInstructionSet="1"') elseif cfg.flags.EnableSSE2 then _p(4,'EnableEnhancedInstructionSet="2"') end end if _ACTION < "vs2005" then if cfg.flags.FloatFast then _p(4,'ImproveFloatingPointConsistency="%s"', _VS.bool(false)) elseif cfg.flags.FloatStrict then _p(4,'ImproveFloatingPointConsistency="%s"', _VS.bool(true)) end else if cfg.flags.FloatFast then _p(4,'FloatingPointModel="2"') elseif cfg.flags.FloatStrict then _p(4,'FloatingPointModel="1"') end end if _ACTION < "vs2005" and not cfg.flags.NoRTTI then _p(4,'RuntimeTypeInfo="%s"', _VS.bool(true)) elseif _ACTION > "vs2003" and cfg.flags.NoRTTI then _p(4,'RuntimeTypeInfo="%s"', _VS.bool(false)) end if cfg.flags.NativeWChar then _p(4,'TreatWChar_tAsBuiltInType="%s"', _VS.bool(true)) elseif cfg.flags.NoNativeWChar then _p(4,'TreatWChar_tAsBuiltInType="%s"', _VS.bool(false)) end if not cfg.flags.NoPCH and cfg.pchheader then _p(4,'UsePrecompiledHeader="%s"', iif(_ACTION < "vs2005", 3, 2)) _p(4,'PrecompiledHeaderThrough="%s"', path.getname(cfg.pchheader)) else _p(4,'UsePrecompiledHeader="%s"', iif(_ACTION > "vs2003" or cfg.flags.NoPCH, 0, 2)) end _p(4,'WarningLevel="%s"', iif(cfg.flags.ExtraWarnings, 4, 3)) if cfg.flags.FatalWarnings then _p(4,'WarnAsError="%s"', _VS.bool(true)) end if _ACTION < "vs2008" and not cfg.flags.Managed then _p(4,'Detect64BitPortabilityProblems="%s"', _VS.bool(not cfg.flags.No64BitChecks)) end _p(4,'ProgramDataBaseFileName="$(OutDir)\\%s.pdb"', path.getbasename(cfg.buildtarget.name)) _p(4,'DebugInformationFormat="%s"', premake.vs200x_vcproj_symbols(cfg)) if cfg.language == "C" then _p(4, 'CompileAs="1"') end _p(3,'/>') end function premake.vs200x_vcproj_VCLinkerTool(cfg) _p(3,' 0 then _p(4,'AdditionalOptions="%s"', table.concat(premake.esc(cfg.linkoptions), " ")) end if #cfg.links > 0 then _p(4,'AdditionalDependencies="%s"', table.concat(premake.getlinks(cfg, "all", "fullpath"), " ")) end _p(4,'OutputFile="$(OutDir)\\%s"', cfg.buildtarget.name) _p(4,'LinkIncremental="%s"', iif(_VS.optimization(cfg) == 0, 2, 1)) _p(4,'AdditionalLibraryDirectories="%s"', table.concat(premake.esc(path.translate(cfg.libdirs, '\\')) , ";")) local deffile = premake.findfile(cfg, ".def") if deffile then _p(4,'ModuleDefinitionFile="%s"', deffile) end if cfg.flags.NoManifest then _p(4,'GenerateManifest="%s"', _VS.bool(false)) end _p(4,'GenerateDebugInformation="%s"', _VS.bool(premake.vs200x_vcproj_symbols(cfg) ~= 0)) if premake.vs200x_vcproj_symbols(cfg) ~= 0 then _p(4,'ProgramDataBaseFileName="$(OutDir)\\%s.pdb"', path.getbasename(cfg.buildtarget.name)) end _p(4,'SubSystem="%s"', iif(cfg.kind == "ConsoleApp", 1, 2)) if _VS.optimization(cfg) ~= 0 then _p(4,'OptimizeReferences="2"') _p(4,'EnableCOMDATFolding="2"') end if (cfg.kind == "ConsoleApp" or cfg.kind == "WindowedApp") and not cfg.flags.WinMain then _p(4,'EntryPointSymbol="mainCRTStartup"') end if cfg.kind == "SharedLib" then local implibname = cfg.linktarget.fullpath _p(4,'ImportLibrary="%s"', iif(cfg.flags.NoImportLib, cfg.objectsdir .. "\\" .. path.getname(implibname), implibname)) end _p(4,'TargetMachine="%d"', iif(cfg.platform == "x64", 17, 1)) else _p(4,'Name="VCLibrarianTool"') if #cfg.links > 0 then _p(4,'AdditionalDependencies="%s"', table.concat(premake.getlinks(cfg, "all", "fullpath"), " ")) end _p(4,'OutputFile="$(OutDir)\\%s"', cfg.buildtarget.name) if #cfg.libdirs > 0 then _p(4,'AdditionalLibraryDirectories="%s"', premake.esc(path.translate(table.concat(cfg.libdirs , ";")))) end if #cfg.linkoptions > 0 then _p(4,'AdditionalOptions="%s"', table.concat(premake.esc(cfg.linkoptions), " ")) end end _p(3,'/>') end function premake.vs200x_vcproj_VCCLCompilerTool_GCC(cfg) _p(3,' 0 then _p(4,'AdditionalOptions="%s"', premake.esc(table.concat(buildoptions, " "))) end if #cfg.includedirs > 0 then _p(4,'AdditionalIncludeDirectories="%s"', premake.esc(path.translate(table.concat(cfg.includedirs, ";"), '\\'))) end if #cfg.defines > 0 then _p(4,'PreprocessorDefinitions="%s"', table.concat(premake.esc(cfg.defines), ";")) end _p(4,'ProgramDataBaseFileName="$(OutDir)\\%s.pdb"', path.getbasename(cfg.buildtarget.name)) _p(4,'DebugInformationFormat="0"') _p(4,'CompileAs="0"') _p(3,'/>') end function premake.vs200x_vcproj_VCLinkerTool_GCC(cfg) _p(3,' 0 then _p(4,'AdditionalOptions="%s"', premake.esc(table.concat(buildoptions, " "))) end if #cfg.links > 0 then _p(4,'AdditionalDependencies="%s"', table.concat(premake.getlinks(cfg, "all", "fullpath"), " ")) end _p(4,'OutputFile="$(OutDir)\\%s"', cfg.buildtarget.name) _p(4,'LinkIncremental="0"') _p(4,'AdditionalLibraryDirectories="%s"', table.concat(premake.esc(path.translate(cfg.libdirs, '\\')) , ";")) _p(4,'GenerateManifest="%s"', _VS.bool(false)) _p(4,'ProgramDatabaseFile=""') _p(4,'RandomizedBaseAddress="1"') _p(4,'DataExecutionPrevention="0"') else _p(4,'Name="VCLibrarianTool"') local buildoptions = table.join(premake.gcc.getldflags(cfg), cfg.linkoptions) if #buildoptions > 0 then _p(4,'AdditionalOptions="%s"', premake.esc(table.concat(buildoptions, " "))) end if #cfg.links > 0 then _p(4,'AdditionalDependencies="%s"', table.concat(premake.getlinks(cfg, "all", "fullpath"), " ")) end _p(4,'OutputFile="$(OutDir)\\%s"', cfg.buildtarget.name) if #cfg.libdirs > 0 then _p(4,'AdditionalLibraryDirectories="%s"', premake.esc(path.translate(table.concat(cfg.libdirs , ";")))) end end _p(3,'/>') end function premake.vs200x_vcproj_VCResourceCompilerTool(cfg) _p(3,' 0 then _p(4,'AdditionalOptions="%s"', table.concat(premake.esc(cfg.resoptions), " ")) end if #cfg.defines > 0 or #cfg.resdefines > 0 then _p(4,'PreprocessorDefinitions="%s"', table.concat(premake.esc(table.join(cfg.defines, cfg.resdefines)), ";")) end if #cfg.includedirs > 0 or #cfg.resincludedirs > 0 then local dirs = table.join(cfg.includedirs, cfg.resincludedirs) _p(4,'AdditionalIncludeDirectories="%s"', premake.esc(path.translate(table.concat(dirs, ";"), '\\'))) end _p(3,'/>') end function premake.vs200x_vcproj_VCManifestTool(cfg) local manifests = { } for _, fname in ipairs(cfg.files) do if path.getextension(fname) == ".manifest" then table.insert(manifests, fname) end end _p(3,' 0 then _p(4,'AdditionalManifestFiles="%s"', premake.esc(table.concat(manifests, ";"))) end _p(3,'/>') end function premake.vs200x_vcproj_VCMIDLTool(cfg) _p(3,'') end function premake.vs200x_vcproj_buildstepsblock(name, steps) _p(3,' 0 then _p(4,'CommandLine="%s"', premake.esc(table.implode(steps, "", "", "\r\n"))) end _p(3,'/>') end local blockmap = { VCCLCompilerTool = premake.vs200x_vcproj_VCCLCompilerTool, VCCLCompilerTool_GCC = premake.vs200x_vcproj_VCCLCompilerTool_GCC, VCLinkerTool = premake.vs200x_vcproj_VCLinkerTool, VCLinkerTool_GCC = premake.vs200x_vcproj_VCLinkerTool_GCC, VCManifestTool = premake.vs200x_vcproj_VCManifestTool, VCMIDLTool = premake.vs200x_vcproj_VCMIDLTool, VCResourceCompilerTool = premake.vs200x_vcproj_VCResourceCompilerTool, } local function getsections(version, platform) if version == "vs2002" then return { "VCCLCompilerTool", "VCCustomBuildTool", "VCLinkerTool", "VCMIDLTool", "VCPostBuildEventTool", "VCPreBuildEventTool", "VCPreLinkEventTool", "VCResourceCompilerTool", "VCWebServiceProxyGeneratorTool", "VCWebDeploymentTool" } end if version == "vs2003" then return { "VCCLCompilerTool", "VCCustomBuildTool", "VCLinkerTool", "VCMIDLTool", "VCPostBuildEventTool", "VCPreBuildEventTool", "VCPreLinkEventTool", "VCResourceCompilerTool", "VCWebServiceProxyGeneratorTool", "VCXMLDataGeneratorTool", "VCWebDeploymentTool", "VCManagedWrapperGeneratorTool", "VCAuxiliaryManagedWrapperGeneratorTool" } end if platform == "Xbox360" then return { "VCPreBuildEventTool", "VCCustomBuildTool", "VCXMLDataGeneratorTool", "VCWebServiceProxyGeneratorTool", "VCMIDLTool", "VCCLCompilerTool", "VCManagedResourceCompilerTool", "VCResourceCompilerTool", "VCPreLinkEventTool", "VCLinkerTool", "VCALinkTool", "VCX360ImageTool", "VCBscMakeTool", "VCX360DeploymentTool", "VCPostBuildEventTool", "DebuggerTool", } end if platform == "PS3" then return { "VCPreBuildEventTool", "VCCustomBuildTool", "VCXMLDataGeneratorTool", "VCWebServiceProxyGeneratorTool", "VCMIDLTool", "VCCLCompilerTool_GCC", "VCManagedResourceCompilerTool", "VCResourceCompilerTool", "VCPreLinkEventTool", "VCLinkerTool_GCC", "VCALinkTool", "VCManifestTool", "VCXDCMakeTool", "VCBscMakeTool", "VCFxCopTool", "VCAppVerifierTool", "VCWebDeploymentTool", "VCPostBuildEventTool" } else return { "VCPreBuildEventTool", "VCCustomBuildTool", "VCXMLDataGeneratorTool", "VCWebServiceProxyGeneratorTool", "VCMIDLTool", "VCCLCompilerTool", "VCManagedResourceCompilerTool", "VCResourceCompilerTool", "VCPreLinkEventTool", "VCLinkerTool", "VCALinkTool", "VCManifestTool", "VCXDCMakeTool", "VCBscMakeTool", "VCFxCopTool", "VCAppVerifierTool", "VCWebDeploymentTool", "VCPostBuildEventTool" } end end function premake.vs200x_vcproj(prj) io.eol = "\r\n" _p('') _p(' "vs2003" then _p(1,'RootNamespace="%s"', prj.name) end _p(1,'Keyword="%s"', iif(prj.flags.Managed, "ManagedCProj", "Win32Proj")) _p(1,'>') premake.vs200x_vcproj_platforms(prj) if _ACTION > "vs2003" then _p(1,'') _p(1,'') end _p(1,'') for _, cfginfo in ipairs(prj.solution.vstudio_configs) do if cfginfo.isreal then local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) vcproj.Configuration(cfginfo.name, cfg) for _, block in ipairs(getsections(_ACTION, cfginfo.src_platform)) do if blockmap[block] then blockmap[block](cfg) elseif block == "VCPreBuildEventTool" then premake.vs200x_vcproj_buildstepsblock("VCPreBuildEventTool", cfg.prebuildcommands) elseif block == "VCPreLinkEventTool" then premake.vs200x_vcproj_buildstepsblock("VCPreLinkEventTool", cfg.prelinkcommands) elseif block == "VCPostBuildEventTool" then premake.vs200x_vcproj_buildstepsblock("VCPostBuildEventTool", cfg.postbuildcommands) elseif block == "VCX360DeploymentTool" then _p(3,' 0 then _p(4,'AdditionalOptions="%s"', table.concat(premake.esc(cfg.deploymentoptions), " ")) end _p(3,'/>') elseif block == "VCX360ImageTool" then _p(3,' 0 then _p(4,'AdditionalOptions="%s"', table.concat(premake.esc(cfg.imageoptions), " ")) end if cfg.imagepath ~= nil then _p(4,'OutputFileName="%s"', premake.esc(path.translate(cfg.imagepath))) end _p(3,'/>') elseif block == "DebuggerTool" then _p(3,'') else _p(3,'') end end _p(2,'') end end _p(1,'') _p(1,'') _p(1,'') _p(1,'') premake.walksources(prj, _VS.files) _p(1,'') _p(1,'') _p(1,'') _p('') end function premake.vs2003_solution(sln) io.eol = '\r\n' sln.vstudio_configs = premake.vstudio_buildconfigs(sln) _p('Microsoft Visual Studio Solution File, Format Version 8.00') for prj in premake.solution.eachproject(sln) do local projpath = path.translate(path.getrelative(sln.location, _VS.projectfile(prj))) _p('Project("{%s}") = "%s", "%s", "{%s}"', _VS.tool(prj), prj.name, projpath, prj.uuid) local deps = premake.getdependencies(prj) if #deps > 0 then _p('\tProjectSection(ProjectDependencies) = postProject') for _, dep in ipairs(deps) do _p('\t\t{%s} = {%s}', dep.uuid, dep.uuid) end _p('\tEndProjectSection') end _p('EndProject') end _p('Global') _p('\tGlobalSection(SolutionConfiguration) = preSolution') for _, cfgname in ipairs(sln.configurations) do _p('\t\t%s = %s', cfgname, cfgname) end _p('\tEndGlobalSection') _p('\tGlobalSection(ProjectDependencies) = postSolution') _p('\tEndGlobalSection') _p('\tGlobalSection(ProjectConfiguration) = postSolution') for prj in premake.solution.eachproject(sln) do for _, cfgname in ipairs(sln.configurations) do _p('\t\t{%s}.%s.ActiveCfg = %s|%s', prj.uuid, cfgname, cfgname, _VS.arch(prj)) _p('\t\t{%s}.%s.Build.0 = %s|%s', prj.uuid, cfgname, cfgname, _VS.arch(prj)) end end _p('\tEndGlobalSection') _p('\tGlobalSection(ExtensibilityGlobals) = postSolution') _p('\tEndGlobalSection') _p('\tGlobalSection(ExtensibilityAddIns) = postSolution') _p('\tEndGlobalSection') _p('EndGlobal') end function premake.vs2005_solution(sln) io.eol = '\r\n' sln.vstudio_configs = premake.vstudio_buildconfigs(sln) _p('\239\187\191') _p('Microsoft Visual Studio Solution File, Format Version %s', iif(_ACTION == 'vs2005', '9.00', '10.00')) _p('# Visual Studio %s', iif(_ACTION == 'vs2005', '2005', '2008')) for prj in premake.solution.eachproject(sln) do local projpath = path.translate(path.getrelative(sln.location, _VS.projectfile(prj)), "\\") _p('Project("{%s}") = "%s", "%s", "{%s}"', _VS.tool(prj), prj.name, projpath, prj.uuid) local deps = premake.getdependencies(prj) if #deps > 0 then _p('\tProjectSection(ProjectDependencies) = postProject') for _, dep in ipairs(deps) do _p('\t\t{%s} = {%s}', dep.uuid, dep.uuid) end _p('\tEndProjectSection') end _p('EndProject') end _p('Global') premake.vs2005_solution_platforms(sln) premake.vs2005_solution_project_platforms(sln) premake.vs2005_solution_properties(sln) _p('EndGlobal') end function premake.vs2005_solution_platforms(sln) _p('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution') for _, cfg in ipairs(sln.vstudio_configs) do _p('\t\t%s = %s', cfg.name, cfg.name) end _p('\tEndGlobalSection') end function premake.vs2005_solution_project_platforms(sln) _p('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution') for prj in premake.solution.eachproject(sln) do for _, cfg in ipairs(sln.vstudio_configs) do local mapped if premake.isdotnetproject(prj) then mapped = "Any CPU" else if cfg.platform == "Any CPU" or cfg.platform == "Mixed Platforms" then mapped = sln.vstudio_configs[3].platform else mapped = cfg.platform end end _p('\t\t{%s}.%s.ActiveCfg = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped) if mapped == cfg.platform or cfg.platform == "Mixed Platforms" then _p('\t\t{%s}.%s.Build.0 = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped) end end end _p('\tEndGlobalSection') end function premake.vs2005_solution_properties(sln) _p('\tGlobalSection(SolutionProperties) = preSolution') _p('\t\tHideSolutionNode = FALSE') _p('\tEndGlobalSection') end premake.vstudio.cs2005 = { } local vstudio = premake.vstudio local cs2005 = premake.vstudio.cs2005 local function getelements(prj, action, fname) if action == "Compile" and fname:endswith(".cs") then if fname:endswith(".Designer.cs") then local basename = fname:sub(1, -13) local testname = basename .. ".cs" if premake.findfile(prj, testname) then return "Dependency", testname end testname = basename .. ".resx" if premake.findfile(prj, testname) then return "AutoGen", testname end else local basename = fname:sub(1, -4) local testname = basename .. ".Designer.cs" if premake.findfile(prj, testname) then return "SubTypeForm" end end end if action == "EmbeddedResource" and fname:endswith(".resx") then local basename = fname:sub(1, -6) local testname = path.getname(basename .. ".cs") if premake.findfile(prj, testname) then if premake.findfile(prj, basename .. ".Designer.cs") then return "DesignerType", testname else return "Dependency", testname end else testname = path.getname(basename .. ".Designer.cs") if premake.findfile(prj, testname) then return "AutoGenerated" end end end if action == "Content" then return "CopyNewest" end return "None" end function cs2005.projectelement(prj) _p('', iif(_ACTION == 'vs2005', '', ' ToolsVersion="3.5"')) end function cs2005.projectsettings(prj) _p(' ') _p(' %s', premake.esc(prj.solution.configurations[1])) _p(' AnyCPU') _p(' %s', iif(_ACTION == "vs2005", "8.0.50727", "9.0.21022")) _p(' 2.0') _p(' {%s}', prj.uuid) _p(' %s', premake.dotnet.getkind(prj)) _p(' Properties') _p(' %s', prj.buildtarget.basename) _p(' %s', prj.buildtarget.basename) if prj.framework then _p(' v%s', prj.framework) end _p(' ') end function premake.vs2005_csproj(prj) io.eol = "\r\n" local vsversion, toolversion if _ACTION == "vs2005" then vsversion = "8.0.50727" toolversion = nil elseif _ACTION == "vs2008" then vsversion = "9.0.21022" toolversion = "3.5" end if toolversion then _p('', toolversion) else _p('') end _p(' ') _p(' %s', premake.esc(prj.solution.configurations[1])) _p(' AnyCPU') _p(' %s', vsversion) _p(' 2.0') _p(' {%s}', prj.uuid) _p(' %s', premake.dotnet.getkind(prj)) _p(' Properties') _p(' %s', prj.buildtarget.basename) _p(' %s', prj.buildtarget.basename) _p(' ') for cfg in premake.eachconfig(prj) do _p(' ', premake.esc(cfg.name)) if cfg.flags.Symbols then _p(' true') _p(' full') else _p(' pdbonly') end _p(' %s', iif(cfg.flags.Optimize or cfg.flags.OptimizeSize or cfg.flags.OptimizeSpeed, "true", "false")) _p(' %s', cfg.buildtarget.directory) _p(' %s', table.concat(premake.esc(cfg.defines), ";")) _p(' prompt') _p(' 4') if cfg.flags.Unsafe then _p(' true') end if cfg.flags.FatalWarnings then _p(' true') end _p(' ') end _p(' ') for _, ref in ipairs(premake.getlinks(prj, "siblings", "object")) do _p(' ', path.translate(path.getrelative(prj.location, _VS.projectfile(ref)), "\\")) _p(' {%s}', ref.uuid) _p(' %s', premake.esc(ref.name)) _p(' ') end for _, linkname in ipairs(premake.getlinks(prj, "system", "basename")) do _p(' ', premake.esc(linkname)) end _p(' ') _p(' ') for fcfg in premake.eachfile(prj) do local action = premake.dotnet.getbuildaction(fcfg) local fname = path.translate(premake.esc(fcfg.name), "\\") local elements, dependency = getelements(prj, action, fcfg.name) if elements == "None" then _p(' <%s Include="%s" />', action, fname) else _p(' <%s Include="%s">', action, fname) if elements == "AutoGen" then _p(' True') elseif elements == "AutoGenerated" then _p(' Designer') _p(' ResXFileCodeGenerator') _p(' %s.Designer.cs', premake.esc(path.getbasename(fcfg.name))) elseif elements == "SubTypeDesigner" then _p(' Designer') elseif elements == "SubTypeForm" then _p(' Form') elseif elements == "PreserveNewest" then _p(' PreserveNewest') end if dependency then _p(' %s', path.translate(premake.esc(dependency), "\\")) end _p(' ', action) end end _p(' ') _p(' ') _p(' ') _p('') end function premake.vs2005_csproj_user(prj) io.eol = "\r\n" _p('') _p(' ') local refpaths = table.translate(prj.libdirs, function(v) return path.getabsolute(prj.location .. "/" .. v) end) _p(' %s', path.translate(table.concat(refpaths, ";"), "\\")) _p(' ') _p('') end local vs_format_version = function() local t = { vs2005 = '9.00', vs2008 = '10.00', vs2010 = '11.00' } return t[_ACTION] end local vs_version = function() local t = { vs2005 = '2005', vs2008 = '2008', vs2010 = '2010' } return t[_ACTION] end local vs_write_version_info = function() _p('Microsoft Visual Studio Solution File, Format Version %s', vs_format_version()) _p('# Visual Studio %s', vs_version() ) end local vs_write_projects = function(sln) for prj in premake.solution.eachproject(sln) do local projpath = path.translate(path.getrelative(sln.location, _VS.projectfile(prj)), "\\") _p('Project("{%s}") = "%s", "%s", "{%s}"', _VS.tool(prj), prj.name, projpath, prj.uuid) local deps = premake.getdependencies(prj) if #deps > 0 then _p('\tProjectSection(ProjectDependencies) = postProject') for _, dep in ipairs(deps) do _p('\t\t{%s} = {%s}', dep.uuid, dep.uuid) end _p('\tEndProjectSection') end _p('EndProject') end end local vs_write_pre_version = function(sln) io.eol = '\r\n' sln.vstudio_configs = premake.vstudio_buildconfigs(sln) _p('\239\187\191') end function premake.vs_generic_solution(sln) vs_write_pre_version(sln) vs_write_version_info() vs_write_projects(sln) _p('Global') premake.vs2005_solution_platforms(sln) premake.vs2005_solution_project_platforms(sln) premake.vs2005_solution_properties(sln) _p('EndGlobal') end premake.vstudio.vs10_helpers = { } local vs10_helpers = premake.vstudio.vs10_helpers function vs10_helpers.remove_relative_path(file) file = file:gsub("%.%.\\",'') file = file:gsub("%.\\",'') return file end function vs10_helpers.file_path(file) file = vs10_helpers.remove_relative_path(file) local path = string.find(file,'\\[%w%.%_%-]+$') if path then return string.sub(file,1,path-1) else return nil end end function vs10_helpers.list_of_directories_in_path(path) local list={} path = vs10_helpers.remove_relative_path(path) if path then for dir in string.gmatch(path,"[%w%-%_%.]+\\")do if #list == 0 then list[1] = dir:sub(1,#dir-1) else list[#list +1] = list[#list] .."\\" ..dir:sub(1,#dir-1) end end end return list end function vs10_helpers.table_of_file_filters(files) local filters ={} for _, valueTable in pairs(files) do for _, entry in ipairs(valueTable) do local result = vs10_helpers.list_of_directories_in_path(entry) for __,dir in ipairs(result) do if table.contains(filters,dir) ~= true then filters[#filters +1] = dir end end end end return filters end function vs10_helpers.get_file_extension(file) local ext_start,ext_end = string.find(file,"%.[%w_%-]+$") if ext_start then return string.sub(file,ext_start+1,ext_end) end end function vs10_helpers.sort_input_files(files,sorted_container) local types = { h= "ClInclude", hpp= "ClInclude", hxx= "ClInclude", c= "ClCompile", cpp= "ClCompile", cxx= "ClCompile", cc= "ClCompile", rc = "ResourceCompile" } for _, current_file in ipairs(files) do local translated_path = path.translate(current_file, '\\') local ext = vs10_helpers.get_file_extension(translated_path) if ext then local type = types[ext] if type then table.insert(sorted_container[type],translated_path) else table.insert(sorted_container.None,translated_path) end end end end local function vs2010_config(prj) _p(1,'') for _, cfginfo in ipairs(prj.solution.vstudio_configs) do _p(2,'', premake.esc(cfginfo.name)) _p(3,'%s',cfginfo.buildcfg) _p(3,'%s',cfginfo.platform) _p(2,'') end _p(1,'') end local function vs2010_globals(prj) _p(1,'') _p(2,'{%s}',prj.uuid) _p(2,'%s',prj.name) _p(2,'Win32Proj') _p(1,'') end function vs10_helpers.config_type(config) local t = { SharedLib = "DynamicLibrary", StaticLib = "StaticLibrary", ConsoleApp = "Application", WindowedApp = "Application" } return t[config.kind] end local function if_config_and_platform() return 'Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"' end local function optimisation(cfg) local result = "Disabled" for _, value in ipairs(cfg.flags) do if (value == "Optimize") then result = "Full" elseif (value == "OptimizeSize") then result = "MinSpace" elseif (value == "OptimizeSpeed") then result = "MaxSpeed" end end return result end local function config_type_block(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(1,'' , premake.esc(cfginfo.name)) _p(2,'%s',vs10_helpers.config_type(cfg)) _p(2,'%s',iif(cfg.flags.Unicode,"Unicode","MultiByte")) if cfg.flags.MFC then _p(2,'Dynamic') end local use_debug = "false" if optimisation(cfg) == "Disabled" then use_debug = "true" else _p(2,'true') end _p(2,'%s',use_debug) _p(1,'') end end local function import_props(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(1,'' ,premake.esc(cfginfo.name)) _p(2,'') _p(1,'') end end local function incremental_link(cfg,cfginfo) if cfg.kind ~= "StaticLib" then ShoudLinkIncrementally = 'false' if optimisation(cfg) == "Disabled" then ShoudLinkIncrementally = 'true' end _p(2,'%s' ,premake.esc(cfginfo.name),ShoudLinkIncrementally) end end local function ignore_import_lib(cfg,cfginfo) if cfg.kind == "SharedLib" then local shouldIgnore = "false" if cfg.flags.NoImportLib then shouldIgnore = "true" end _p(2,'%s' ,premake.esc(cfginfo.name),shouldIgnore) end end local function intermediate_and_out_dirs(prj) _p(1,'') _p(2,'<_ProjectFileVersion>10.0.30319.1') for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(2,'%s\\' , premake.esc(cfginfo.name),premake.esc(cfg.buildtarget.directory) ) _p(2,'%s\\' , premake.esc(cfginfo.name), premake.esc(cfg.objectsdir)) _p(2,'%s' ,premake.esc(cfginfo.name),path.getbasename(cfg.buildtarget.name)) ignore_import_lib(cfg,cfginfo) incremental_link(cfg,cfginfo) if cfg.flags.NoManifest then _p(2,'false' ,premake.esc(cfginfo.name)) end end _p(1,'') end local function runtime(cfg) local runtime if premake.config.isdebugbuild(cfg) then runtime = iif(cfg.flags.StaticRuntime,"MultiThreadedDebug", "MultiThreadedDebugDLL") else runtime = iif(cfg.flags.StaticRuntime, "MultiThreaded", "MultiThreadedDLL") end return runtime end local function precompiled_header(cfg) if not cfg.flags.NoPCH and cfg.pchheader then _p(3,'Use') _p(3,'%s', path.getname(cfg.pchheader)) else _p(3,'') end end local function preprocessor(indent,cfg) if #cfg.defines > 0 then _p(indent,'%s;%%(PreprocessorDefinitions)' ,premake.esc(table.concat(cfg.defines, ";"))) else _p(indent,'') end end local function include_dirs(indent,cfg) if #cfg.includedirs > 0 then _p(indent,'%s;%%(AdditionalIncludeDirectories)' ,premake.esc(path.translate(table.concat(cfg.includedirs, ";"), '\\'))) end end local function resource_compile(cfg) _p(2,'') preprocessor(3,cfg) include_dirs(3,cfg) _p(2,'') end local function exceptions(cfg) if cfg.flags.NoExceptions then _p(2,'false') elseif cfg.flags.SEH then _p(2,'Async') end end local function rtti(cfg) if cfg.flags.NoRTTI then _p(3,'false') end end local function wchar_t_buildin(cfg) if cfg.flags.NativeWChar then _p(3,'true') elseif cfg.flags.NoNativeWChar then _p(3,'false') end end local function sse(cfg) if cfg.flags.EnableSSE then _p(3,'StreamingSIMDExtensions') elseif cfg.flags.EnableSSE2 then _p(3,'StreamingSIMDExtensions2') end end local function floating_point(cfg) if cfg.flags.FloatFast then _p(3,'Fast') elseif cfg.flags.FloatStrict then _p(3,'Strict') end end local function debug_info(cfg) local debug_info = '' if cfg.flags.Symbols then if optimisation(cfg) ~= "Disabled" or cfg.flags.NoEditAndContinue then debug_info = "ProgramDatabase" elseif cfg.platform ~= "x64" then debug_info = "EditAndContinue" else debug_info = "OldStyle" end end _p(3,'%s',debug_info) end local function minimal_build(cfg) if premake.config.isdebugbuild(cfg) and not cfg.flags.NoMinimalRebuild then _p(3,'true') else _p(3,'false') end end local function compile_language(cfg) if cfg.language == "C" then _p(3,'CompileAsC') end end local function vs10_clcompile(cfg) _p(2,'') if #cfg.buildoptions > 0 then _p(3,'%s %%(AdditionalOptions)', table.concat(premake.esc(cfg.buildoptions), " ")) end _p(3,'%s',optimisation(cfg)) include_dirs(3,cfg) preprocessor(3,cfg) minimal_build(cfg) if optimisation(cfg) == "Disabled" then _p(3,'EnableFastChecks') if cfg.flags.ExtraWarnings then _p(3,'true') end else _p(3,'true') end _p(3,'%s', runtime(cfg)) _p(3,'true') precompiled_header(cfg) if cfg.flags.ExtraWarnings then _p(3,'Level4') else _p(3,'Level3') end if cfg.flags.FatalWarnings then _p(3,'true') end exceptions(cfg) rtti(cfg) wchar_t_buildin(cfg) sse(cfg) floating_point(cfg) debug_info(cfg) if cfg.flags.NoFramePointer then _p(3,'true') end compile_language(cfg) _p(2,'') end local function event_hooks(cfg) if #cfg.postbuildcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.postbuildcommands, "", "", "\r\n"))) _p(2,'') end if #cfg.prebuildcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.prebuildcommands, "", "", "\r\n"))) _p(2,'') end if #cfg.prelinkcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.prelinkcommands, "", "", "\r\n"))) _p(2,'') end end local function additional_options(indent,cfg) if #cfg.linkoptions > 0 then _p(indent,'%s %%(AdditionalOptions)', table.concat(premake.esc(cfg.linkoptions), " ")) end end local function item_def_lib(cfg) if cfg.kind == 'StaticLib' then _p(1,'') _p(2,'$(OutDir)%s',cfg.buildtarget.name) additional_options(2,cfg) _p(1,'') end end local function link_target_machine(cfg) local target if cfg.platform == nil or cfg.platform == "x32" then target ="MachineX86" elseif cfg.platform == "x64" then target ="MachineX64" end _p(3,'%s', target) end local function import_lib(cfg) if cfg.kind == "SharedLib" then local implibname = cfg.linktarget.fullpath _p(3,'%s',iif(cfg.flags.NoImportLib, cfg.objectsdir .. "\\" .. path.getname(implibname), implibname)) end end local function common_link_section(cfg) _p(3,'%s',iif(cfg.kind == "ConsoleApp","Console", "Windows")) if cfg.flags.Symbols then _p(3,'true') else _p(3,'false') end if optimisation(cfg) ~= "Disabled" then _p(3,'true') _p(3,'true') end if cfg.flags.Symbols then _p(3,'$(OutDir)%s.pdb' , path.getbasename(cfg.buildtarget.name)) end end local function item_link(cfg) _p(2,'') if cfg.kind ~= 'StaticLib' then if #cfg.links > 0 then _p(3,'%s;%%(AdditionalDependencies)', table.concat(premake.getlinks(cfg, "all", "fullpath"), ";")) end _p(3,'$(OutDir)%s', cfg.buildtarget.name) _p(3,'%s%s%%(AdditionalLibraryDirectories)', table.concat(premake.esc(path.translate(cfg.libdirs, '\\')) , ";"), iif(cfg.libdirs and #cfg.libdirs >0,';','')) common_link_section(cfg) if vs10_helpers.config_type(cfg) == 'Application' and not cfg.flags.WinMain then _p(3,'mainCRTStartup') end import_lib(cfg) _p(3,'%s', iif(cfg.platform == "x64", "MachineX64", "MachineX86")) additional_options(3,cfg) else common_link_section(cfg) end _p(2,'') end local function item_definitions(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(1,'' ,premake.esc(cfginfo.name)) vs10_clcompile(cfg) resource_compile(cfg) item_def_lib(cfg) item_link(cfg) event_hooks(cfg) _p(1,'') end end -- -- {8fd826f8-3739-44e6-8cc8-997122e53b8d} -- -- local function write_file_type_block(files,group_type) if #files > 0 then _p(1,'') for _, current_file in ipairs(files) do _p(2,'<%s Include=\"%s\" />', group_type,current_file) end _p(1,'') end end local function write_file_compile_block(files,prj,configs) if #files > 0 then local config_mappings = {} for _, cfginfo in ipairs(configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) if cfg.pchheader and cfg.pchsource and not cfg.flags.NoPCH then config_mappings[cfginfo] = path.translate(cfg.pchsource, "\\") end end _p(1,'') for _, current_file in ipairs(files) do _p(2,'', current_file) for _, cfginfo in ipairs(configs) do if config_mappings[cfginfo] and current_file == config_mappings[cfginfo] then _p(3,'Create' ,premake.esc(cfginfo.name)) config_mappings[cfginfo] = nil _p(2,'') end end _p(2,'') end _p(1,'') end end local function vcxproj_files(prj) local sorted = { ClCompile={}, ClInclude={}, None={}, ResourceCompile ={} } cfg = premake.getconfig(prj) vs10_helpers.sort_input_files(cfg.files,sorted) write_file_type_block(sorted.ClInclude,"ClInclude") write_file_compile_block(sorted.ClCompile,prj,prj.solution.vstudio_configs) write_file_type_block(sorted.None,'None') write_file_type_block(sorted.ResourceCompile,'ResourceCompile') end local function write_filter_includes(sorted_table) local directories = vs10_helpers.table_of_file_filters(sorted_table) if #directories >0 then _p(1,'') for _, dir in pairs(directories) do _p(2,'',dir) _p(3,'{%s}',os.uuid()) _p(2,'') end _p(1,'') end end local function write_file_filter_block(files,group_type) if #files > 0 then _p(1,'') for _, current_file in ipairs(files) do local path_to_file = vs10_helpers.file_path(current_file) if path_to_file then _p(2,'<%s Include=\"%s\">', group_type,path.translate(current_file, "\\")) _p(3,'%s',path_to_file) _p(2,'',group_type) else _p(2,'<%s Include=\"%s\" />', group_type,path.translate(current_file, "\\")) end end _p(1,'') end end local tool_version_and_xmlns = 'ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"' local xml_version_and_encoding = '' local function vcxproj_filter_files(prj) local sorted = { ClCompile={}, ClInclude={}, None={}, ResourceCompile ={} } cfg = premake.getconfig(prj) vs10_helpers.sort_input_files(cfg.files,sorted) io.eol = "\r\n" _p(xml_version_and_encoding) _p('') write_filter_includes(sorted) write_file_filter_block(sorted.ClInclude,"ClInclude") write_file_filter_block(sorted.ClCompile,"ClCompile") write_file_filter_block(sorted.None,"None") write_file_filter_block(sorted.ResourceCompile,"ResourceCompile") _p('') end function premake.vs2010_vcxproj(prj) io.eol = "\r\n" _p(xml_version_and_encoding) _p('') vs2010_config(prj) vs2010_globals(prj) _p(1,'') config_type_block(prj) _p(1,'') _p(1,'') _p(1,'') import_props(prj) _p(1,'') intermediate_and_out_dirs(prj) item_definitions(prj) vcxproj_files(prj) _p(1,'') _p(1,'') _p(1,'') _p('') end function premake.vs2010_vcxproj_user(prj) _p(xml_version_and_encoding) _p('') _p('') end function premake.vs2010_vcxproj_filters(prj) vcxproj_filter_files(prj) end premake.xcode = { } newaction { trigger = "xcode3", shortname = "Xcode 3", description = "Generate Apple Xcode 3 project files (experimental)", os = "macosx", valid_kinds = { "ConsoleApp", "WindowedApp", "SharedLib", "StaticLib" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, valid_platforms = { Native = "Native", x32 = "Native 32-bit", x64 = "Native 64-bit", Universal32 = "32-bit Universal", Universal64 = "64-bit Universal", Universal = "Universal", }, default_platform = "Universal", onsolution = function(sln) premake.xcode.preparesolution(sln) end, onproject = function(prj) premake.generate(prj, "%%.xcodeproj/project.pbxproj", premake.xcode.project) end, oncleanproject = function(prj) premake.clean.directory(prj, "%%.xcodeproj") end, oncheckproject = function(prj) local last for cfg in premake.eachconfig(prj) do if last and last ~= cfg.kind then error("Project '" .. prj.name .. "' uses more than one target kind; not supported by Xcode", 0) end last = cfg.kind end end, } local xcode = premake.xcode local tree = premake.tree function xcode.getbuildcategory(node) local categories = { [".a"] = "Frameworks", [".c"] = "Sources", [".cc"] = "Sources", [".cpp"] = "Sources", [".cxx"] = "Sources", [".dylib"] = "Frameworks", [".framework"] = "Frameworks", [".m"] = "Sources", [".mm"] = "Sources", [".strings"] = "Resources", [".nib"] = "Resources", [".xib"] = "Resources", [".icns"] = "Resources", } return categories[path.getextension(node.name)] end function xcode.getconfigname(cfg) local name = cfg.name if #cfg.project.solution.xcode.platforms > 1 then name = name .. " " .. premake.action.current().valid_platforms[cfg.platform] end return name end function xcode.getfiletype(node) local types = { [".c"] = "sourcecode.c.c", [".cc"] = "sourcecode.cpp.cpp", [".cpp"] = "sourcecode.cpp.cpp", [".css"] = "text.css", [".cxx"] = "sourcecode.cpp.cpp", [".framework"] = "wrapper.framework", [".gif"] = "image.gif", [".h"] = "sourcecode.c.h", [".html"] = "text.html", [".lua"] = "sourcecode.lua", [".m"] = "sourcecode.c.objc", [".mm"] = "sourcecode.cpp.objc", [".nib"] = "wrapper.nib", [".pch"] = "sourcecode.c.h", [".plist"] = "text.plist.xml", [".strings"] = "text.plist.strings", [".xib"] = "file.xib", [".icns"] = "image.icns", } return types[path.getextension(node.path)] or "text" end function xcode.getproducttype(node) local types = { ConsoleApp = "com.apple.product-type.tool", WindowedApp = "com.apple.product-type.application", StaticLib = "com.apple.product-type.library.static", SharedLib = "com.apple.product-type.library.dynamic", } return types[node.cfg.kind] end function xcode.gettargettype(node) local types = { ConsoleApp = "\"compiled.mach-o.executable\"", WindowedApp = "wrapper.application", StaticLib = "archive.ar", SharedLib = "\"compiled.mach-o.dylib\"", } return types[node.cfg.kind] end function xcode.getxcodeprojname(prj) local fname = premake.project.getfilename(prj, "%%.xcodeproj") return fname end function xcode.isframework(fname) return (path.getextension(fname) == ".framework") end function xcode.newid() return string.format("%04X%04X%04X%04X%04X%04X", math.random(0, 32767), math.random(0, 32767), math.random(0, 32767), math.random(0, 32767), math.random(0, 32767), math.random(0, 32767)) end function xcode.preparesolution(sln) sln.xcode = { } sln.xcode.platforms = premake.filterplatforms(sln, premake.action.current().valid_platforms, "Universal") for prj in premake.solution.eachproject(sln) do local cfg = premake.getconfig(prj, prj.configurations[1], sln.xcode.platforms[1]) local node = premake.tree.new(path.getname(cfg.buildtarget.bundlepath)) node.cfg = cfg node.id = premake.xcode.newid(node, "product") node.targetid = premake.xcode.newid(node, "target") prj.xcode = {} prj.xcode.projectnode = node end end function xcode.printlist(list, tag) if #list > 0 then _p(4,'%s = (', tag) for _, item in ipairs(list) do _p(5, '"%s",', item) end _p(4,');') end end function xcode.Header() _p('// !$*UTF8*$!') _p('{') _p(1,'archiveVersion = 1;') _p(1,'classes = {') _p(1,'};') _p(1,'objectVersion = 45;') _p(1,'objects = {') _p('') end function xcode.PBXBuildFile(tr) _p('/* Begin PBXBuildFile section */') tree.traverse(tr, { onnode = function(node) if node.buildid then _p(2,'%s /* %s in %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; };', node.buildid, node.name, xcode.getbuildcategory(node), node.id, node.name) end end }) _p('/* End PBXBuildFile section */') _p('') end function xcode.PBXContainerItemProxy(tr) if #tr.projects.children > 0 then _p('/* Begin PBXContainerItemProxy section */') for _, node in ipairs(tr.projects.children) do _p(2,'%s /* PBXContainerItemProxy */ = {', node.productproxyid) _p(3,'isa = PBXContainerItemProxy;') _p(3,'containerPortal = %s /* %s */;', node.id, path.getname(node.path)) _p(3,'proxyType = 2;') _p(3,'remoteGlobalIDString = %s;', node.project.xcode.projectnode.id) _p(3,'remoteInfo = "%s";', node.project.xcode.projectnode.name) _p(2,'};') _p(2,'%s /* PBXContainerItemProxy */ = {', node.targetproxyid) _p(3,'isa = PBXContainerItemProxy;') _p(3,'containerPortal = %s /* %s */;', node.id, path.getname(node.path)) _p(3,'proxyType = 1;') _p(3,'remoteGlobalIDString = %s;', node.project.xcode.projectnode.targetid) _p(3,'remoteInfo = "%s";', node.project.xcode.projectnode.name) _p(2,'};') end _p('/* End PBXContainerItemProxy section */') _p('') end end function xcode.PBXFileReference(tr) _p('/* Begin PBXFileReference section */') tree.traverse(tr, { onleaf = function(node) if not node.path then return end if node.kind == "product" then _p(2,'%s /* %s */ = {isa = PBXFileReference; explicitFileType = %s; includeInIndex = 0; name = "%s"; path = "%s"; sourceTree = BUILT_PRODUCTS_DIR; };', node.id, node.name, xcode.gettargettype(node), node.name, path.getname(node.cfg.buildtarget.bundlepath)) elseif node.parent.parent == tr.projects then local relpath = path.getrelative(tr.project.location, node.parent.project.location) _p(2,'%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "%s"; path = "%s"; sourceTree = SOURCE_ROOT; };', node.parent.id, node.parent.name, node.parent.name, path.join(relpath, node.parent.name)) else local pth, src if xcode.isframework(node.path) then pth = "/System/Library/Frameworks/" .. node.path src = "absolute" else pth = tree.getlocalpath(node) src = "group" end _p(2,'%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = %s; name = "%s"; path = "%s"; sourceTree = "<%s>"; };', node.id, node.name, xcode.getfiletype(node), node.name, pth, src) end end }) _p('/* End PBXFileReference section */') _p('') end function xcode.PBXFrameworksBuildPhase(tr) _p('/* Begin PBXFrameworksBuildPhase section */') _p(2,'%s /* Frameworks */ = {', tr.products.children[1].fxstageid) _p(3,'isa = PBXFrameworksBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') tree.traverse(tr.frameworks, { onleaf = function(node) _p(4,'%s /* %s in Frameworks */,', node.buildid, node.name) end }) tree.traverse(tr.projects, { onleaf = function(node) _p(4,'%s /* %s in Frameworks */,', node.buildid, node.name) end }) _p(3,');') _p(3,'runOnlyForDeploymentPostprocessing = 0;') _p(2,'};') _p('/* End PBXFrameworksBuildPhase section */') _p('') end function xcode.PBXGroup(tr) _p('/* Begin PBXGroup section */') tree.traverse(tr, { onnode = function(node) if (node.path and #node.children == 0) or node.kind == "vgroup" then return end if node.parent == tr.projects then _p(2,'%s /* Products */ = {', node.productgroupid) else _p(2,'%s /* %s */ = {', node.id, node.name) end _p(3,'isa = PBXGroup;') _p(3,'children = (') for _, childnode in ipairs(node.children) do _p(4,'%s /* %s */,', childnode.id, childnode.name) end _p(3,');') if node.parent == tr.projects then _p(3,'name = Products;') else _p(3,'name = "%s";', node.name) if node.path then local p = node.path if node.parent.path then p = path.getrelative(node.parent.path, node.path) end _p(3,'path = %s;', p) end end _p(3,'sourceTree = "";') _p(2,'};') end }, true) _p('/* End PBXGroup section */') _p('') end function xcode.PBXNativeTarget(tr) _p('/* Begin PBXNativeTarget section */') for _, node in ipairs(tr.products.children) do local name = tr.project.name _p(2,'%s /* %s */ = {', node.targetid, name) _p(3,'isa = PBXNativeTarget;') _p(3,'buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;', node.cfgsection, name) _p(3,'buildPhases = (') if #tr.project.prebuildcommands > 0 then _p(4,'9607AE1010C857E500CD1376 /* Prebuild */,') end _p(4,'%s /* Resources */,', node.resstageid) _p(4,'%s /* Sources */,', node.sourcesid) if #tr.project.prelinkcommands > 0 then _p(4,'9607AE3510C85E7E00CD1376 /* Prelink */,') end _p(4,'%s /* Frameworks */,', node.fxstageid) if #tr.project.postbuildcommands > 0 then _p(4,'9607AE3710C85E8F00CD1376 /* Postbuild */,') end _p(3,');') _p(3,'buildRules = (') _p(3,');') _p(3,'dependencies = (') for _, node in ipairs(tr.projects.children) do _p(4,'%s /* PBXTargetDependency */,', node.targetdependid) end _p(3,');') _p(3,'name = "%s";', name) local p if node.cfg.kind == "ConsoleApp" then p = "$(HOME)/bin" elseif node.cfg.kind == "WindowedApp" then p = "$(HOME)/Applications" end if p then _p(3,'productInstallPath = "%s";', p) end _p(3,'productName = "%s";', name) _p(3,'productReference = %s /* %s */;', node.id, node.name) _p(3,'productType = "%s";', xcode.getproducttype(node)) _p(2,'};') end _p('/* End PBXNativeTarget section */') _p('') end function xcode.PBXProject(tr) _p('/* Begin PBXProject section */') _p(2,'08FB7793FE84155DC02AAC07 /* Project object */ = {') _p(3,'isa = PBXProject;') _p(3,'buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "%s" */;', tr.name) _p(3,'compatibilityVersion = "Xcode 3.1";') _p(3,'hasScannedForEncodings = 1;') _p(3,'mainGroup = %s /* %s */;', tr.id, tr.name) _p(3,'projectDirPath = "";') if #tr.projects.children > 0 then _p(3,'projectReferences = (') for _, node in ipairs(tr.projects.children) do _p(4,'{') _p(5,'ProductGroup = %s /* Products */;', node.productgroupid) _p(5,'ProjectRef = %s /* %s */;', node.id, path.getname(node.path)) _p(4,'},') end _p(3,');') end _p(3,'projectRoot = "";') _p(3,'targets = (') for _, node in ipairs(tr.products.children) do _p(4,'%s /* %s */,', node.targetid, node.name) end _p(3,');') _p(2,'};') _p('/* End PBXProject section */') _p('') end function xcode.PBXReferenceProxy(tr) if #tr.projects.children > 0 then _p('/* Begin PBXReferenceProxy section */') tree.traverse(tr.projects, { onleaf = function(node) _p(2,'%s /* %s */ = {', node.id, node.name) _p(3,'isa = PBXReferenceProxy;') _p(3,'fileType = %s;', xcode.gettargettype(node)) _p(3,'path = "%s";', node.path) _p(3,'remoteRef = %s /* PBXContainerItemProxy */;', node.parent.productproxyid) _p(3,'sourceTree = BUILT_PRODUCTS_DIR;') _p(2,'};') end }) _p('/* End PBXReferenceProxy section */') _p('') end end function xcode.PBXResourcesBuildPhase(tr) _p('/* Begin PBXResourcesBuildPhase section */') for _, target in ipairs(tr.products.children) do _p(2,'%s /* Resources */ = {', target.resstageid) _p(3,'isa = PBXResourcesBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') tree.traverse(tr, { onnode = function(node) if xcode.getbuildcategory(node) == "Resources" then _p(4,'%s /* %s in Resources */,', node.buildid, node.name) end end }) _p(3,');') _p(3,'runOnlyForDeploymentPostprocessing = 0;') _p(2,'};') end _p('/* End PBXResourcesBuildPhase section */') _p('') end function xcode.PBXShellScriptBuildPhase(tr) local wrapperWritten = false local function doblock(id, name, which) local prjcmds = tr.project[which] local commands = table.join(prjcmds, {}) for _, cfg in ipairs(tr.configs) do local cfgcmds = cfg[which] if #cfgcmds > #prjcmds then table.insert(commands, 'if [ "${CONFIGURATION}" = "' .. xcode.getconfigname(cfg) .. '" ]; then') for i = #prjcmds + 1, #cfgcmds do table.insert(commands, cfgcmds[i]) end table.insert(commands, 'fi') end end if #commands > 0 then if not wrapperWritten then _p('/* Begin PBXShellScriptBuildPhase section */') wrapperWritten = true end _p(2,'%s /* %s */ = {', id, name) _p(3,'isa = PBXShellScriptBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') _p(3,');') _p(3,'inputPaths = ('); _p(3,');'); _p(3,'name = %s;', name); _p(3,'outputPaths = ('); _p(3,');'); _p(3,'runOnlyForDeploymentPostprocessing = 0;'); _p(3,'shellPath = /bin/sh;'); _p(3,'shellScript = "%s";', table.concat(commands, "\\n"):gsub('"', '\\"')) _p(2,'};') end end doblock("9607AE1010C857E500CD1376", "Prebuild", "prebuildcommands") doblock("9607AE3510C85E7E00CD1376", "Prelink", "prelinkcommands") doblock("9607AE3710C85E8F00CD1376", "Postbuild", "postbuildcommands") if wrapperWritten then _p('/* End PBXShellScriptBuildPhase section */') end end function xcode.PBXSourcesBuildPhase(tr) _p('/* Begin PBXSourcesBuildPhase section */') for _, target in ipairs(tr.products.children) do _p(2,'%s /* Sources */ = {', target.sourcesid) _p(3,'isa = PBXSourcesBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') tree.traverse(tr, { onleaf = function(node) if xcode.getbuildcategory(node) == "Sources" then _p(4,'%s /* %s in Sources */,', node.buildid, node.name) end end }) _p(3,');') _p(3,'runOnlyForDeploymentPostprocessing = 0;') _p(2,'};') end _p('/* End PBXSourcesBuildPhase section */') _p('') end function xcode.PBXVariantGroup(tr) _p('/* Begin PBXVariantGroup section */') tree.traverse(tr, { onbranch = function(node) if node.kind == "vgroup" then _p(2,'%s /* %s */ = {', node.id, node.name) _p(3,'isa = PBXVariantGroup;') _p(3,'children = (') for _, lang in ipairs(node.children) do _p(4,'%s /* %s */,', lang.id, lang.name) end _p(3,');') _p(3,'name = %s;', node.name) _p(3,'sourceTree = "";') _p(2,'};') end end }) _p('/* End PBXVariantGroup section */') _p('') end function xcode.PBXTargetDependency(tr) if #tr.projects.children > 0 then _p('/* Begin PBXTargetDependency section */') tree.traverse(tr.projects, { onleaf = function(node) _p(2,'%s /* PBXTargetDependency */ = {', node.parent.targetdependid) _p(3,'isa = PBXTargetDependency;') _p(3,'name = "%s";', node.name) _p(3,'targetProxy = %s /* PBXContainerItemProxy */;', node.parent.targetproxyid) _p(2,'};') end }) _p('/* End PBXTargetDependency section */') _p('') end end function xcode.XCBuildConfiguration_Target(tr, target, cfg) local cfgname = xcode.getconfigname(cfg) _p(2,'%s /* %s */ = {', cfg.xcode.targetid, cfgname) _p(3,'isa = XCBuildConfiguration;') _p(3,'buildSettings = {') _p(4,'ALWAYS_SEARCH_USER_PATHS = NO;') if not cfg.flags.Symbols then _p(4,'DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";') end if cfg.kind ~= "StaticLib" and cfg.buildtarget.prefix ~= "" then _p(4,'EXECUTABLE_PREFIX = %s;', cfg.buildtarget.prefix) end local outdir = path.getdirectory(cfg.buildtarget.bundlepath) if outdir ~= "." then _p(4,'CONFIGURATION_BUILD_DIR = %s;', outdir) end _p(4,'GCC_DYNAMIC_NO_PIC = NO;') _p(4,'GCC_MODEL_TUNING = G5;') if tr.infoplist then _p(4,'INFOPLIST_FILE = "%s";', tr.infoplist.path) end installpaths = { ConsoleApp = '/usr/local/bin', WindowedApp = '"$(HOME)/Applications"', SharedLib = '/usr/local/lib', StaticLib = '/usr/local/lib', } _p(4,'INSTALL_PATH = %s;', installpaths[cfg.kind]) _p(4,'PRODUCT_NAME = "%s";', cfg.buildtarget.basename) _p(3,'};') _p(3,'name = "%s";', cfgname) _p(2,'};') end function xcode.XCBuildConfiguration_Project(tr, cfg) local cfgname = xcode.getconfigname(cfg) _p(2,'%s /* %s */ = {', cfg.xcode.projectid, cfgname) _p(3,'isa = XCBuildConfiguration;') _p(3,'buildSettings = {') local archs = { Native = "$(NATIVE_ARCH_ACTUAL)", x32 = "i386", x64 = "x86_64", Universal32 = "$(ARCHS_STANDARD_32_BIT)", Universal64 = "$(ARCHS_STANDARD_64_BIT)", Universal = "$(ARCHS_STANDARD_32_64_BIT)", } _p(4,'ARCHS = "%s";', archs[cfg.platform]) local targetdir = path.getdirectory(cfg.buildtarget.bundlepath) if targetdir ~= "." then _p(4,'CONFIGURATION_BUILD_DIR = "$(SYMROOT)";'); end _p(4,'CONFIGURATION_TEMP_DIR = "$(OBJROOT)";') if cfg.flags.Symbols then _p(4,'COPY_PHASE_STRIP = NO;') end _p(4,'GCC_C_LANGUAGE_STANDARD = gnu99;') if cfg.flags.NoExceptions then _p(4,'GCC_ENABLE_CPP_EXCEPTIONS = NO;') end if cfg.flags.NoRTTI then _p(4,'GCC_ENABLE_CPP_RTTI = NO;') end if cfg.flags.Symbols and not cfg.flags.NoEditAndContinue then _p(4,'GCC_ENABLE_FIX_AND_CONTINUE = YES;') end if cfg.flags.NoExceptions then _p(4,'GCC_ENABLE_OBJC_EXCEPTIONS = NO;') end if cfg.flags.Optimize or cfg.flags.OptimizeSize then _p(4,'GCC_OPTIMIZATION_LEVEL = s;') elseif cfg.flags.OptimizeSpeed then _p(4,'GCC_OPTIMIZATION_LEVEL = 3;') else _p(4,'GCC_OPTIMIZATION_LEVEL = 0;') end if cfg.pchheader and not cfg.flags.NoPCH then _p(4,'GCC_PRECOMPILE_PREFIX_HEADER = YES;') _p(4,'GCC_PREFIX_HEADER = "%s";', cfg.pchheader) end xcode.printlist(cfg.defines, 'GCC_PREPROCESSOR_DEFINITIONS') if cfg.flags.FatalWarnings then _p(4,'GCC_TREAT_WARNINGS_AS_ERRORS = YES;') end _p(4,'GCC_WARN_ABOUT_RETURN_TYPE = YES;') _p(4,'GCC_WARN_UNUSED_VARIABLE = YES;') xcode.printlist(cfg.includedirs, 'HEADER_SEARCH_PATHS') xcode.printlist(cfg.libdirs, 'LIBRARY_SEARCH_PATHS') _p(4,'OBJROOT = "%s";', cfg.objectsdir) _p(4,'ONLY_ACTIVE_ARCH = NO;') local checks = { ["-ffast-math"] = cfg.flags.FloatFast, ["-ffloat-store"] = cfg.flags.FloatStrict, ["-fomit-frame-pointer"] = cfg.flags.NoFramePointer, } local flags = { } for flag, check in pairs(checks) do if check then table.insert(flags, flag) end end xcode.printlist(table.join(flags, cfg.buildoptions), 'OTHER_CFLAGS') flags = { } for _, lib in ipairs(premake.getlinks(cfg, "system")) do if not xcode.isframework(lib) then table.insert(flags, "-l" .. lib) end end flags = table.join(flags, cfg.linkoptions) xcode.printlist(flags, 'OTHER_LDFLAGS') _p(4,'PREBINDING = NO;') if cfg.flags.StaticRuntime then _p(4,'STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static;') end if targetdir ~= "." then _p(4,'SYMROOT = "%s";', targetdir) end if cfg.flags.ExtraWarnings then _p(4,'WARNING_CFLAGS = "-Wall";') end _p(3,'};') _p(3,'name = "%s";', cfgname) _p(2,'};') end function xcode.XCBuildConfiguration(tr) _p('/* Begin XCBuildConfiguration section */') for _, target in ipairs(tr.products.children) do for _, cfg in ipairs(tr.configs) do xcode.XCBuildConfiguration_Target(tr, target, cfg) end end for _, cfg in ipairs(tr.configs) do xcode.XCBuildConfiguration_Project(tr, cfg) end _p('/* End XCBuildConfiguration section */') _p('') end function xcode.XCBuildConfigurationList(tr) local sln = tr.project.solution _p('/* Begin XCConfigurationList section */') for _, target in ipairs(tr.products.children) do _p(2,'%s /* Build configuration list for PBXNativeTarget "%s" */ = {', target.cfgsection, target.name) _p(3,'isa = XCConfigurationList;') _p(3,'buildConfigurations = (') for _, cfg in ipairs(tr.configs) do _p(4,'%s /* %s */,', cfg.xcode.targetid, xcode.getconfigname(cfg)) end _p(3,');') _p(3,'defaultConfigurationIsVisible = 0;') _p(3,'defaultConfigurationName = "%s";', xcode.getconfigname(tr.configs[1])) _p(2,'};') end _p(2,'1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "%s" */ = {', tr.name) _p(3,'isa = XCConfigurationList;') _p(3,'buildConfigurations = (') for _, cfg in ipairs(tr.configs) do _p(4,'%s /* %s */,', cfg.xcode.projectid, xcode.getconfigname(cfg)) end _p(3,');') _p(3,'defaultConfigurationIsVisible = 0;') _p(3,'defaultConfigurationName = "%s";', xcode.getconfigname(tr.configs[1])) _p(2,'};') _p('/* End XCConfigurationList section */') _p('') end function xcode.Footer() _p(1,'};') _p('\trootObject = 08FB7793FE84155DC02AAC07 /* Project object */;') _p('}') end local xcode = premake.xcode local tree = premake.tree function xcode.buildprjtree(prj) local tr = premake.project.buildsourcetree(prj) tr.configs = {} for _, cfgname in ipairs(prj.solution.configurations) do for _, platform in ipairs(prj.solution.xcode.platforms) do local cfg = premake.getconfig(prj, cfgname, platform) cfg.xcode = {} cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode, cfgname) cfg.xcode.projectid = xcode.newid(tr, cfgname) table.insert(tr.configs, cfg) end end tree.traverse(tr, { onbranch = function(node) if path.getextension(node.name) == ".lproj" then local lang = path.getbasename(node.name) -- "English", "French", etc. for _, filenode in ipairs(node.children) do local grpnode = node.parent.children[filenode.name] if not grpnode then grpnode = tree.insert(node.parent, tree.new(filenode.name)) grpnode.kind = "vgroup" end filenode.name = path.getbasename(lang) tree.insert(grpnode, filenode) end tree.remove(node) end end }) tr.frameworks = tree.new("Frameworks") for cfg in premake.eachconfig(prj) do for _, link in ipairs(premake.getlinks(cfg, "system", "fullpath")) do local name = path.getname(link) if xcode.isframework(name) and not tr.frameworks.children[name] then node = tree.insert(tr.frameworks, tree.new(name)) node.path = link end end end if #tr.frameworks.children > 0 then tree.insert(tr, tr.frameworks) end tr.products = tree.insert(tr, tree.new("Products")) tr.projects = tree.new("Projects") for _, dep in ipairs(premake.getdependencies(prj, "sibling", "object")) do local xcpath = xcode.getxcodeprojname(dep) local xcnode = tree.insert(tr.projects, tree.new(path.getname(xcpath))) xcnode.path = xcpath xcnode.project = dep xcnode.productgroupid = xcode.newid(xcnode, "prodgrp") xcnode.productproxyid = xcode.newid(xcnode, "prodprox") xcnode.targetproxyid = xcode.newid(xcnode, "targprox") xcnode.targetdependid = xcode.newid(xcnode, "targdep") local cfg = premake.getconfig(dep, prj.configurations[1]) node = tree.insert(xcnode, tree.new(cfg.linktarget.name)) node.path = cfg.linktarget.fullpath node.cfg = cfg end if #tr.projects.children > 0 then tree.insert(tr, tr.projects) end tree.traverse(tr, { onnode = function(node) node.id = xcode.newid(node) if xcode.getbuildcategory(node) then node.buildid = xcode.newid(node, "build") end if string.endswith(node.name, "Info.plist") then tr.infoplist = node end end }, true) node = tree.insert(tr.products, prj.xcode.projectnode) node.kind = "product" node.path = node.cfg.buildtarget.fullpath node.cfgsection = xcode.newid(node, "cfg") node.resstageid = xcode.newid(node, "rez") node.sourcesid = xcode.newid(node, "src") node.fxstageid = xcode.newid(node, "fxs") return tr end function premake.xcode.project(prj) local tr = xcode.buildprjtree(prj) xcode.Header(tr) xcode.PBXBuildFile(tr) xcode.PBXContainerItemProxy(tr) xcode.PBXFileReference(tr) xcode.PBXFrameworksBuildPhase(tr) xcode.PBXGroup(tr) xcode.PBXNativeTarget(tr) xcode.PBXProject(tr) xcode.PBXReferenceProxy(tr) xcode.PBXResourcesBuildPhase(tr) xcode.PBXShellScriptBuildPhase(tr) xcode.PBXSourcesBuildPhase(tr) xcode.PBXVariantGroup(tr) xcode.PBXTargetDependency(tr) xcode.XCBuildConfiguration(tr) xcode.XCBuildConfigurationList(tr) xcode.Footer(tr) end premake.clean = { } function premake.clean.directory(obj, pattern) local fname = premake.project.getfilename(obj, pattern) os.rmdir(fname) end function premake.clean.file(obj, pattern) local fname = premake.project.getfilename(obj, pattern) os.remove(fname) end newaction { trigger = "clean", description = "Remove all binaries and generated files", onsolution = function(sln) for action in premake.action.each() do if action.oncleansolution then action.oncleansolution(sln) end end end, onproject = function(prj) for action in premake.action.each() do if action.oncleanproject then action.oncleanproject(prj) end end if (prj.objectsdir) then premake.clean.directory(prj, prj.objectsdir) end local platforms = prj.solution.platforms or { } if not table.contains(platforms, "Native") then platforms = table.join(platforms, { "Native" }) end for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do premake.clean.directory(prj, cfg.objectsdir) premake.clean.file(prj, premake.gettarget(cfg, "build", "posix", "windows", "windows").fullpath) premake.clean.file(prj, premake.gettarget(cfg, "build", "posix", "posix", "linux").fullpath) premake.clean.file(prj, premake.gettarget(cfg, "build", "posix", "posix", "macosx").fullpath) premake.clean.file(prj, premake.gettarget(cfg, "build", "posix", "PS3", "windows").fullpath) if cfg.kind == "WindowedApp" then premake.clean.directory(prj, premake.gettarget(cfg, "build", "posix", "posix", "linux").fullpath .. ".app") end premake.clean.file(prj, premake.gettarget(cfg, "link", "windows", "windows", "windows").fullpath) premake.clean.file(prj, premake.gettarget(cfg, "link", "posix", "posix", "linux").fullpath) local target = path.join(premake.project.getfilename(prj, cfg.buildtarget.directory), cfg.buildtarget.basename) for action in premake.action.each() do if action.oncleantarget then action.oncleantarget(target) end end end end end } local scriptfile = "premake4.lua" local shorthelp = "Type 'premake4 --help' for help" local versionhelp = "premake4 (Premake Build Script Generator) %s" local function injectplatform(platform) if not platform then return true end platform = premake.checkvalue(platform, premake.fields.platforms.allowed) for sln in premake.solution.each() do local platforms = sln.platforms or { } if #platforms == 0 then table.insert(platforms, "Native") end if not table.contains(platforms, "Native") then return false, sln.name .. " does not target native platform\nNative platform settings are required for the --platform feature." end if not table.contains(platforms, platform) then table.insert(platforms, platform) end sln.platforms = platforms end return true end function _premake_main(scriptpath) if (scriptpath) then local scripts = dofile(scriptpath .. "/_manifest.lua") for _,v in ipairs(scripts) do dofile(scriptpath .. "/" .. v) end end premake.action.set(_ACTION) math.randomseed(os.time()) local fname = _OPTIONS["file"] or scriptfile if (os.isfile(fname)) then dofile(fname) end if (_OPTIONS["version"]) then printf(versionhelp, _PREMAKE_VERSION) return 1 end if (_OPTIONS["help"]) then premake.showhelp() return 1 end if (not _ACTION) then print(shorthelp) return 1 end if (not os.isfile(fname)) then error("No Premake script ("..scriptfile..") found!", 2) end action = premake.action.current() if (not action) then error("Error: no such action '" .. _ACTION .. "'", 0) end ok, err = premake.option.validate(_OPTIONS) if (not ok) then error("Error: " .. err, 0) end ok, err = premake.checktools() if (not ok) then error("Error: " .. err, 0) end ok, err = injectplatform(_OPTIONS["platform"]) if (not ok) then error("Error: " .. err, 0) end print("Building configurations...") premake.buildconfigs() ok, err = premake.checkprojects() if (not ok) then error("Error: " .. err, 0) end printf("Running action '%s'...", action.trigger) premake.action.call(action.trigger) print("Done.") return 0 end $Lua: Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio $ $Authors: R. Ierusalimschy, L. H. de Figueiredo & W. Celes $ $URL: www.lua.org $ no calling environmentno valueYw#@#@#@s#@s#@w#@s#@?+@+@,@,@,@#,@^,@f,@Sl%s:%d: bad argument #%d (%s)nmethodcalling '%s' on bad self (%s)?bad argument #%d to '%s' (%s)%s expected, got %sstack overflow (%s)value expectedinvalid option '%s'_LOADEDname conflict for module '%s' cannot %s %s: %s=stdin@%sropenrbreopenreadPANIC: unprotected error in call to Lua API (%s) createresumerunningstatuswrapyield0CK@7CK@>CyL@FCJ@MC:L@RC^L@suspendednormaldead>CCCCassertcollectgarbagedofileerrorgcinfogetfenvgetmetatableloadfileloadloadstringnextpcallprintrawequalrawgetrawsetselectsetfenvsetmetatabletonumbertostringtypeunpackxpcallCF@CB@CE@CB?@CB@CA@C?@CD@C{E@CD@(CkC@-C}G@3C=@9CA@BCB@ICAB@PCF@WCDA@_C?@lCW>@uCH@~C8C@CdF@CG@'tostring' must return a string to 'print'base out of range__metatablenil or table expectedcannot change a protected metatablelevel must be non-negativeinvalid levelfno function environment for tail call at level %d'setfenv' cannot change environment of given objectstoprestartcollectcountstepsetpausesetstepmulCCCCCCC:too many nested functionsreader function must return a string=(load)assertion failed!%stoo many results to unpackindex out of range__tostringtruefalsenil%s: %pboolean or proxy expectedcoroutine expectedtoo many arguments to resumecannot resume %s coroutinetoo many results to resumeLua function expected_GLua 5.1_VERSIONipairspairskv__modenewproxycoroutinecontrol structure too longfunction or expression too complexconstant table overflowcode size overflowT@T@T@T@%U@%U@%U@U@U@U@V@V@V@V@zV@zV@zV@zV@zV@8V@[V@CW@HW@CW@CW@^W@^W@^W@^W@PW@!Z@nZ@%Z@)Z@%sfunction or level expectedinvalid optionsourceshort_srclinedefinedlastlinedefinedwhatcurrentlinenupsnamenamewhatactivelinesfunclevel out of rangecallreturnlinecounttail returnLCQCXC]CcCexternal hooklua_debug> cont =(debug command) stack traceback: ... Snl%s:%d: in function '%s' in main chunk ? in function <%s:%d>(*temporary)p@p@#q@.q@$s@.q@#q@$s@$s@Dq@$s@$s@$s@$s@$s@$s@$s@$s@$s@bq@q@$s@$s@$s@$s@$s@q@q@Sr@q@q@jq@hr@$s@r@r@?localglobalfieldupvaluemethod/t@t@t@t@_t@t@Ct@t@t@t@t@t@tail=(tail call)=[C]CmainLua%s:%d: %sattempt to compare two %s valuesattempt to compare %s with %sattempt to %s %s '%s' (a %s value)attempt to %s a %s valueperform arithmetic onconcatenatenot enough memoryerror in error handlingstack overflowcallnC stack overflowcannot resume non-suspended coroutineattempt to yield across metamethod/C-call boundary@@@R@@@u@@@@Г@@@@@ @@@@packagetableioosstringmathdebugCL@Ch@Cf'AC@C#@C AC@Ck@closeflushinputlinesopenoutputpopenreadtmpfiletypewriteCo@C@C@Cg@C@C@Cw@C@Cݞ@C@C@CCseeksetvbuf__gc__tostringCo@C@CF@C @HC@MCX@C@UC@ZC̝@%s: %s%sFILE*closed filefileattempt to use a closed filecannot close standard file__closefile (closed)file (%p)rstandard %s file is closedwtoo many argumentsinvalid option%lfinvalid formatfile is already closed%.14gsetcurendCCC@nofulllineCCC__indexiostdinstdoutstderrandbreakdoelseelseifendfalseforfunctionifinlocalnilnotorrepeatreturnthentrueuntilwhile.....==>=<=~=@CDCJCMCRCYC]CcCgCpCsCvC|CCCCCCCCCCCCCCCCCCCchar(%d)%c%s:%d: %s%s near '%s'lexical element too longchunk has too many linesEe+-malformed numberunfinished long stringunfinished long commentnesting of [[...]] is deprecatedinvalid long string delimiterunfinished stringescape sequence too large.absacosasinatan2atanceilcoshcosdegexpfloorfmodfrexpldexplog10logmaxminmodfpowradrandomrandomseedsinhsinsqrttanhtanC@C @C@C^@C4@C@Cb@C8@C^@C4@C@C@C@C@C @C@C}@C@C @C@C@C@C@C@C@Dc@D@ D@9RFߑ?9RFߑ?interval is emptywrong number of argumentsF?mathpihugemodmemory allocation error: block too bigmodulerequireD{@D@S@@Y@@loadlibseeallD@D<@system error %d _LOADLIBLOADLIB: %s%sopeninit\.'package.%s' must be a string?r no file '%s'error loading module '%s' from file '%s': %spath_luaopen_%scpath no module '%s' in file '%s'preload'package.preload' must be a table no field package.preload['%s']_LOADEDloop or previous error loading module '%s'loaders'package.loaders' must be a tablemodule '%s' not found:%sname conflict for module '%s'_NAME_M_PACKAGEf'module' not called from a Lua function__index;;;;unable to get ModuleFileName!__gcpackage.\?.lua;!\lua\?.lua;!\lua\?\init.lua;!\?.lua;!\?\init.luaLUA_PATH.\?.dll;!\?.dll;!\loadall.dllLUA_CPATH\ ; ? ! -configloaded%(null)%p... "]`qT`Pql1 or '...' expectedconstant table overflowcannot use '...' outside a vararg functionitems in a constructorambiguous syntax (function call x new statement)function arguments expectedunexpected symbolsyntax errorvariables in assignmentnot enough memorybytechardumpfindformatgfindgmatchgsublenlowermatchrepreversesubupper@ D@E D}@J D-@O D AT DA[ D Aa D Ah D Am D@q D<@w D A} DP@ D@ D-@ D@string slice too longinvalid valueunable to dump given functionmalformed pattern (ends with '%%')malformed pattern (missing ']')AnAHAlAnAnAnAnAnAnAnAAnAnAnAAnAnAAnAAnAA7AnAdAinvalid pattern captureunbalanced patternmissing '[' after '%%f' in patterninvalid capture indextoo many capturesunfinished capture^$*+?.([%-'string.gfind' was renamed to 'string.gmatch'string/function/table expectedinvalid replacement value (a %s)-+ #0invalid format (repeated flags)invalid format (width or precision too long)\r\000invalid option '%%%c' to 'format'string__indexYinvalid key to 'next'table overflowYtable index is niltable index is NaNconcatforeachforeachigetnmaxninsertremovesetnsort D~#A'D A/D A8D!A=D!!ABD!AID"APD!AUD'A'setn' is obsoletewrong number of arguments to 'insert'invalid value (%s) at index %d in table for 'concat'invalid order function for sortingtablenilbooleanuserdatanumberstringtablefunctionthreadprotoupval`DdDlDuD|DDDlDDDD__index__newindex__gc__mode__eq__add__sub__mul__div__mod__pow__unm__len__lt__le__concat__callDDDD DDDD"D(D.D4D:D@DEDJDSD%s: %s in precompiled chunkunexpected endbad integercode too deepbad constantbad codebinary stringbad header=?%.14gindexloop in gettableloop in settable}4A4A4A4A4A4A4A4Astring length overflow6A 7A6A6A6A 7A,7Aget length of'for' initial value must be a number'for' limit must be a number'for' step must be a number8A8A8A8A 9A-9Ak9A9A9A8:A:A:AZ;A;A,AO>A>A ?At?A?A?Ah@ASAAAAAAOBA;CACACADA8EAEAFAFA-LIBGCCW32-EH-2-SJLJ-GTHR-MINGW32w32_sharedptr->size == sizeof(W32_EH_SHARED)%s:%u: failed assertion `%s' ../../gcc/gcc/config/i386/w32-shared-ptr.cGetAtomNameA (atom, s, sizeof(s)) != 0T0:H20(:20;284D4P4d4t444444444 5$585H5\5t555555555666(646@6L6X6d6p6x6666666666666667 777$70787@7H7P7\7d7p7x777777777777788 8(80888@8L8X8d8p8|888888888888899 9,989D9P9\9h9t9|999999984D4P4d4t444444444 5$585H5\5t555555555666(646@6L6X6d6p6x6666666666666667 777$70787@7H7P7\7d7p7x777777777777788 8(80888@8L8X8d8p8|888888888888899 9,989D9P9\9h9t9|9999999AddAtomA5CopyFileA<CreateDirectoryAExitProcessFindAtomAFindCloseFindFirstFileAFindNextFileAFormatMessageAFreeLibraryGetAtomNameAGetCurrentDirectoryACGetLastErrorMGetModuleFileNameAjGetProcAddress LoadLibraryAtRemoveDirectoryASetCurrentDirectoryASetUnhandledExceptionFilterO_stat'__getmainargs0__mb_cur_max<__p__environ>__p__fmodeP__set_app_typey_cexit_errno_filbuf_iob_isctype^_onexitf_pcloseg_pctypej_popen_setjmp_setmodeabortacosasinatanatan2atexit"ceil#clearerr$clock%cos&cosh(difftime*exit+exp-fclose0fflush3fgets6floor7fmod8fopen9fprintf:fputc;fputs>fread?free@freopenAfrexpBfscanfCfseekEftellGfwriteKgetenvOgmtimekldexpmlocaleconvnlocaltimeologplog10qlongjmprmallocvmemchrwmemcmpxmemcpy{mktime|modf~powputsrandreallocremoverenamesetlocalesetvbufsignalsinsinhsprintfsqrtsrandstrcatstrchrstrcmpstrcollstrcpystrcspnstrerrorstrftimestrncatstrncpystrpbrkstrrchrstrstrstrtodstrtoulsystemtantanhtimetmpfiletmpnamtolowertoupperungetc0000000000000000000KERNEL32.dll0msvcrt.dll(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0(0msvcrt.dllode-0.14/build/premake4.lua0000644000000000000000000003771212635011627014232 0ustar rootroot---------------------------------------------------------------------- -- Premake4 configuration script for OpenDE -- Contributed by Jason Perkins (starkos@industriousone.com) -- For more information on Premake: http://industriousone.com/premake ---------------------------------------------------------------------- ode_version = "0.14" ---------------------------------------------------------------------- -- Demo list: add/remove demos from here and the rest of the build -- should just work. ---------------------------------------------------------------------- local demos = { "boxstack", "buggy", "cards", "chain1", "chain2", "collision", "crash", "cylvssphere", "dball", "dhinge", "feedback", "friction", "gyroscopic", "gyro2", "heightfield", "hinge", "I", "jointPR", "jointPU", "joints", "kinematic", "motion", "motor", "ode", "piston", "plane2d", "rfriction", "slider", "space", "space_stress", "step", "transmission" } local trimesh_demos = { "basket", "cyl", "moving_convex", "moving_trimesh", "tracks", "trimesh" } if not _OPTIONS["no-trimesh"] then demos = table.join(demos, trimesh_demos) end ---------------------------------------------------------------------- -- Configuration options ---------------------------------------------------------------------- newoption { trigger = "with-demos", description = "Builds the demo applications and DrawStuff library" } newoption { trigger = "with-tests", description = "Builds the unit test application" } newoption { trigger = "with-gimpact", description = "Use GIMPACT for trimesh collisions (experimental)" } newoption { trigger = "all-collis-libs", description = "Include sources of all collision libraries into the project" } newoption { trigger = "with-libccd", description = "Uses libccd for handling some collision tests absent in ODE." } newoption { trigger = "no-dif", description = "Exclude DIF (Dynamics Interchange Format) exports" } newoption { trigger = "no-trimesh", description = "Exclude trimesh collision geometry" } newoption { trigger = "with-ou", description = "Use TLS for global caches (allows threaded collision checks for separated spaces)" } newoption { trigger = "with-builtin-threading-impl", description = "Include built-in multithreaded threading implementation (still must be created and assigned to be used)" } newoption { trigger = "no-threading-intf", description = "Disable threading interface support (external implementations may not be assigned; overrides with-builtin-threading-impl)" } newoption { trigger = "16bit-indices", description = "Use 16-bit indices for trimeshes (default is 32-bit)" } newoption { trigger = "old-trimesh", description = "Use old OPCODE trimesh-trimesh collider" } newoption { trigger = "to", value = "path", description = "Set the output location for the generated project files" } newoption { trigger = "only-shared", description = "Only build shared (DLL) version of the library" } newoption { trigger = "only-static", description = "Only build static versions of the library" } newoption { trigger = "only-single", description = "Only use single-precision math" } newoption { trigger = "only-double", description = "Only use double-precision math" } -- always clean all of the optional components and toolsets if _ACTION == "clean" then _OPTIONS["with-demos"] = "" _OPTIONS["with-tests"] = "" for action in premake.action.each() do os.rmdir(action.trigger) end os.remove("../ode/src/config.h") os.remove("../include/ode/version.h") os.remove("../include/ode/precision.h") os.remove("../libccd/src/ccd/precision.h") end -- special validation for Xcode if _ACTION == "xcode3" and (not _OPTIONS["only-static"] and not _OPTIONS["only-shared"]) then error( "Xcode does not support different library types in a single project.\n" .. "Please use one of the flags: --only-static or --only-shared", 0) end -- build the list of configurations, based on the flags. Ends up -- with configurations like "Debug", "DebugSingle" or "DebugSingleShared" local configs = { "Debug", "Release" } local function addconfigs(...) local newconfigs = { } for _, root in ipairs(configs) do for _, suffix in ipairs(arg) do table.insert(newconfigs, root .. suffix) end end configs = newconfigs end if not _OPTIONS["only-single"] and not _OPTIONS["only-double"] then addconfigs("Single", "Double") end if not _OPTIONS["only-shared"] and not _OPTIONS["only-static"] then addconfigs("DLL", "Lib") end ---------------------------------------------------------------------- -- The solution, and solution-wide settings ---------------------------------------------------------------------- solution "ode" language "C++" uuid "4DA77C12-15E5-497B-B1BB-5100D5161E15" location ( _OPTIONS["to"] or _ACTION ) includedirs { "../include", "../ode/src" } defines { "_MT" } -- apply the configuration list built above configurations (configs) configuration { "Debug*" } defines { "_DEBUG" } flags { "Symbols" } configuration { "Release*" } defines { "NDEBUG", "dNODEBUG" } flags { "OptimizeSpeed", "NoFramePointer" } configuration { "*Single*" } defines { "dIDESINGLE", "CCD_IDESINGLE" } configuration { "*Double*" } defines { "dIDEDOUBLE", "CCD_IDEDOUBLE" } configuration { "Windows" } defines { "WIN32" } configuration { "MacOSX" } linkoptions { "-framework Carbon" } -- give each configuration a unique output directory for _, name in ipairs(configurations()) do configuration { name } targetdir ( "../lib/" .. name ) end -- disable Visual Studio security warnings configuration { "vs*" } defines { "_CRT_SECURE_NO_DEPRECATE" } -- enable M_* macros from math.h configuration { "vs*" } defines { "_USE_MATH_DEFINES" } -- don't remember why we had to do this configuration { "vs2002 or vs2003", "*Lib" } flags { "StaticRuntime" } ---------------------------------------------------------------------- -- The demo projects, automated from list above. These go first so -- they will be selected as the active project automatically in IDEs ---------------------------------------------------------------------- if _OPTIONS["with-demos"] then for _, name in ipairs(demos) do project ( "demo_" .. name ) kind "ConsoleApp" location ( _OPTIONS["to"] or _ACTION ) files { "../ode/demo/demo_" .. name .. ".*" } links { "ode", "drawstuff" } configuration { "Windows" } files { "../drawstuff/src/resources.rc" } links { "user32", "winmm", "gdi32", "opengl32", "glu32" } configuration { "MacOSX" } linkoptions { "-framework Carbon -framework OpenGL -framework AGL" } configuration { "not Windows", "not MacOSX" } links { "GL", "GLU" } end end ---------------------------------------------------------------------- -- The ODE library project ---------------------------------------------------------------------- project "ode" -- kind "StaticLib" location ( _OPTIONS["to"] or _ACTION ) includedirs { "../ode/src/joints", "../OPCODE", "../GIMPACT/include", "../libccd/src" } files { "../include/ode/*.h", "../ode/src/joints/*.h", "../ode/src/joints/*.cpp", "../ode/src/*.h", "../ode/src/*.c", "../ode/src/*.cpp", } excludes { "../ode/src/collision_std.cpp", } if _OPTIONS["with-ou"] or not _OPTIONS["no-threading-intf"] then includedirs { "../ou/include" } files { "../ou/include/**.h", "../ou/src/**.h", "../ou/src/**.cpp" } defines { "_OU_NAMESPACE=odeou" } if _ACTION == "gmake" and ( os.get() == "linux" or os.get() == "bsd" ) then buildoptions { "-pthread" } linkoptions { "-pthread" } end if _ACTION == "gmake" and os.get() == "windows" then buildoptions { "-mthreads" } linkoptions { "-mthreads" } end -- TODO: MacOSX probably needs something too end configuration { "no-dif" } excludes { "../ode/src/export-dif.cpp" } configuration { "no-trimesh" } excludes { "../ode/src/collision_trimesh_colliders.h", "../ode/src/collision_trimesh_internal.h", "../ode/src/collision_trimesh_opcode.cpp", "../ode/src/collision_trimesh_gimpact.cpp", "../ode/src/collision_trimesh_box.cpp", "../ode/src/collision_trimesh_ccylinder.cpp", "../ode/src/collision_cylinder_trimesh.cpp", "../ode/src/collision_trimesh_distance.cpp", "../ode/src/collision_trimesh_ray.cpp", "../ode/src/collision_trimesh_sphere.cpp", "../ode/src/collision_trimesh_trimesh.cpp", "../ode/src/collision_trimesh_plane.cpp", "../ode/src/collision_convex_trimesh.cpp" } configuration { "not no-trimesh", "with-gimpact or all-collis-libs" } files { "../GIMPACT/**.h", "../GIMPACT/**.cpp" } configuration { "not no-trimesh", "not with-gimpact" } files { "../OPCODE/**.h", "../OPCODE/**.cpp" } configuration { "with-libccd" } files { "../libccd/src/ccd/*.h", "../libccd/src/*.c" } defines { "dLIBCCD_ENABLED", "dLIBCCD_INTERNAL", "dLIBCCD_BOX_CYL", "dLIBCCD_CYL_CYL", "dLIBCCD_CAP_CYL", "dLIBCCD_CONVEX_BOX", "dLIBCCD_CONVEX_CAP", "dLIBCCD_CONVEX_CYL", "dLIBCCD_CONVEX_SPHERE", "dLIBCCD_CONVEX_CONVEX" } configuration { "not with-libccd" } excludes { "../ode/src/collision_libccd.cpp", "../ode/src/collision_libccd.h" } configuration { "windows" } links { "user32" } configuration { "only-static or *Lib" } kind "StaticLib" defines "ODE_LIB" configuration { "only-shared or *DLL" } kind "SharedLib" defines "ODE_DLL" configuration { "*DLL" } defines "_DLL" configuration { "Debug" } targetname "oded" configuration { "Release" } targetname "ode" configuration { "DebugSingle*" } targetname "ode_singled" configuration { "ReleaseSingle*" } targetname "ode_single" configuration { "DebugDouble*" } targetname "ode_doubled" configuration { "ReleaseDouble*" } targetname "ode_double" ---------------------------------------------------------------------- -- Write a custom to build, based on the supplied flags ---------------------------------------------------------------------- if _ACTION and _ACTION ~= "clean" then local infile = io.open("config-default.h", "r") local text = infile:read("*a") if _OPTIONS["no-trimesh"] then text = string.gsub(text, "#define dTRIMESH_ENABLED 1", "/* #define dTRIMESH_ENABLED 1 */") text = string.gsub(text, "#define dTRIMESH_OPCODE 1", "/* #define dTRIMESH_OPCODE 1 */") elseif (_OPTIONS["with-gimpact"]) then text = string.gsub(text, "#define dTRIMESH_OPCODE 1", "#define dTRIMESH_GIMPACT 1") end if _OPTIONS["with-ou"] or not _OPTIONS["no-threading-intf"] then text = string.gsub(text, "/%* #define dOU_ENABLED 1 %*/", "#define dOU_ENABLED 1") text = string.gsub(text, "/%* #define dATOMICS_ENABLED 1 %*/", "#define dATOMICS_ENABLED 1") end if _OPTIONS["with-ou"] then text = string.gsub(text, "/%* #define dTLS_ENABLED 1 %*/", "#define dTLS_ENABLED 1") end if _OPTIONS["no-threading-intf"] then text = string.gsub(text, "/%* #define dTHREADING_INTF_DISABLED 1 %*/", "#define dTHREADING_INTF_DISABLED 1") elseif _OPTIONS["with-builtin-threading-impl"] then text = string.gsub(text, "/%* #define dBUILTIN_THREADING_IMPL_ENABLED 1 %*/", "#define dBUILTIN_THREADING_IMPL_ENABLED 1") end if _OPTIONS["16bit-indices"] then text = string.gsub(text, "#define dTRIMESH_16BIT_INDICES 0", "#define dTRIMESH_16BIT_INDICES 1") end if _OPTIONS["old-trimesh"] then text = string.gsub(text, "#define dTRIMESH_OPCODE_USE_OLD_TRIMESH_TRIMESH_COLLIDER 0", "#define dTRIMESH_OPCODE_USE_OLD_TRIMESH_TRIMESH_COLLIDER 1") end local outfile = io.open("../ode/src/config.h", "w") outfile:write(text) outfile:close() end ---------------------------- -- Write precision headers ---------------------------- if _ACTION and _ACTION ~= "clean" then function generateheader(headerfile, placeholder, precstr) local outfile = io.open(headerfile, "w") for i in io.lines(headerfile .. ".in") do local j,_ = string.gsub(i, placeholder, precstr) --print("writing " .. j .. " into " .. headerfile) outfile:write(j .. "\n") end outfile:close() end function generate(precstr) generateheader("../include/ode/precision.h", "@ODE_PRECISION@", "d" .. precstr) generateheader("../libccd/src/ccd/precision.h", "@CCD_PRECISION@", "CCD_" .. precstr) end if _OPTIONS["only-single"] then generate("SINGLE") elseif _OPTIONS["only-double"] then generate("DOUBLE") else generate("UNDEFINEDPRECISION") end generateheader("../include/ode/version.h", "@ODE_VERSION@", ode_version) end ---------------------------------------------------------------------- -- The DrawStuff library project ---------------------------------------------------------------------- if _OPTIONS["with-demos"] then project "drawstuff" location ( _OPTIONS["to"] or _ACTION ) files { "../include/drawstuff/*.h", "../drawstuff/src/internal.h", "../drawstuff/src/drawstuff.cpp" } configuration { "Debug*" } targetname "drawstuffd" configuration { "only-static or *Lib" } kind "StaticLib" defines { "DS_LIB" } configuration { "only-shared or *DLL" } kind "SharedLib" defines { "DS_DLL", "USRDLL" } configuration { "Windows" } files { "../drawstuff/src/resource.h", "../drawstuff/src/resources.rc", "../drawstuff/src/windows.cpp" } links { "user32", "opengl32", "glu32", "winmm", "gdi32" } configuration { "MacOSX" } defines { "HAVE_APPLE_OPENGL_FRAMEWORK" } files { "../drawstuff/src/osx.cpp" } linkoptions { "-framework Carbon -framework OpenGL -framework AGL" } configuration { "not Windows", "not MacOSX" } files { "../drawstuff/src/x11.cpp" } links { "X11", "GL", "GLU" } end ---------------------------------------------------------------------- -- The automated test application ---------------------------------------------------------------------- if _OPTIONS["with-tests"] then project "tests" kind "ConsoleApp" location ( _OPTIONS["to"] or _ACTION ) includedirs { "../tests/UnitTest++/src" } files { "../tests/*.cpp", "../tests/joints/*.cpp", "../tests/UnitTest++/src/*" } links { "ode" } configuration { "Windows" } files { "../tests/UnitTest++/src/Win32/*" } configuration { "not Windows" } files { "../tests/UnitTest++/src/Posix/*" } -- add post-build step to automatically run test executable local path_to_lib = path.getrelative(location(), "../lib") local command = path.translate(path.join(path_to_lib, "%s/tests")) for _, name in ipairs(configurations()) do configuration { name } postbuildcommands { command:format(name) } end end ode-0.14/configure.ac0000644000000000000000000004262612635011627013206 0ustar rootrootdnl AC_INIT does not take a macro as a version nr: set it separately! - Bram AC_INIT([ODE],[0.14],[ode@ode.org]) ODE_VERSION=0.14 AC_SUBST(ODE_VERSION) # Those are instructions from the Libtool manual: # 1. Start with version information of `0:0:0' for each libtool library. # # 2. Update the version information only immediately before a public # release of your software. More frequent updates are unnecessary, # and only guarantee that the current interface number gets larger # faster. # # 3. If the library source code has changed at all since the last # update, then increment REVISION (`C:R:A' becomes `C:r+1:A'). # # 4. If any interfaces have been added, removed, or changed since the # last update, increment CURRENT, and set REVISION to 0. # # 5. If any interfaces have been added since the last public release, # then increment AGE. # # 6. If any interfaces have been removed since the last public release, # then set AGE to 0. CURRENT=6 REVISION=0 AGE=0 AC_ARG_ENABLE(version-info, AS_HELP_STRING([--disable-version-info], [don't encode version information in the generated library]), version_info=$enableval, version_info=yes) if test x$version_info = xyes then ODE_VERSION_INFO="-version-info $CURRENT:$REVISION:$AGE" else ODE_VERSION_INFO="-avoid-version" fi AC_SUBST(ODE_VERSION_INFO) AC_CONFIG_SRCDIR([ode/src/ode.cpp]) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_HOST AM_INIT_AUTOMAKE([1.10 foreign]) AC_CONFIG_HEADERS([ode/src/config.h]) dnl This is needed because we have subdirectories AC_PROG_MAKE_SET AC_PROG_CXX AC_PROG_CC AM_PROG_CC_C_O AC_PROG_CPP AC_PROG_AWK AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MKDIR_P LT_INIT([disable-shared win32-dll]) AC_CHECK_TOOLS([WINDRES], [windres]) AC_C_BIGENDIAN AC_C_INLINE AC_C_VOLATILE PKG_PROG_PKG_CONFIG AC_ARG_VAR([DOXYGEN], [set to doxygen binary to generate doxygen docs]) AC_CHECK_PROGS([DOXYGEN], [doxygen]) AM_CONDITIONAL([HAVE_DOXYGEN], [test x$DOXYGEN = xdoxygen]) dnl this may NOT be the machine on which the code is going to run in, dnl so allow users to compile programs for their target machine. pentium=no cpu64=no case "$host_cpu" in i586 | i686 | i786 ) pentium=yes AC_DEFINE(PENTIUM,1,[compiling for a pentium on a gcc-based platform?]) ;; x86_64* ) pentium=yes cpu64=yes AC_DEFINE(X86_64_SYSTEM,1,[compiling for a X86_64 system on a gcc-based platform?]) ;; esac AM_CONDITIONAL(X86_64_SYSTEM, test x$cpu64 = xyes) dnl check for required headers AC_CHECK_HEADERS( [alloca.h stdio.h inttypes.h stdint.h stdlib.h math.h \ string.h stdarg.h malloc.h float.h time.h sys/time.h \ limits.h stddef.h]) opcode=no gimpact=no AC_ARG_WITH(trimesh, AS_HELP_STRING([--with-trimesh=@<:@opcode|gimpact|none@:>@], [use the specified system for trimesh support @<:@default=opcode@:>@]), trimesh=$withval,trimesh=opcode ) if test "$trimesh" = opcode then opcode=yes fi if test "$trimesh" = gimpact then gimpact=yes fi AM_CONDITIONAL(OPCODE, test $opcode = yes) AM_CONDITIONAL(GIMPACT, test $gimpact = yes) AM_CONDITIONAL(TRIMESH, test $opcode = yes -o $gimpact = yes) AC_MSG_CHECKING(if double precision is requested) AC_ARG_ENABLE(double-precision, AS_HELP_STRING([--enable-double-precision], [Configure ODE to work with double precision, if not specified, single precision is used @<:@default=no@:>@]), usedouble=$enableval,usedouble=no) AC_MSG_RESULT([$usedouble]) if test "$usedouble" = yes; then ODE_PRECISION=dDOUBLE else ODE_PRECISION=dSINGLE fi AC_SUBST(ODE_PRECISION) AC_ARG_WITH([drawstuff], AS_HELP_STRING([--with-drawstuff=X11|Win32|OSX|none], [force a particular drawstuff implementation or disable it.[default=autodetect]]), [drawstuff=$withval],[drawstuff=]) dnl Set some Platform Specific Variables EXTRA_LIBTOOL_LDFLAGS= case "$host_os" in cygwin* | mingw*) if test "x$drawstuff" = x then drawstuff="Win32" # if in a Windows enviroment fi EXTRA_LIBTOOL_LDFLAGS="-no-undefined" ;; *apple* | *darwin*) # For Mac OS X if test "x$drawstuff" = x then drawstuff="OSX" fi dnl We need to use C++ compilation and linking for ode on Mac dnl Might as well do it for all code. CC="$CXX" LINK="$CXXLINK" ;; *) if test "x$drawstuff" = x then drawstuff="X11" # if anything else default to X11 fi ;; esac AC_SUBST(EXTRA_LIBTOOL_LDFLAGS) dnl Set Drawstuff variables AC_MSG_CHECKING([which drawstuff lib to build]) AC_MSG_RESULT($drawstuff) if test "x$drawstuff" = "xX11" then # The built-in macro, X_PATH, causes too many problems, these days everyone uses Xorg, # so we can ask pkg-config to find it for us. PKG_CHECK_MODULES(X11, x11, [], [drawstuff="none"]) fi dnl Check for OpenGL if test "x$drawstuff" = "xOSX"; then AC_DEFINE([HAVE_APPLE_OPENGL_FRAMEWORK], [1], [Use the Apple OpenGL framework.]) GL_LIBS="-framework OpenGL -framework GLUT" elif test "x$drawstuff" != "xnone"; then have_gl_headers=yes AC_CHECK_HEADERS(GL/gl.h GL/glu.h GL/glext.h, , [have_gl_headers=no], [[#ifdef WIN32 #include #endif #if HAVE_GL_GL_H #include #endif #if HAVE_GL_GLU_H #include #endif ]]) have_gl=no have_glu=no TEMP_LDFLAGS="$LDFLAGS" AC_CHECK_LIB(GL, main, [GL_LIBS="-lGL"; have_gl=yes]) AC_CHECK_LIB(GLU, main, [GL_LIBS="-lGLU $GL_LIBS"; have_glu=yes], , -lGL) AC_CHECK_LIB(opengl32, main, [GL_LIBS="-lopengl32"; have_gl=yes]) AC_CHECK_LIB(glu32, main, [GL_LIBS="-lglu32 $GL_LIBS"; have_glu=yes], , -lopengl32) LDFLAGS="$TEMP_LDFLAGS" if test $have_gl = no -o $have_glu = no -o $have_gl_headers = no; then drawstuff="none" fi fi AC_SUBST(GL_LIBS) dnl Set Conditionals AM_CONDITIONAL(WIN32, test x$drawstuff = xWin32) AM_CONDITIONAL(X11, test x$drawstuff = xX11) AM_CONDITIONAL(OSX, test x$drawstuff = xOSX) AM_CONDITIONAL(ENABLE_DRAWSTUFF, test x$drawstuff != xnone) dnl Check if we want to build demos AC_MSG_CHECKING(if demos should be built) AC_ARG_ENABLE(demos, AS_HELP_STRING([--disable-demos], [don't build demos]), enable_demos=$enableval,enable_demos=yes) if test x$drawstuff = xnone -a x$enable_demos = xyes ; then enable_demos=no AC_MSG_RESULT($enable_demos) AC_MSG_WARN([Demos will not be built because OpenGL doesn't seem to work. See `config.log' for details.]) else AC_MSG_RESULT($enable_demos) fi dnl stdc++ is required when linking C programs against ode AC_CHECK_LIB(stdc++,main,[LIBSTDCXX="-lstdc++"],[LIBSTDCXX=]) AC_SUBST(LIBSTDCXX) AC_CHECK_LIB(pthread,main,[LIBS="$LIBS -lpthread"]) dnl test if we will build demos AM_CONDITIONAL(ENABLE_DEMOS, test x$enable_demos = xyes) dnl Check if the user wants the old timesh collider old_trimesh=no AC_ARG_ENABLE([old-trimesh], AS_HELP_STRING([--enable-old-trimesh],[enable use of the old trimesh collider]), [old_trimesh=$enableval] ) if test x$old_trimesh = xyes -a $trimesh = opcode; then AC_DEFINE(dTRIMESH_OPCODE_USE_OLD_TRIMESH_TRIMESH_COLLIDER, 1, [Use the old trimesh-trimesh collider]) else old_trimesh=no fi dnl Check if the user wants to profile ODE using gprof AC_MSG_CHECKING(for gprof) AC_ARG_ENABLE([gprof], AS_HELP_STRING([--enable-gprof],[enable profiling with gprof]), gprof=$enableval, gprof=no) if test "$gprof" != no then CFLAGS="-pg $CFLAGS" CXXFLAGS="-pg $CXXFLAGS" AC_MSG_RESULT(enabled) AC_CHECK_LIB(gmon, main,[LIBS="$LIBS -lgmon"]) else AC_MSG_RESULT(no) fi # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL AC_C_INLINE AC_TYPE_INT32_T AC_FUNC_OBSTACK AC_TYPE_SIZE_T AC_TYPE_UINT32_T dnl Check for autoscan sugested functions AC_CHECK_LIB(m, [main]) AC_CHECK_LIB(sunmath, [main]) AC_CHECK_FUNCS([floor memmove memset sqrt sqrtf sinf cosf fabsf atan2f fmodf copysignf copysign snprintf vsnprintf gettimeofday isnan isnanf _isnan _isnanf __isnan __isnanf strchr strstr pthread_attr_setstacklazy clock_gettime]) AC_FUNC_ALLOCA AC_ARG_ENABLE([threading-intf], AS_HELP_STRING([--disable-threading-intf], [disable threading interface support (external implementations may not be assigned; overrides --enable-builtin-threading-impl)] ), threading_intf=$enableval,threading_intf=yes) AC_ARG_ENABLE([ou], AS_HELP_STRING([--enable-ou], [use TLS for global caches (allows threaded collision checks for isolated spaces)] ), use_ou_tls=$enableval,use_ou_tls=no) use_ou="no" if test x$use_ou_tls = xyes -o x$threading_intf = xyes then use_ou="yes" fi if test x$use_ou = xyes then OU_NAMESPACE=odeou AC_CONFIG_COMMANDS_POST([export OU_NAMESPACE=odeou]) AC_DEFINE([_OU_NAMESPACE],[odeou],[libou namespace for ODE]) AC_DEFINE([dOU_ENABLED],[1],[Generic OU features are enabled]) AC_DEFINE([dATOMICS_ENABLED],[1],[Atomic API of OU is enabled]) if test x$use_ou_tls = xyes then AC_DEFINE([dTLS_ENABLED],[1],[Thread Local Storage API of OU is enabled]) fi case "$host_os" in cygwin* | mingw*) targetos=_OU_TARGET_OS_WINDOWS ;; *qnx*) targetos=_OU_TARGET_OS_QNX ;; *apple* | *darwin*) targetos=_OU_TARGET_OS_MAC ;; *sunos*) targetos=_OU_TARGET_OS_SUNOS ;; *aix*) targetos=_OU_TARGET_OS_AIX ;; *) targetos=_OU_TARGET_OS_GENUNIX ;; esac if test $targetos = _OU_TARGET_OS_MAC then MAC_OS_X_VERSION=1000 AC_CHECK_FUNC([OSAtomicAdd32Barrier], [MAC_OS_X_VERSION=1040]) AC_CHECK_FUNC([OSAtomicAnd32OrigBarrier], [MAC_OS_X_VERSION=1050]) AC_DEFINE_UNQUOTED(MAC_OS_X_VERSION, $MAC_OS_X_VERSION, [Mac OS X version setting for OU Library]) fi if test $targetos = _OU_TARGET_OS_SUNOS then AC_CHECK_FUNC(atomic_inc_32_nv, [], [targetos=_OU_TARGET_OS_GENUNIX]) fi AC_DEFINE_UNQUOTED(_OU_TARGET_OS, $targetos, [Target OS setting for OU Library]) fi AC_CONFIG_SUBDIRS([ou]) AM_CONDITIONAL(ENABLE_OU, test x$use_ou = xyes) if test x$threading_intf = xyes then AC_ARG_ENABLE([builtin-threading-impl], AS_HELP_STRING([--enable-builtin-threading-impl], [include built-in multithreaded threading implementation (still must be created and assigned to be used)] ), use_builtin_threading_impl=$enableval,use_builtin_threading_impl=no) if test x$use_builtin_threading_impl = xyes then AC_DEFINE([dBUILTIN_THREADING_IMPL_ENABLED],[1],[Built-in multithreaded threading implementation included]) fi else AC_DEFINE([dTHREADING_INTF_DISABLED],[1],[Threading interface is disabled]) use_builtin_threading_impl=no fi col_cylinder_cylinder=none col_box_cylinder=default col_capsule_cylinder=none col_convex_box=none col_convex_capsule=none col_convex_cylinder=none col_convex_sphere=default col_convex_convex=default use_libccd=no libccd_all=no AC_ARG_ENABLE(libccd, AS_HELP_STRING([--enable-libccd], [enable all libccd colliders (except box-cylinder)]), libccd_all=$enableval) if test x$libccd_all = xyes then col_cylinder_cylinder=libccd col_capsule_cylinder=libccd col_convex_box=libccd col_convex_capsule=libccd col_convex_cylinder=libccd col_convex_sphere=libccd col_convex_convex=libccd use_libccd=yes fi AC_ARG_WITH([cylinder-cylinder], AS_HELP_STRING([--with-cylinder-cylinder=@<:@none,libccd@:>@], [use specific collider for cylinder-cylinder]), col_cylinder_cylinder=$withval) AC_ARG_WITH([box-cylinder], AS_HELP_STRING([--with-box-cylinder=@<:@default,libccd@:>@], [use specific collider for box-cylinder]), col_box_cylinder=$withval) AC_ARG_WITH([capsule-cylinder], AS_HELP_STRING([--with-capsule-cylinder=@<:@none,libccd@:>@], [use specific collider for capsule-cylinder]), col_capsule_cylinder=$withval) AC_ARG_WITH([convex-box], AS_HELP_STRING([--with-convex-box=@<:@none,libccd@:>@], [use specific collider for convex-box]), col_convex_box=$withval) AC_ARG_WITH([convex-capsule], AS_HELP_STRING([--with-convex-capsule=@<:@none,libccd@:>@], [use specific collider for convex-capsule]), col_convex_capsule=$withval) AC_ARG_WITH([convex-cylinder], AS_HELP_STRING([--with-convex-cylinder=@<:@none,libccd@:>@], [use specific collider for convex-cylinder]), col_convex_cylinder=$withval) AC_ARG_WITH([convex-sphere], AS_HELP_STRING([--with-convex-sphere=@<:@default,libccd@:>@], [use specific collider for convex-sphere]), col_convex_sphere=$withval) AC_ARG_WITH([convex-convex], AS_HELP_STRING([--with-convex-convex=@<:@default,libccd@:>@], [use specific collider for convex-convex]), col_convex_convex=$withval) if test x$col_cylinder_cylinder = xlibccd -o \ x$col_box_cylinder = xlibccd -o \ x$col_capsule_cylinder = xlibccd -o \ x$col_convex_box = xlibccd -o \ x$col_convex_capsule = libccd -o \ x$col_convex_cylinder = xlibccd -o \ x$col_convex_sphere = libccd -o \ x$col_convex_convex = libccd then use_libccd=yes fi libccd_source=internal AC_ARG_WITH(libccd, [AS_HELP_STRING([--with-libccd=@<:@internal|system@:>@], [use the specified libccd @<:@default=system@:>@])], [libccd_source=$withval], [libccd_source=system]) if test x$use_libccd = xyes then if test x$libccd_source = xsystem then PKG_CHECK_MODULES(CCD, ccd, ,[libccd_source=internal]) fi fi if test x$use_libccd = xyes then if test x$libccd_source = xinternal then AC_CONFIG_SUBDIRS([libccd]) fi fi AM_CONDITIONAL(LIBCCD, test x$use_libccd != xno) AM_CONDITIONAL(LIBCCD_INTERNAL, test x$libccd_source = xinternal) AM_CONDITIONAL(LIBCCD_BOX_CYL, test x$col_box_cylinder = xlibccd) AM_CONDITIONAL(LIBCCD_CYL_CYL, test x$col_cylinder_cylinder = xlibccd) AM_CONDITIONAL(LIBCCD_CAP_CYL, test x$col_capsule_cylinder = xlibccd) AM_CONDITIONAL(LIBCCD_CONVEX_BOX, test x$col_convex_box = xlibccd) AM_CONDITIONAL(LIBCCD_CONVEX_CAP, test x$col_convex_capsule = xlibccd) AM_CONDITIONAL(LIBCCD_CONVEX_CYL, test x$col_convex_cylinder = xlibccd) AM_CONDITIONAL(LIBCCD_CONVEX_SPHERE, test x$col_convex_sphere = xlibccd) AM_CONDITIONAL(LIBCCD_CONVEX_CONVEX, test x$col_convex_convex = xlibccd) AC_ARG_ENABLE([asserts], AS_HELP_STRING([--disable-asserts], [disables debug error checking]), asserts=$enableval,asserts=yes) if test x$asserts = xno then CPPFLAGS="$CPPFLAGS -DdNODEBUG" if test x$use_ou = xyes then CPPFLAGS="$CPPFLAGS -DNDEBUG" fi fi dnl include found system headers into config.h AH_TOP([ #ifndef ODE_CONFIG_H #define ODE_CONFIG_H ]) AH_BOTTOM([ #ifdef HAVE_ALLOCA_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_STDINT_H #include #endif #ifdef HAVE_INTTYPES_H #include #endif /* an integer type that we can safely cast a pointer to and * from without loss of bits. */ typedef uintptr_t intP; #ifdef dSINGLE #define dEpsilon FLT_EPSILON #else #define dEpsilon DBL_EPSILON #endif #include "typedefs.h" #endif /* #define ODE_CONFIG_H */ ]) dnl Finally write our Makefiles AC_CONFIG_FILES([ Makefile drawstuff/Makefile drawstuff/src/Makefile drawstuff/dstest/Makefile include/Makefile include/drawstuff/Makefile include/ode/Makefile include/ode/version.h include/ode/precision.h ode/Makefile ode/doc/Doxyfile ode/doc/Makefile ode/src/Makefile ode/src/joints/Makefile ode/demo/Makefile OPCODE/Makefile OPCODE/Ice/Makefile GIMPACT/Makefile GIMPACT/include/Makefile GIMPACT/include/GIMPACT/Makefile GIMPACT/src/Makefile tests/Makefile tests/joints/Makefile tests/UnitTest++/Makefile tests/UnitTest++/src/Makefile tests/UnitTest++/src/Posix/Makefile tests/UnitTest++/src/Win32/Makefile ode-config ode.pc ]) AC_OUTPUT chmod +x ode-config BUILDDIR=`pwd` dnl Print some useful information echo "Configuration:" echo " Build system type: $build" echo " Host system type: $host" echo " Use double precision: $usedouble" echo " Use drawstuff: $drawstuff" echo " Demos enabled: $enable_demos" echo " Use OPCODE: $opcode" echo " Use GIMPACT: $gimpact" echo " Use libccd: $use_libccd" if test x$use_libccd = xyes then echo " libccd source: $libccd_source" fi echo " Custom colliders:" echo " cylinder-cylinder: $col_cylinder_cylinder" echo " box-cylinder: $col_box_cylinder" echo " capsule-cylinder: $col_capsule_cylinder" echo " convex-box: $col_convex_box" echo " convex-capsule: $col_convex_capsule" echo " convex-cylinder: $col_convex_cylinder" echo " convex-sphere: $col_convex_sphere" echo " convex-convex: $col_convex_convex" echo " Is target a Pentium: $pentium" echo " Is target x86-64: $cpu64" echo " Use old opcode trimesh collider: $old_trimesh" echo " TLS for global caches: $use_ou_tls" echo " Threading intf enabled: $threading_intf" echo " Built-in threading included: $use_builtin_threading_impl" echo " Enable debug error check: $asserts" echo " Headers will be installed in $includedir/ode" echo " Libraries will be installed in $libdir" echo " Building in directory $BUILDDIR" ode-0.14/contrib/0000775000000000000000000000000012635012023012337 5ustar rootrootode-0.14/contrib/BreakableJoints/0000775000000000000000000000000012635012023015376 5ustar rootrootode-0.14/contrib/BreakableJoints/README.txt0000644000000000000000000001101412635011627017100 0ustar rootrootBreakable Joints ================================================================================ Description: This is a small addition to ODE that makes joints breakable. Breakable means that if a force on a joint is to high it wil break. I have included a modified version of test_buggy.cpp (test_breakable.cpp) so you can see it for your self. Just drive your buggy into an obstacle and enjoy! ================================================================================ Installation instructions: - copy joint.h, joint.cpp, ode.cpp and step.cpp to the ode/src/ directory - copy common.h and object.h to the include/ directory - copy test_breakable.cpp to the ode/test/ directory - add test_breakable.cpp to the ODE_TEST_SRC_CPP object in the makefile. - make ode-lib - make ode-test You can also use the diffs. The above files will quickly go out of sync with the rest of ODE but the diffs wil remain valid longer. ================================================================================ Functions: dJointSetBreakable (dJointID joint, int b) If b is 1 the joint is made breakable. If b is 0 the joint is made unbreakable. void dJointSetBreakCallback (dJointID joint, dJointBreakCallback *callbackFunc) Sets the callback function for this joint. If a funtion is set it will be called if the joint is broken but before it is actually detached or deleted. void dJointSetBreakMode (dJointID joint, int mode) Use this functions to set some flags. These flags can be ORred ( | ) together; ie. dJointSetBreakMode (someJoint, dJOINT_BREAK_AT_B1_FORCE|dJOINT_DELETE_ON_BREAK) dJOINT_DELETE_ON_BREAK - If the joint breaks it wil be deleted. dJOINT_BREAK_AT_B1_FORCE - If the force on body 1 is to high the joint will break dJOINT_BREAK_AT_B1_TORQUE - If the torque on body 1 is to high the joint will break dJOINT_BREAK_AT_B2_FORCE - If the force on body 2 is to high the joint will break dJOINT_BREAK_AT_B2_TORQUE - If the torque on body 2 is to high the joint will break void dJointSetBreakForce (dJointID joint, int body, dReal x, dReal y, dReal z) With this function you can set the maximum force for a body connected to this joint. A value of 0 for body means body 1, 1 means body 2. The force is relative to the bodies rotation. void dJointSetBreakTorque (dJointID joint, int body, dReal x, dReal y, dReal z) With this function you can set the maximum torque for a body connected to this joint. A value of 0 for body means body 1, 1 means body 2. The torque is relative to the bodies rotation. int dJointIsBreakable (dJointID joint) Returns 1 if this joint is breakable, 0 otherwise. int dJointGetBreakMode (dJointID joint) Returns the breakmode flag. void dJointGetBreakForce (dJointID joint, int body, dReal *force) Returns the force at what this joint will break. A value of 0 for body means body 1, 1 means body 2. force must have enough space for 3 dReal values. void dJointGetBreakTorque (dJointID joint, int body, dReal *torque) Returns the torque at what this joint will break. A value of 0 for body means body 1, 1 means body 2. force must have enough space for 3 dReal values. ================================================================================ The callback function is defined like this (in common.h): void dJointBreakCallback (dJointID); ================================================================================ Problems, known bugs & other issues: - If the timestep is very small then joints get a lot weaker. They can even fall apart! - I have tested all this with the latest checkout from CVS (at the time of writing ofcourse). I haven't tested it with earlier versions of ODE. - I have modified the code that fills the jointfeedback struct. I haven't tested if it still works. - I'm not sure if the forces are really relative to the connected bodies. - There are some memory leaks in the test_breakable.cpp example. ================================================================================ Bugfixes and changes: 09/08/2003 - I fixed a bug when there where 0 joints in the simulation 06/12/2003 - dJointGetBreakMode() added, by vadim_mcagon@hotmail.com 11/03/2004 - Updated files to work with latest CVS checkout. - Added support for dWorldStepFast1() - Added separate test_breakable.cpp example. - Updated the code that breaks and destroys a joint. ================================================================================ Send me an e-mail if you have any suggestions, ideas, bugs, bug-fixes, anything! e-mail: roelvandijk@home.nl Roel van Dijk - 11/03/2004 ode-0.14/contrib/BreakableJoints/common.h0000644000000000000000000002372312635011627017055 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_COMMON_H_ #define _ODE_COMMON_H_ #include #include #ifdef __cplusplus extern "C" { #endif /* configuration stuff */ /* the efficient alignment. most platforms align data structures to some * number of bytes, but this is not always the most efficient alignment. * for example, many x86 compilers align to 4 bytes, but on a pentium it * is important to align doubles to 8 byte boundaries (for speed), and * the 4 floats in a SIMD register to 16 byte boundaries. many other * platforms have similar behavior. setting a larger alignment can waste * a (very) small amount of memory. NOTE: this number must be a power of * two. this is set to 16 by default. */ #define EFFICIENT_ALIGNMENT 16 /* constants */ /* pi and 1/sqrt(2) are defined here if necessary because they don't get * defined in on some platforms (like MS-Windows) */ #ifndef M_PI #define M_PI REAL(3.1415926535897932384626433832795029) #endif #ifndef M_SQRT1_2 #define M_SQRT1_2 REAL(0.7071067811865475244008443621048490) #endif /* debugging: * IASSERT is an internal assertion, i.e. a consistency check. if it fails * we want to know where. * UASSERT is a user assertion, i.e. if it fails a nice error message * should be printed for the user. * AASSERT is an arguments assertion, i.e. if it fails "bad argument(s)" * is printed. * DEBUGMSG just prints out a message */ #ifndef dNODEBUG #ifdef __GNUC__ #define dIASSERT(a) if (!(a)) dDebug (d_ERR_IASSERT, \ "assertion \"" #a "\" failed in %s() [%s]",__FUNCTION__,__FILE__); #define dUASSERT(a,msg) if (!(a)) dDebug (d_ERR_UASSERT, \ msg " in %s()", __FUNCTION__); #define dDEBUGMSG(msg) dMessage (d_ERR_UASSERT, \ msg " in %s()", __FUNCTION__); #else #define dIASSERT(a) if (!(a)) dDebug (d_ERR_IASSERT, \ "assertion \"" #a "\" failed in %s:%d",__FILE__,__LINE__); #define dUASSERT(a,msg) if (!(a)) dDebug (d_ERR_UASSERT, \ msg " (%s:%d)", __FILE__,__LINE__); #define dDEBUGMSG(msg) dMessage (d_ERR_UASSERT, \ msg " (%s:%d)", __FILE__,__LINE__); #endif #else #define dIASSERT(a) ; #define dUASSERT(a,msg) ; #define dDEBUGMSG(msg) ; #endif #define dAASSERT(a) dUASSERT(a,"Bad argument(s)") /* floating point data type, vector, matrix and quaternion types */ #if defined(dSINGLE) typedef float dReal; #elif defined(dDOUBLE) typedef double dReal; #else #error You must #define dSINGLE or dDOUBLE #endif /* round an integer up to a multiple of 4, except that 0 and 1 are unmodified * (used to compute matrix leading dimensions) */ #define dPAD(a) (((a) > 1) ? ((((a)-1)|3)+1) : (a)) /* these types are mainly just used in headers */ typedef dReal dVector3[4]; typedef dReal dVector4[4]; typedef dReal dMatrix3[4*3]; typedef dReal dMatrix4[4*4]; typedef dReal dMatrix6[8*6]; typedef dReal dQuaternion[4]; /* precision dependent scalar math functions */ #if defined(dSINGLE) #define REAL(x) (x ## f) /* form a constant */ #define dRecip(x) ((float)(1.0f/(x))) /* reciprocal */ #define dSqrt(x) ((float)sqrt(x)) /* square root */ #define dRecipSqrt(x) ((float)(1.0f/sqrt(x))) /* reciprocal square root */ #define dSin(x) ((float)sin(x)) /* sine */ #define dCos(x) ((float)cos(x)) /* cosine */ #define dFabs(x) ((float)fabs(x)) /* absolute value */ #define dAtan2(y,x) ((float)atan2((y),(x))) /* arc tangent with 2 args */ #elif defined(dDOUBLE) #define REAL(x) (x) #define dRecip(x) (1.0/(x)) #define dSqrt(x) sqrt(x) #define dRecipSqrt(x) (1.0/sqrt(x)) #define dSin(x) sin(x) #define dCos(x) cos(x) #define dFabs(x) fabs(x) #define dAtan2(y,x) atan2((y),(x)) #else #error You must #define dSINGLE or dDOUBLE #endif /* utility */ /* round something up to be a multiple of the EFFICIENT_ALIGNMENT */ #define dEFFICIENT_SIZE(x) ((((x)-1)|(EFFICIENT_ALIGNMENT-1))+1) /* alloca aligned to the EFFICIENT_ALIGNMENT. note that this can waste * up to 15 bytes per allocation, depending on what alloca() returns. */ #define dALLOCA16(n) \ ((char*)dEFFICIENT_SIZE(((int)(alloca((n)+(EFFICIENT_ALIGNMENT-1)))))) /* internal object types (all prefixed with `dx') */ struct dxWorld; /* dynamics world */ struct dxSpace; /* collision space */ struct dxBody; /* rigid body (dynamics object) */ struct dxGeom; /* geometry (collision object) */ struct dxJoint; struct dxJointNode; struct dxJointGroup; typedef struct dxWorld *dWorldID; typedef struct dxSpace *dSpaceID; typedef struct dxBody *dBodyID; typedef struct dxGeom *dGeomID; typedef struct dxJoint *dJointID; typedef struct dxJointGroup *dJointGroupID; /* error numbers */ enum { d_ERR_UNKNOWN = 0, /* unknown error */ d_ERR_IASSERT, /* internal assertion failed */ d_ERR_UASSERT, /* user assertion failed */ d_ERR_LCP /* user assertion failed */ }; /* joint type numbers */ enum { dJointTypeNone = 0, /* or "unknown" */ dJointTypeBall, dJointTypeHinge, dJointTypeSlider, dJointTypeContact, dJointTypeUniversal, dJointTypeHinge2, dJointTypeFixed, dJointTypeNull, dJointTypeAMotor }; /******************** breakable joint contribution ***********************/ /* joint break callback function */ typedef void dJointBreakCallback (dJointID joint); /* joint break modes */ enum { // if this flag is set, the joint wil break dJOINT_BROKEN = 0x0001, // if this flag is set, the joint wil be deleted when it breaks dJOINT_DELETE_ON_BREAK = 0x0002, // if this flag is set, the joint can break at a certain force on body 1 dJOINT_BREAK_AT_B1_FORCE = 0x0004, // if this flag is set, the joint can break at a certain torque on body 1 dJOINT_BREAK_AT_B1_TORQUE = 0x0008, // if this flag is set, the joint can break at a certain force on body 2 dJOINT_BREAK_AT_B2_FORCE = 0x0010, // if this flag is set, the joint can break at a certain torque on body 2 dJOINT_BREAK_AT_B2_TORQUE = 0x0020 }; /*************************************************************************/ /* an alternative way of setting joint parameters, using joint parameter * structures and member constants. we don't actually do this yet. */ /* typedef struct dLimot { int mode; dReal lostop, histop; dReal vel, fmax; dReal fudge_factor; dReal bounce, soft; dReal suspension_erp, suspension_cfm; } dLimot; enum { dLimotLoStop = 0x0001, dLimotHiStop = 0x0002, dLimotVel = 0x0004, dLimotFMax = 0x0008, dLimotFudgeFactor = 0x0010, dLimotBounce = 0x0020, dLimotSoft = 0x0040 }; */ /* standard joint parameter names. why are these here? - because we don't want * to include all the joint function definitions in joint.cpp. hmmmm. * MSVC complains if we call D_ALL_PARAM_NAMES_X with a blank second argument, * which is why we have the D_ALL_PARAM_NAMES macro as well. please copy and * paste between these two. */ #define D_ALL_PARAM_NAMES(start) \ /* parameters for limits and motors */ \ dParamLoStop = start, \ dParamHiStop, \ dParamVel, \ dParamFMax, \ dParamFudgeFactor, \ dParamBounce, \ dParamCFM, \ dParamStopERP, \ dParamStopCFM, \ /* parameters for suspension */ \ dParamSuspensionERP, \ dParamSuspensionCFM, #define D_ALL_PARAM_NAMES_X(start,x) \ /* parameters for limits and motors */ \ dParamLoStop ## x = start, \ dParamHiStop ## x, \ dParamVel ## x, \ dParamFMax ## x, \ dParamFudgeFactor ## x, \ dParamBounce ## x, \ dParamCFM ## x, \ dParamStopERP ## x, \ dParamStopCFM ## x, \ /* parameters for suspension */ \ dParamSuspensionERP ## x, \ dParamSuspensionCFM ## x, enum { D_ALL_PARAM_NAMES(0) D_ALL_PARAM_NAMES_X(0x100,2) D_ALL_PARAM_NAMES_X(0x200,3) /* add a multiple of this constant to the basic parameter numbers to get * the parameters for the second, third etc axes. */ dParamGroup=0x100 }; /* angular motor mode numbers */ enum{ dAMotorUser = 0, dAMotorEuler = 1 }; /* joint force feedback information */ typedef struct dJointFeedback { dVector3 f1; /* force applied to body 1 */ dVector3 t1; /* torque applied to body 1 */ dVector3 f2; /* force applied to body 2 */ dVector3 t2; /* torque applied to body 2 */ } dJointFeedback; /* private functions that must be implemented by the collision library: * (1) indicate that a geom has moved, (2) get the next geom in a body list. * these functions are called whenever the position of geoms connected to a * body have changed, e.g. with dBodySetPosition(), dBodySetRotation(), or * when the ODE step function updates the body state. */ void dGeomMoved (dGeomID); dGeomID dGeomGetBodyNext (dGeomID); #ifdef __cplusplus } #endif #endif ode-0.14/contrib/BreakableJoints/diff/0000775000000000000000000000000012635012023016306 5ustar rootrootode-0.14/contrib/BreakableJoints/diff/common.h.diff0000644000000000000000000000170712635011627020672 0ustar rootroot208,227d207 < /******************** breakable joint contribution ***********************/ < /* joint break callback function */ < typedef void dJointBreakCallback (dJointID joint); < < /* joint break modes */ < enum { < // if this flag is set, the joint wil break < dJOINT_BROKEN = 0x0001, < // if this flag is set, the joint wil be deleted when it breaks < dJOINT_DELETE_ON_BREAK = 0x0002, < // if this flag is set, the joint can break at a certain force on body 1 < dJOINT_BREAK_AT_B1_FORCE = 0x0004, < // if this flag is set, the joint can break at a certain torque on body 1 < dJOINT_BREAK_AT_B1_TORQUE = 0x0008, < // if this flag is set, the joint can break at a certain force on body 2 < dJOINT_BREAK_AT_B2_FORCE = 0x0010, < // if this flag is set, the joint can break at a certain torque on body 2 < dJOINT_BREAK_AT_B2_TORQUE = 0x0020 < }; < /*************************************************************************/ ode-0.14/contrib/BreakableJoints/diff/joint.cpp.diff0000644000000000000000000001035312635011627021055 0ustar rootroot2659,2804d2658 < < /******************** breakable joint contribution ***********************/ < extern "C" void dJointSetBreakable (dxJoint *joint, int b) { < dAASSERT(joint); < if (b) { < // we want this joint to be breakable but we must first check if it < // was already breakable < if (!joint->breakInfo) { < // allocate a dxJointBreakInfo struct < joint->breakInfo = new dxJointBreakInfo; < joint->breakInfo->flags = 0; < for (int i = 0; i < 3; i++) { < joint->breakInfo->b1MaxF[0] = 0; < joint->breakInfo->b1MaxT[0] = 0; < joint->breakInfo->b2MaxF[0] = 0; < joint->breakInfo->b2MaxT[0] = 0; < } < joint->breakInfo->callback = 0; < } < else { < // the joint was already breakable < return; < } < } < else { < // we want this joint to be unbreakable mut we must first check if < // it is alreay unbreakable < if (joint->breakInfo) { < // deallocate the dxJointBreakInfo struct < delete joint->breakInfo; < joint->breakInfo = 0; < } < else { < // the joint was already unbreakable < return; < } < } < } < < extern "C" void dJointSetBreakCallback (dxJoint *joint, dJointBreakCallback *callbackFunc) { < dAASSERT(joint); < # ifndef dNODEBUG < // only works for a breakable joint < if (!joint->breakInfo) { < dDebug (0, "dJointSetBreakCallback called on unbreakable joint"); < } < # endif < joint->breakInfo->callback = callbackFunc; < } < < extern "C" void dJointSetBreakMode (dxJoint *joint, int mode) { < dAASSERT(joint); < # ifndef dNODEBUG < // only works for a breakable joint < if (!joint->breakInfo) { < dDebug (0, "dJointSetBreakMode called on unbreakable joint"); < } < # endif < joint->breakInfo->flags = mode; < } < < extern "C" int dJointGetBreakMode (dxJoint *joint) { < dAASSERT(joint); < # ifndef dNODEBUG < // only works for a breakable joint < if (!joint->breakInfo) { < dDebug (0, "dJointGetBreakMode called on unbreakable joint"); < } < # endif < return joint->breakInfo->flags; < } < < extern "C" void dJointSetBreakForce (dxJoint *joint, int body, dReal x, dReal y, dReal z) { < dAASSERT(joint); < # ifndef dNODEBUG < // only works for a breakable joint < if (!joint->breakInfo) { < dDebug (0, "dJointSetBreakForce called on unbreakable joint"); < } < # endif < if (body) { < joint->breakInfo->b2MaxF[0] = x; < joint->breakInfo->b2MaxF[1] = y; < joint->breakInfo->b2MaxF[2] = z; < } < else { < joint->breakInfo->b1MaxF[0] = x; < joint->breakInfo->b1MaxF[1] = y; < joint->breakInfo->b1MaxF[2] = z; < } < } < < extern "C" void dJointSetBreakTorque (dxJoint *joint, int body, dReal x, dReal y, dReal z) { < dAASSERT(joint); < # ifndef dNODEBUG < // only works for a breakable joint < if (!joint->breakInfo) { < dDebug (0, "dJointSetBreakTorque called on unbreakable joint"); < } < # endif < if (body) { < joint->breakInfo->b2MaxT[0] = x; < joint->breakInfo->b2MaxT[1] = y; < joint->breakInfo->b2MaxT[2] = z; < } < else { < joint->breakInfo->b1MaxT[0] = x; < joint->breakInfo->b1MaxT[1] = y; < joint->breakInfo->b1MaxT[2] = z; < } < } < < extern "C" int dJointIsBreakable (dxJoint *joint) { < dAASSERT(joint); < return joint->breakInfo != 0; < } < < extern "C" void dJointGetBreakForce (dxJoint *joint, int body, dReal *force) { < dAASSERT(joint); < # ifndef dNODEBUG < // only works for a breakable joint < if (!joint->breakInfo) { < dDebug (0, "dJointGetBreakForce called on unbreakable joint"); < } < # endif < if (body) < for (int i=0; i<3; i++) force[i]=joint->breakInfo->b2MaxF[i]; < else < for (int i=0; i<3; i++) force[i]=joint->breakInfo->b1MaxF[i]; < } < < extern "C" void dJointGetBreakTorque (dxJoint *joint, int body, dReal *torque) { < dAASSERT(joint); < # ifndef dNODEBUG < // only works for a breakable joint < if (!joint->breakInfo) { < dDebug (0, "dJointGetBreakTorque called on unbreakable joint"); < } < # endif < if (body) < for (int i=0; i<3; i++) torque[i]=joint->breakInfo->b2MaxT[i]; < else < for (int i=0; i<3; i++) torque[i]=joint->breakInfo->b1MaxT[i]; < } < /*************************************************************************/ < \ No newline at end of file ode-0.14/contrib/BreakableJoints/diff/joint.h.diff0000644000000000000000000000144412635011627020523 0ustar rootroot61,70d60 < /******************** breakable joint contribution ***********************/ < struct dxJointBreakInfo : public dBase { < int flags; < dReal b1MaxF[3]; // maximum force on body 1 < dReal b1MaxT[3]; // maximum torque on body 1 < dReal b2MaxF[3]; // maximum force on body 2 < dReal b2MaxT[3]; // maximum torque on body 2 < dJointBreakCallback *callback; // function that is called when this joint breaks < }; < /*************************************************************************/ 135,140d124 < < /******************** breakable joint contribution ***********************/ < // optional break info structure. if this is not NULL the the joint is < // breakable. < dxJointBreakInfo *breakInfo; < /*************************************************************************/ ode-0.14/contrib/BreakableJoints/diff/objects.h.diff0000644000000000000000000000126712635011627021034 0ustar rootroot168,179d167 < /******************** breakable joint contribution ***********************/ < void dJointSetBreakable (dJointID, int b); < void dJointSetBreakCallback (dJointID, dJointBreakCallback *callbackFunc); < void dJointSetBreakMode (dJointID, int mode); < int dJointGetBreakMode (dJointID); < void dJointSetBreakForce (dJointID, int body, dReal x, dReal y, dReal z); < void dJointSetBreakTorque (dJointID, int body, dReal x, dReal y, dReal z); < int dJointIsBreakable (dJointID); < void dJointGetBreakForce (dJointID, int body, dReal *force); < void dJointGetBreakTorque (dJointID, int body, dReal *torque); < /*************************************************************************/ < ode-0.14/contrib/BreakableJoints/diff/ode.cpp.diff0000644000000000000000000000231012635011627020473 0ustar rootroot212,230d211 < /******************** breakable joint contribution ***********************/ < dxJoint* nextJ; < if (!world->firstjoint) < nextJ = 0; < else < nextJ = (dxJoint*)world->firstjoint->next; < for (j=world->firstjoint; j; j=nextJ) { < nextJ = (dxJoint*)j->next; < // check if joint is breakable and broken < if (j->breakInfo && j->breakInfo->flags & dJOINT_BROKEN) { < // detach (break) the joint < dJointAttach (j, 0, 0); < // call the callback function if it is set < if (j->breakInfo->callback) j->breakInfo->callback (j); < // finally destroy the joint if the dJOINT_DELETE_ON_BREAK is set < if (j->breakInfo->flags & dJOINT_DELETE_ON_BREAK) dJointDestroy (j); < } < } < /*************************************************************************/ 931,933d911 < /******************** breakable joint contribution ***********************/ < j->breakInfo = 0; < /*************************************************************************/ 1011,1013d988 < /******************** breakable joint contribution ***********************/ < if (j->breakInfo) delete j->breakInfo; < /*************************************************************************/ ode-0.14/contrib/BreakableJoints/diff/step.cpp.diff0000644000000000000000000001155012635011627020705 0ustar rootroot966,1066c966,989 < /******************** breakable joint contribution ***********************/ < // this saves us a few dereferences < dxJointBreakInfo *jBI = joint[i]->breakInfo; < // we need joint feedback if the joint is breakable or if the user < // requested feedback. < if (jBI||fb) { < // we need feedback on the amount of force that this joint is < // applying to the bodies. we use a slightly slower computation < // that splits out the force components and puts them in the < // feedback structure. < dJointFeedback temp_fb; // temporary storage for joint feedback < dReal data1[8],data2[8]; < Multiply1_8q1 (data1, JJ, lambda+ofs[i], info[i].m); < dReal *cf1 = cforce + 8*b1->tag; < cf1[0] += (temp_fb.f1[0] = data1[0]); < cf1[1] += (temp_fb.f1[1] = data1[1]); < cf1[2] += (temp_fb.f1[2] = data1[2]); < cf1[4] += (temp_fb.t1[0] = data1[4]); < cf1[5] += (temp_fb.t1[1] = data1[5]); < cf1[6] += (temp_fb.t1[2] = data1[6]); < if (b2) { < Multiply1_8q1 (data2, JJ + 8*info[i].m, lambda+ofs[i], info[i].m); < dReal *cf2 = cforce + 8*b2->tag; < cf2[0] += (temp_fb.f2[0] = data2[0]); < cf2[1] += (temp_fb.f2[1] = data2[1]); < cf2[2] += (temp_fb.f2[2] = data2[2]); < cf2[4] += (temp_fb.t2[0] = data2[4]); < cf2[5] += (temp_fb.t2[1] = data2[5]); < cf2[6] += (temp_fb.t2[2] = data2[6]); < } < // if the user requested so we must copy the feedback information to < // the feedback struct that the user suplied. < if (fb) { < // copy temp_fb to fb < fb->f1[0] = temp_fb.f1[0]; < fb->f1[1] = temp_fb.f1[1]; < fb->f1[2] = temp_fb.f1[2]; < fb->t1[0] = temp_fb.t1[0]; < fb->t1[1] = temp_fb.t1[1]; < fb->t1[2] = temp_fb.t1[2]; < if (b2) { < fb->f2[0] = temp_fb.f2[0]; < fb->f2[1] = temp_fb.f2[1]; < fb->f2[2] = temp_fb.f2[2]; < fb->t2[0] = temp_fb.t2[0]; < fb->t2[1] = temp_fb.t2[1]; < fb->t2[2] = temp_fb.t2[2]; < } < } < // if the joint is breakable we need to check the breaking conditions < if (jBI) { < dReal relCF1[3]; < dReal relCT1[3]; < // multiply the force and torque vectors by the rotation matrix of body 1 < dMULTIPLY1_331 (&relCF1[0],b1->R,&temp_fb.f1[0]); < dMULTIPLY1_331 (&relCT1[0],b1->R,&temp_fb.t1[0]); < if (jBI->flags & dJOINT_BREAK_AT_B1_FORCE) { < // check if the force is to high < for (int i = 0; i < 3; i++) { < if (relCF1[i] > jBI->b1MaxF[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < if (jBI->flags & dJOINT_BREAK_AT_B1_TORQUE) { < // check if the torque is to high < for (int i = 0; i < 3; i++) { < if (relCT1[i] > jBI->b1MaxT[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < if (b2) { < dReal relCF2[3]; < dReal relCT2[3]; < // multiply the force and torque vectors by the rotation matrix of body 2 < dMULTIPLY1_331 (&relCF2[0],b2->R,&temp_fb.f2[0]); < dMULTIPLY1_331 (&relCT2[0],b2->R,&temp_fb.t2[0]); < if (jBI->flags & dJOINT_BREAK_AT_B2_FORCE) { < // check if the force is to high < for (int i = 0; i < 3; i++) { < if (relCF2[i] > jBI->b2MaxF[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < if (jBI->flags & dJOINT_BREAK_AT_B2_TORQUE) { < // check if the torque is to high < for (int i = 0; i < 3; i++) { < if (relCT2[i] > jBI->b2MaxT[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < } < doneCheckingBreaks: < ; --- > if (fb) { > // the user has requested feedback on the amount of force that this > // joint is applying to the bodies. we use a slightly slower > // computation that splits out the force components and puts them > // in the feedback structure. > dReal data1[8],data2[8]; > Multiply1_8q1 (data1, JJ, lambda+ofs[i], info[i].m); > dReal *cf1 = cforce + 8*b1->tag; > cf1[0] += (fb->f1[0] = data1[0]); > cf1[1] += (fb->f1[1] = data1[1]); > cf1[2] += (fb->f1[2] = data1[2]); > cf1[4] += (fb->t1[0] = data1[4]); > cf1[5] += (fb->t1[1] = data1[5]); > cf1[6] += (fb->t1[2] = data1[6]); > if (b2){ > Multiply1_8q1 (data2, JJ + 8*info[i].m, lambda+ofs[i], info[i].m); > dReal *cf2 = cforce + 8*b2->tag; > cf2[0] += (fb->f2[0] = data2[0]); > cf2[1] += (fb->f2[1] = data2[1]); > cf2[2] += (fb->f2[2] = data2[2]); > cf2[4] += (fb->t2[0] = data2[4]); > cf2[5] += (fb->t2[1] = data2[5]); > cf2[6] += (fb->t2[2] = data2[6]); > } 1068,1069d990 < } < /*************************************************************************/ ode-0.14/contrib/BreakableJoints/diff/stepfast.cpp.diff0000644000000000000000000001176712635011627021575 0ustar rootroot587,598c587,593 < /******************** breakable joint contribution ***********************/ < // this saves us a few dereferences < dxJointBreakInfo *jBI = joint->breakInfo; < // we need joint feedback if the joint is breakable or if the user < // requested feedback. < if (jBI||fb) { < // we need feedback on the amount of force that this joint is < // applying to the bodies. we use a slightly slower computation < // that splits out the force components and puts them in the < // feedback structure. < dJointFeedback temp_fb; // temporary storage for joint feedback < dReal data1[8],data2[8]; --- > if (fb) > { > // the user has requested feedback on the amount of force that this > // joint is applying to the bodies. we use a slightly slower > // computation that splits out the force components and puts them > // in the feedback structure. > dReal data1[8], data2[8]; 603,608c598,603 < cf1[0] = (temp_fb.f1[0] = data1[0]); < cf1[1] = (temp_fb.f1[1] = data1[1]); < cf1[2] = (temp_fb.f1[2] = data1[2]); < cf1[4] = (temp_fb.t1[0] = data1[4]); < cf1[5] = (temp_fb.t1[1] = data1[5]); < cf1[6] = (temp_fb.t1[2] = data1[6]); --- > cf1[0] = (fb->f1[0] = data1[0]); > cf1[1] = (fb->f1[1] = data1[1]); > cf1[2] = (fb->f1[2] = data1[2]); > cf1[4] = (fb->t1[0] = data1[4]); > cf1[5] = (fb->t1[1] = data1[5]); > cf1[6] = (fb->t1[2] = data1[6]); 614,691c609,614 < cf2[0] = (temp_fb.f2[0] = data2[0]); < cf2[1] = (temp_fb.f2[1] = data2[1]); < cf2[2] = (temp_fb.f2[2] = data2[2]); < cf2[4] = (temp_fb.t2[0] = data2[4]); < cf2[5] = (temp_fb.t2[1] = data2[5]); < cf2[6] = (temp_fb.t2[2] = data2[6]); < } < // if the user requested so we must copy the feedback information to < // the feedback struct that the user suplied. < if (fb) { < // copy temp_fb to fb < fb->f1[0] = temp_fb.f1[0]; < fb->f1[1] = temp_fb.f1[1]; < fb->f1[2] = temp_fb.f1[2]; < fb->t1[0] = temp_fb.t1[0]; < fb->t1[1] = temp_fb.t1[1]; < fb->t1[2] = temp_fb.t1[2]; < if (body[1]) { < fb->f2[0] = temp_fb.f2[0]; < fb->f2[1] = temp_fb.f2[1]; < fb->f2[2] = temp_fb.f2[2]; < fb->t2[0] = temp_fb.t2[0]; < fb->t2[1] = temp_fb.t2[1]; < fb->t2[2] = temp_fb.t2[2]; < } < } < // if the joint is breakable we need to check the breaking conditions < if (jBI) { < dReal relCF1[3]; < dReal relCT1[3]; < // multiply the force and torque vectors by the rotation matrix of body 1 < dMULTIPLY1_331 (&relCF1[0],body[0]->R,&temp_fb.f1[0]); < dMULTIPLY1_331 (&relCT1[0],body[0]->R,&temp_fb.t1[0]); < if (jBI->flags & dJOINT_BREAK_AT_B1_FORCE) { < // check if the force is to high < for (int i = 0; i < 3; i++) { < if (relCF1[i] > jBI->b1MaxF[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < if (jBI->flags & dJOINT_BREAK_AT_B1_TORQUE) { < // check if the torque is to high < for (int i = 0; i < 3; i++) { < if (relCT1[i] > jBI->b1MaxT[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < if (body[1]) { < dReal relCF2[3]; < dReal relCT2[3]; < // multiply the force and torque vectors by the rotation matrix of body 2 < dMULTIPLY1_331 (&relCF2[0],body[1]->R,&temp_fb.f2[0]); < dMULTIPLY1_331 (&relCT2[0],body[1]->R,&temp_fb.t2[0]); < if (jBI->flags & dJOINT_BREAK_AT_B2_FORCE) { < // check if the force is to high < for (int i = 0; i < 3; i++) { < if (relCF2[i] > jBI->b2MaxF[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < if (jBI->flags & dJOINT_BREAK_AT_B2_TORQUE) { < // check if the torque is to high < for (int i = 0; i < 3; i++) { < if (relCT2[i] > jBI->b2MaxT[i]) { < jBI->flags |= dJOINT_BROKEN; < goto doneCheckingBreaks; < } < } < } < } < doneCheckingBreaks: < ; --- > cf2[0] = (fb->f2[0] = data2[0]); > cf2[1] = (fb->f2[1] = data2[1]); > cf2[2] = (fb->f2[2] = data2[2]); > cf2[4] = (fb->t2[0] = data2[4]); > cf2[5] = (fb->t2[1] = data2[5]); > cf2[6] = (fb->t2[2] = data2[6]); 694d616 < /*************************************************************************/ 1178,1196d1099 < /******************** breakable joint contribution ***********************/ < dxJoint* nextJ; < if (!world->firstjoint) < nextJ = 0; < else < nextJ = (dxJoint*)world->firstjoint->next; < for (j=world->firstjoint; j; j=nextJ) { < nextJ = (dxJoint*)j->next; < // check if joint is breakable and broken < if (j->breakInfo && j->breakInfo->flags & dJOINT_BROKEN) { < // detach (break) the joint < dJointAttach (j, 0, 0); < // call the callback function if it is set < if (j->breakInfo->callback) j->breakInfo->callback (j); < // finally destroy the joint if the dJOINT_DELETE_ON_BREAK is set < if (j->breakInfo->flags & dJOINT_DELETE_ON_BREAK) dJointDestroy (j); < } < } < /*************************************************************************/ ode-0.14/contrib/BreakableJoints/diff/test_buggy.cpp.diff0000644000000000000000000000074012635011627022105 0ustar rootroot266,270d265 < < // breakable joints contribution < dJointSetBreakable (joint[i], 1); < dJointSetBreakMode (joint[i], dJOINT_BREAK_AT_FORCE); < dJointSetBreakForce (joint[i], 0.5); 298c293 < ground_box = dCreateBox (space,2,1.5,5); --- > ground_box = dCreateBox (space,2,1.5,1); 300,301c295,296 < dRFromAxisAndAngle (R,0,1,0,-0.85); < dGeomSetPosition (ground_box,5,0,-1); --- > dRFromAxisAndAngle (R,0,1,0,-0.15); > dGeomSetPosition (ground_box,2,0,-0.34); ode-0.14/contrib/BreakableJoints/joint.cpp0000644000000000000000000024334712635011627017251 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* design note: the general principle for giving a joint the option of connecting to the static environment (i.e. the absolute frame) is to check the second body (joint->node[1].body), and if it is zero then behave as if its body transform is the identity. */ #include #include #include #include "joint.h" //**************************************************************************** // externs extern "C" void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); extern "C" void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); //**************************************************************************** // utility // set three "ball-and-socket" rows in the constraint equation, and the // corresponding right hand side. static inline void setBall (dxJoint *joint, dxJoint::Info2 *info, dVector3 anchor1, dVector3 anchor2) { // anchor points in global coordinates with respect to body PORs. dVector3 a1,a2; int s = info->rowskip; // set jacobian info->J1l[0] = 1; info->J1l[s+1] = 1; info->J1l[2*s+2] = 1; dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1); dCROSSMAT (info->J1a,a1,s,-,+); if (joint->node[1].body) { info->J2l[0] = -1; info->J2l[s+1] = -1; info->J2l[2*s+2] = -1; dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2); dCROSSMAT (info->J2a,a2,s,+,-); } // set right hand side dReal k = info->fps * info->erp; if (joint->node[1].body) { for (int j=0; j<3; j++) { info->c[j] = k * (a2[j] + joint->node[1].body->pos[j] - a1[j] - joint->node[0].body->pos[j]); } } else { for (int j=0; j<3; j++) { info->c[j] = k * (anchor2[j] - a1[j] - joint->node[0].body->pos[j]); } } } // this is like setBall(), except that `axis' is a unit length vector // (in global coordinates) that should be used for the first jacobian // position row (the other two row vectors will be derived from this). // `erp1' is the erp value to use along the axis. static inline void setBall2 (dxJoint *joint, dxJoint::Info2 *info, dVector3 anchor1, dVector3 anchor2, dVector3 axis, dReal erp1) { // anchor points in global coordinates with respect to body PORs. dVector3 a1,a2; int i,s = info->rowskip; // get vectors normal to the axis. in setBall() axis,q1,q2 is [1 0 0], // [0 1 0] and [0 0 1], which makes everything much easier. dVector3 q1,q2; dPlaneSpace (axis,q1,q2); // set jacobian for (i=0; i<3; i++) info->J1l[i] = axis[i]; for (i=0; i<3; i++) info->J1l[s+i] = q1[i]; for (i=0; i<3; i++) info->J1l[2*s+i] = q2[i]; dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1); dCROSS (info->J1a,=,a1,axis); dCROSS (info->J1a+s,=,a1,q1); dCROSS (info->J1a+2*s,=,a1,q2); if (joint->node[1].body) { for (i=0; i<3; i++) info->J2l[i] = -axis[i]; for (i=0; i<3; i++) info->J2l[s+i] = -q1[i]; for (i=0; i<3; i++) info->J2l[2*s+i] = -q2[i]; dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2); dCROSS (info->J2a,= -,a2,axis); dCROSS (info->J2a+s,= -,a2,q1); dCROSS (info->J2a+2*s,= -,a2,q2); } // set right hand side - measure error along (axis,q1,q2) dReal k1 = info->fps * erp1; dReal k = info->fps * info->erp; for (i=0; i<3; i++) a1[i] += joint->node[0].body->pos[i]; if (joint->node[1].body) { for (i=0; i<3; i++) a2[i] += joint->node[1].body->pos[i]; info->c[0] = k1 * (dDOT(axis,a2) - dDOT(axis,a1)); info->c[1] = k * (dDOT(q1,a2) - dDOT(q1,a1)); info->c[2] = k * (dDOT(q2,a2) - dDOT(q2,a1)); } else { info->c[0] = k1 * (dDOT(axis,anchor2) - dDOT(axis,a1)); info->c[1] = k * (dDOT(q1,anchor2) - dDOT(q1,a1)); info->c[2] = k * (dDOT(q2,anchor2) - dDOT(q2,a1)); } } // set three orientation rows in the constraint equation, and the // corresponding right hand side. static void setFixedOrientation(dxJoint *joint, dxJoint::Info2 *info, dQuaternion qrel, int start_row) { int s = info->rowskip; int start_index = start_row * s; // 3 rows to make body rotations equal info->J1a[start_index] = 1; info->J1a[start_index + s + 1] = 1; info->J1a[start_index + s*2+2] = 1; if (joint->node[1].body) { info->J2a[start_index] = -1; info->J2a[start_index + s+1] = -1; info->J2a[start_index + s*2+2] = -1; } // compute the right hand side. the first three elements will result in // relative angular velocity of the two bodies - this is set to bring them // back into alignment. the correcting angular velocity is // |angular_velocity| = angle/time = erp*theta / stepsize // = (erp*fps) * theta // angular_velocity = |angular_velocity| * u // = (erp*fps) * theta * u // where rotation along unit length axis u by theta brings body 2's frame // to qrel with respect to body 1's frame. using a small angle approximation // for sin(), this gives // angular_velocity = (erp*fps) * 2 * v // where the quaternion of the relative rotation between the two bodies is // q = [cos(theta/2) sin(theta/2)*u] = [s v] // get qerr = relative rotation (rotation error) between two bodies dQuaternion qerr,e; if (joint->node[1].body) { dQuaternion qq; dQMultiply1 (qq,joint->node[0].body->q,joint->node[1].body->q); dQMultiply2 (qerr,qq,qrel); } else { dQMultiply3 (qerr,joint->node[0].body->q,qrel); } if (qerr[0] < 0) { qerr[1] = -qerr[1]; // adjust sign of qerr to make theta small qerr[2] = -qerr[2]; qerr[3] = -qerr[3]; } dMULTIPLY0_331 (e,joint->node[0].body->R,qerr+1); // @@@ bad SIMD padding! dReal k = info->fps * info->erp; info->c[start_row] = 2*k * e[0]; info->c[start_row+1] = 2*k * e[1]; info->c[start_row+2] = 2*k * e[2]; } // compute anchor points relative to bodies static void setAnchors (dxJoint *j, dReal x, dReal y, dReal z, dVector3 anchor1, dVector3 anchor2) { if (j->node[0].body) { dReal q[4]; q[0] = x - j->node[0].body->pos[0]; q[1] = y - j->node[0].body->pos[1]; q[2] = z - j->node[0].body->pos[2]; q[3] = 0; dMULTIPLY1_331 (anchor1,j->node[0].body->R,q); if (j->node[1].body) { q[0] = x - j->node[1].body->pos[0]; q[1] = y - j->node[1].body->pos[1]; q[2] = z - j->node[1].body->pos[2]; q[3] = 0; dMULTIPLY1_331 (anchor2,j->node[1].body->R,q); } else { anchor2[0] = x; anchor2[1] = y; anchor2[2] = z; } } anchor1[3] = 0; anchor2[3] = 0; } // compute axes relative to bodies. either axis1 or axis2 can be 0. static void setAxes (dxJoint *j, dReal x, dReal y, dReal z, dVector3 axis1, dVector3 axis2) { if (j->node[0].body) { dReal q[4]; q[0] = x; q[1] = y; q[2] = z; q[3] = 0; dNormalize3 (q); if (axis1) { dMULTIPLY1_331 (axis1,j->node[0].body->R,q); axis1[3] = 0; } if (axis2) { if (j->node[1].body) { dMULTIPLY1_331 (axis2,j->node[1].body->R,q); } else { axis2[0] = x; axis2[1] = y; axis2[2] = z; } axis2[3] = 0; } } } static void getAnchor (dxJoint *j, dVector3 result, dVector3 anchor1) { if (j->node[0].body) { dMULTIPLY0_331 (result,j->node[0].body->R,anchor1); result[0] += j->node[0].body->pos[0]; result[1] += j->node[0].body->pos[1]; result[2] += j->node[0].body->pos[2]; } } static void getAnchor2 (dxJoint *j, dVector3 result, dVector3 anchor2) { if (j->node[1].body) { dMULTIPLY0_331 (result,j->node[1].body->R,anchor2); result[0] += j->node[1].body->pos[0]; result[1] += j->node[1].body->pos[1]; result[2] += j->node[1].body->pos[2]; } else { result[0] = anchor2[0]; result[1] = anchor2[1]; result[2] = anchor2[2]; } } static void getAxis (dxJoint *j, dVector3 result, dVector3 axis1) { if (j->node[0].body) { dMULTIPLY0_331 (result,j->node[0].body->R,axis1); } } static void getAxis2 (dxJoint *j, dVector3 result, dVector3 axis2) { if (j->node[1].body) { dMULTIPLY0_331 (result,j->node[1].body->R,axis2); } else { result[0] = axis2[0]; result[1] = axis2[1]; result[2] = axis2[2]; } } static dReal getHingeAngleFromRelativeQuat (dQuaternion qrel, dVector3 axis) { // the angle between the two bodies is extracted from the quaternion that // represents the relative rotation between them. recall that a quaternion // q is: // [s,v] = [ cos(theta/2) , sin(theta/2) * u ] // where s is a scalar and v is a 3-vector. u is a unit length axis and // theta is a rotation along that axis. we can get theta/2 by: // theta/2 = atan2 ( sin(theta/2) , cos(theta/2) ) // but we can't get sin(theta/2) directly, only its absolute value, i.e.: // |v| = |sin(theta/2)| * |u| // = |sin(theta/2)| // using this value will have a strange effect. recall that there are two // quaternion representations of a given rotation, q and -q. typically as // a body rotates along the axis it will go through a complete cycle using // one representation and then the next cycle will use the other // representation. this corresponds to u pointing in the direction of the // hinge axis and then in the opposite direction. the result is that theta // will appear to go "backwards" every other cycle. here is a fix: if u // points "away" from the direction of the hinge (motor) axis (i.e. more // than 90 degrees) then use -q instead of q. this represents the same // rotation, but results in the cos(theta/2) value being sign inverted. // extract the angle from the quaternion. cost2 = cos(theta/2), // sint2 = |sin(theta/2)| dReal cost2 = qrel[0]; dReal sint2 = dSqrt (qrel[1]*qrel[1]+qrel[2]*qrel[2]+qrel[3]*qrel[3]); dReal theta = (dDOT(qrel+1,axis) >= 0) ? // @@@ padding assumptions (2 * dAtan2(sint2,cost2)) : // if u points in direction of axis (2 * dAtan2(sint2,-cost2)); // if u points in opposite direction // the angle we get will be between 0..2*pi, but we want to return angles // between -pi..pi if (theta > M_PI) theta -= 2*M_PI; // the angle we've just extracted has the wrong sign theta = -theta; return theta; } // given two bodies (body1,body2), the hinge axis that they are connected by // w.r.t. body1 (axis), and the initial relative orientation between them // (q_initial), return the relative rotation angle. the initial relative // orientation corresponds to an angle of zero. if body2 is 0 then measure the // angle between body1 and the static frame. // // this will not return the correct angle if the bodies rotate along any axis // other than the given hinge axis. static dReal getHingeAngle (dxBody *body1, dxBody *body2, dVector3 axis, dQuaternion q_initial) { // get qrel = relative rotation between the two bodies dQuaternion qrel; if (body2) { dQuaternion qq; dQMultiply1 (qq,body1->q,body2->q); dQMultiply2 (qrel,qq,q_initial); } else { // pretend body2->q is the identity dQMultiply3 (qrel,body1->q,q_initial); } return getHingeAngleFromRelativeQuat (qrel,axis); } //**************************************************************************** // dxJointLimitMotor void dxJointLimitMotor::init (dxWorld *world) { vel = 0; fmax = 0; lostop = -dInfinity; histop = dInfinity; fudge_factor = 1; normal_cfm = world->global_cfm; stop_erp = world->global_erp; stop_cfm = world->global_cfm; bounce = 0; limit = 0; limit_err = 0; } void dxJointLimitMotor::set (int num, dReal value) { switch (num) { case dParamLoStop: if (value <= histop) lostop = value; break; case dParamHiStop: if (value >= lostop) histop = value; break; case dParamVel: vel = value; break; case dParamFMax: if (value >= 0) fmax = value; break; case dParamFudgeFactor: if (value >= 0 && value <= 1) fudge_factor = value; break; case dParamBounce: bounce = value; break; case dParamCFM: normal_cfm = value; break; case dParamStopERP: stop_erp = value; break; case dParamStopCFM: stop_cfm = value; break; } } dReal dxJointLimitMotor::get (int num) { switch (num) { case dParamLoStop: return lostop; case dParamHiStop: return histop; case dParamVel: return vel; case dParamFMax: return fmax; case dParamFudgeFactor: return fudge_factor; case dParamBounce: return bounce; case dParamCFM: return normal_cfm; case dParamStopERP: return stop_erp; case dParamStopCFM: return stop_cfm; default: return 0; } } int dxJointLimitMotor::testRotationalLimit (dReal angle) { if (angle <= lostop) { limit = 1; limit_err = angle - lostop; return 1; } else if (angle >= histop) { limit = 2; limit_err = angle - histop; return 1; } else { limit = 0; return 0; } } int dxJointLimitMotor::addLimot (dxJoint *joint, dxJoint::Info2 *info, int row, dVector3 ax1, int rotational) { int srow = row * info->rowskip; // if the joint is powered, or has joint limits, add in the extra row int powered = fmax > 0; if (powered || limit) { dReal *J1 = rotational ? info->J1a : info->J1l; dReal *J2 = rotational ? info->J2a : info->J2l; J1[srow+0] = ax1[0]; J1[srow+1] = ax1[1]; J1[srow+2] = ax1[2]; if (joint->node[1].body) { J2[srow+0] = -ax1[0]; J2[srow+1] = -ax1[1]; J2[srow+2] = -ax1[2]; } // linear limot torque decoupling step: // // if this is a linear limot (e.g. from a slider), we have to be careful // that the linear constraint forces (+/- ax1) applied to the two bodies // do not create a torque couple. in other words, the points that the // constraint force is applied at must lie along the same ax1 axis. // a torque couple will result in powered or limited slider-jointed free // bodies from gaining angular momentum. // the solution used here is to apply the constraint forces at the point // halfway between the body centers. there is no penalty (other than an // extra tiny bit of computation) in doing this adjustment. note that we // only need to do this if the constraint connects two bodies. dVector3 ltd; // Linear Torque Decoupling vector (a torque) if (!rotational && joint->node[1].body) { dVector3 c; c[0]=REAL(0.5)*(joint->node[1].body->pos[0]-joint->node[0].body->pos[0]); c[1]=REAL(0.5)*(joint->node[1].body->pos[1]-joint->node[0].body->pos[1]); c[2]=REAL(0.5)*(joint->node[1].body->pos[2]-joint->node[0].body->pos[2]); dCROSS (ltd,=,c,ax1); info->J1a[srow+0] = ltd[0]; info->J1a[srow+1] = ltd[1]; info->J1a[srow+2] = ltd[2]; info->J2a[srow+0] = ltd[0]; info->J2a[srow+1] = ltd[1]; info->J2a[srow+2] = ltd[2]; } // if we're limited low and high simultaneously, the joint motor is // ineffective if (limit && (lostop == histop)) powered = 0; if (powered) { info->cfm[row] = normal_cfm; if (! limit) { info->c[row] = vel; info->lo[row] = -fmax; info->hi[row] = fmax; } else { // the joint is at a limit, AND is being powered. if the joint is // being powered into the limit then we apply the maximum motor force // in that direction, because the motor is working against the // immovable limit. if the joint is being powered away from the limit // then we have problems because actually we need *two* lcp // constraints to handle this case. so we fake it and apply some // fraction of the maximum force. the fraction to use can be set as // a fudge factor. dReal fm = fmax; if (vel > 0) fm = -fm; // if we're powering away from the limit, apply the fudge factor if ((limit==1 && vel > 0) || (limit==2 && vel < 0)) fm *= fudge_factor; if (rotational) { dBodyAddTorque (joint->node[0].body,-fm*ax1[0],-fm*ax1[1], -fm*ax1[2]); if (joint->node[1].body) dBodyAddTorque (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); } else { dBodyAddForce (joint->node[0].body,-fm*ax1[0],-fm*ax1[1],-fm*ax1[2]); if (joint->node[1].body) { dBodyAddForce (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); // linear limot torque decoupling step: refer to above discussion dBodyAddTorque (joint->node[0].body,-fm*ltd[0],-fm*ltd[1], -fm*ltd[2]); dBodyAddTorque (joint->node[1].body,-fm*ltd[0],-fm*ltd[1], -fm*ltd[2]); } } } } if (limit) { dReal k = info->fps * stop_erp; info->c[row] = -k * limit_err; info->cfm[row] = stop_cfm; if (lostop == histop) { // limited low and high simultaneously info->lo[row] = -dInfinity; info->hi[row] = dInfinity; } else { if (limit == 1) { // low limit info->lo[row] = 0; info->hi[row] = dInfinity; } else { // high limit info->lo[row] = -dInfinity; info->hi[row] = 0; } // deal with bounce if (bounce > 0) { // calculate joint velocity dReal vel; if (rotational) { vel = dDOT(joint->node[0].body->avel,ax1); if (joint->node[1].body) vel -= dDOT(joint->node[1].body->avel,ax1); } else { vel = dDOT(joint->node[0].body->lvel,ax1); if (joint->node[1].body) vel -= dDOT(joint->node[1].body->lvel,ax1); } // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. if (limit == 1) { // low limit if (vel < 0) { dReal newc = -bounce * vel; if (newc > info->c[row]) info->c[row] = newc; } } else { // high limit - all those computations are reversed if (vel > 0) { dReal newc = -bounce * vel; if (newc < info->c[row]) info->c[row] = newc; } } } } } return 1; } else return 0; } //**************************************************************************** // ball and socket static void ballInit (dxJointBall *j) { dSetZero (j->anchor1,4); dSetZero (j->anchor2,4); } static void ballGetInfo1 (dxJointBall *j, dxJoint::Info1 *info) { info->m = 3; info->nub = 3; } static void ballGetInfo2 (dxJointBall *joint, dxJoint::Info2 *info) { setBall (joint,info,joint->anchor1,joint->anchor2); } extern "C" void dJointSetBallAnchor (dxJointBall *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); } extern "C" void dJointGetBallAnchor (dxJointBall *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); if (joint->flags & dJOINT_REVERSE) getAnchor2 (joint,result,joint->anchor2); else getAnchor (joint,result,joint->anchor1); } extern "C" void dJointGetBallAnchor2 (dxJointBall *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); if (joint->flags & dJOINT_REVERSE) getAnchor (joint,result,joint->anchor1); else getAnchor2 (joint,result,joint->anchor2); } dxJoint::Vtable __dball_vtable = { sizeof(dxJointBall), (dxJoint::init_fn*) ballInit, (dxJoint::getInfo1_fn*) ballGetInfo1, (dxJoint::getInfo2_fn*) ballGetInfo2, dJointTypeBall}; //**************************************************************************** // hinge static void hingeInit (dxJointHinge *j) { dSetZero (j->anchor1,4); dSetZero (j->anchor2,4); dSetZero (j->axis1,4); j->axis1[0] = 1; dSetZero (j->axis2,4); j->axis2[0] = 1; dSetZero (j->qrel,4); j->limot.init (j->world); } static void hingeGetInfo1 (dxJointHinge *j, dxJoint::Info1 *info) { info->nub = 5; // see if joint is powered if (j->limot.fmax > 0) info->m = 6; // powered hinge needs an extra constraint row else info->m = 5; // see if we're at a joint limit. if ((j->limot.lostop >= -M_PI || j->limot.histop <= M_PI) && j->limot.lostop <= j->limot.histop) { dReal angle = getHingeAngle (j->node[0].body,j->node[1].body,j->axis1, j->qrel); if (j->limot.testRotationalLimit (angle)) info->m = 6; } } static void hingeGetInfo2 (dxJointHinge *joint, dxJoint::Info2 *info) { // set the three ball-and-socket rows setBall (joint,info,joint->anchor1,joint->anchor2); // set the two hinge rows. the hinge axis should be the only unconstrained // rotational axis, the angular velocity of the two bodies perpendicular to // the hinge axis should be equal. thus the constraint equations are // p*w1 - p*w2 = 0 // q*w1 - q*w2 = 0 // where p and q are unit vectors normal to the hinge axis, and w1 and w2 // are the angular velocity vectors of the two bodies. dVector3 ax1; // length 1 joint axis in global coordinates, from 1st body dVector3 p,q; // plane space vectors for ax1 dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); dPlaneSpace (ax1,p,q); int s3=3*info->rowskip; int s4=4*info->rowskip; info->J1a[s3+0] = p[0]; info->J1a[s3+1] = p[1]; info->J1a[s3+2] = p[2]; info->J1a[s4+0] = q[0]; info->J1a[s4+1] = q[1]; info->J1a[s4+2] = q[2]; if (joint->node[1].body) { info->J2a[s3+0] = -p[0]; info->J2a[s3+1] = -p[1]; info->J2a[s3+2] = -p[2]; info->J2a[s4+0] = -q[0]; info->J2a[s4+1] = -q[1]; info->J2a[s4+2] = -q[2]; } // compute the right hand side of the constraint equation. set relative // body velocities along p and q to bring the hinge back into alignment. // if ax1,ax2 are the unit length hinge axes as computed from body1 and // body2, we need to rotate both bodies along the axis u = (ax1 x ax2). // if `theta' is the angle between ax1 and ax2, we need an angular velocity // along u to cover angle erp*theta in one step : // |angular_velocity| = angle/time = erp*theta / stepsize // = (erp*fps) * theta // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) // ...as ax1 and ax2 are unit length. if theta is smallish, // theta ~= sin(theta), so // angular_velocity = (erp*fps) * (ax1 x ax2) // ax1 x ax2 is in the plane space of ax1, so we project the angular // velocity to p and q to find the right hand side. dVector3 ax2,b; if (joint->node[1].body) { dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); } else { ax2[0] = joint->axis2[0]; ax2[1] = joint->axis2[1]; ax2[2] = joint->axis2[2]; } dCROSS (b,=,ax1,ax2); dReal k = info->fps * info->erp; info->c[3] = k * dDOT(b,p); info->c[4] = k * dDOT(b,q); // if the hinge is powered, or has joint limits, add in the stuff joint->limot.addLimot (joint,info,5,ax1,1); } // compute initial relative rotation body1 -> body2, or env -> body1 static void hingeComputeInitialRelativeRotation (dxJointHinge *joint) { if (joint->node[0].body) { if (joint->node[1].body) { dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); } else { // set joint->qrel to the transpose of the first body q joint->qrel[0] = joint->node[0].body->q[0]; for (int i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; } } } extern "C" void dJointSetHingeAnchor (dxJointHinge *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); hingeComputeInitialRelativeRotation (joint); } extern "C" void dJointSetHingeAxis (dxJointHinge *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); setAxes (joint,x,y,z,joint->axis1,joint->axis2); hingeComputeInitialRelativeRotation (joint); } extern "C" void dJointGetHingeAnchor (dxJointHinge *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); if (joint->flags & dJOINT_REVERSE) getAnchor2 (joint,result,joint->anchor2); else getAnchor (joint,result,joint->anchor1); } extern "C" void dJointGetHingeAnchor2 (dxJointHinge *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); if (joint->flags & dJOINT_REVERSE) getAnchor (joint,result,joint->anchor1); else getAnchor2 (joint,result,joint->anchor2); } extern "C" void dJointGetHingeAxis (dxJointHinge *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); getAxis (joint,result,joint->axis1); } extern "C" void dJointSetHingeParam (dxJointHinge *joint, int parameter, dReal value) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); joint->limot.set (parameter,value); } extern "C" dReal dJointGetHingeParam (dxJointHinge *joint, int parameter) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); return joint->limot.get (parameter); } extern "C" dReal dJointGetHingeAngle (dxJointHinge *joint) { dAASSERT(joint); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); if (joint->node[0].body) { dReal ang = getHingeAngle (joint->node[0].body,joint->node[1].body,joint->axis1, joint->qrel); if (joint->flags & dJOINT_REVERSE) return -ang; else return ang; } else return 0; } extern "C" dReal dJointGetHingeAngleRate (dxJointHinge *joint) { dAASSERT(joint); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge"); if (joint->node[0].body) { dVector3 axis; dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1); dReal rate = dDOT(axis,joint->node[0].body->avel); if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); if (joint->flags & dJOINT_REVERSE) rate = - rate; return rate; } else return 0; } extern "C" void dJointAddHingeTorque (dxJointHinge *joint, dReal torque) { dVector3 axis; dAASSERT(joint); dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge"); if (joint->flags & dJOINT_REVERSE) torque = -torque; getAxis (joint,axis,joint->axis1); axis[0] *= torque; axis[1] *= torque; axis[2] *= torque; if (joint->node[0].body != 0) dBodyAddTorque (joint->node[0].body, axis[0], axis[1], axis[2]); if (joint->node[1].body != 0) dBodyAddTorque(joint->node[1].body, -axis[0], -axis[1], -axis[2]); } dxJoint::Vtable __dhinge_vtable = { sizeof(dxJointHinge), (dxJoint::init_fn*) hingeInit, (dxJoint::getInfo1_fn*) hingeGetInfo1, (dxJoint::getInfo2_fn*) hingeGetInfo2, dJointTypeHinge}; //**************************************************************************** // slider static void sliderInit (dxJointSlider *j) { dSetZero (j->axis1,4); j->axis1[0] = 1; dSetZero (j->qrel,4); dSetZero (j->offset,4); j->limot.init (j->world); } extern "C" dReal dJointGetSliderPosition (dxJointSlider *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); // get axis1 in global coordinates dVector3 ax1,q; dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); if (joint->node[1].body) { // get body2 + offset point in global coordinates dMULTIPLY0_331 (q,joint->node[1].body->R,joint->offset); for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] - q[i] - joint->node[1].body->pos[i]; } else { for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] - joint->offset[i]; } return dDOT(ax1,q); } extern "C" dReal dJointGetSliderPositionRate (dxJointSlider *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); // get axis1 in global coordinates dVector3 ax1; dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); if (joint->node[1].body) { return dDOT(ax1,joint->node[0].body->lvel) - dDOT(ax1,joint->node[1].body->lvel); } else { return dDOT(ax1,joint->node[0].body->lvel); } } static void sliderGetInfo1 (dxJointSlider *j, dxJoint::Info1 *info) { info->nub = 5; // see if joint is powered if (j->limot.fmax > 0) info->m = 6; // powered slider needs an extra constraint row else info->m = 5; // see if we're at a joint limit. j->limot.limit = 0; if ((j->limot.lostop > -dInfinity || j->limot.histop < dInfinity) && j->limot.lostop <= j->limot.histop) { // measure joint position dReal pos = dJointGetSliderPosition (j); if (pos <= j->limot.lostop) { j->limot.limit = 1; j->limot.limit_err = pos - j->limot.lostop; info->m = 6; } else if (pos >= j->limot.histop) { j->limot.limit = 2; j->limot.limit_err = pos - j->limot.histop; info->m = 6; } } } static void sliderGetInfo2 (dxJointSlider *joint, dxJoint::Info2 *info) { int i,s = info->rowskip; int s2=2*s,s3=3*s,s4=4*s; // pull out pos and R for both bodies. also get the `connection' // vector pos2-pos1. dReal *pos1,*pos2,*R1,*R2; dVector3 c; pos1 = joint->node[0].body->pos; R1 = joint->node[0].body->R; if (joint->node[1].body) { pos2 = joint->node[1].body->pos; R2 = joint->node[1].body->R; for (i=0; i<3; i++) c[i] = pos2[i] - pos1[i]; } else { pos2 = 0; R2 = 0; } // 3 rows to make body rotations equal setFixedOrientation(joint, info, joint->qrel, 0); // remaining two rows. we want: vel2 = vel1 + w1 x c ... but this would // result in three equations, so we project along the planespace vectors // so that sliding along the slider axis is disregarded. for symmetry we // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2. dVector3 ax1; // joint axis in global coordinates (unit length) dVector3 p,q; // plane space of ax1 dMULTIPLY0_331 (ax1,R1,joint->axis1); dPlaneSpace (ax1,p,q); if (joint->node[1].body) { dVector3 tmp; dCROSS (tmp, = REAL(0.5) * ,c,p); for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i]; for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i]; dCROSS (tmp, = REAL(0.5) * ,c,q); for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i]; for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i]; for (i=0; i<3; i++) info->J2l[s3+i] = -p[i]; for (i=0; i<3; i++) info->J2l[s4+i] = -q[i]; } for (i=0; i<3; i++) info->J1l[s3+i] = p[i]; for (i=0; i<3; i++) info->J1l[s4+i] = q[i]; // compute last two elements of right hand side. we want to align the offset // point (in body 2's frame) with the center of body 1. dReal k = info->fps * info->erp; if (joint->node[1].body) { dVector3 ofs; // offset point in global coordinates dMULTIPLY0_331 (ofs,R2,joint->offset); for (i=0; i<3; i++) c[i] += ofs[i]; info->c[3] = k * dDOT(p,c); info->c[4] = k * dDOT(q,c); } else { dVector3 ofs; // offset point in global coordinates for (i=0; i<3; i++) ofs[i] = joint->offset[i] - pos1[i]; info->c[3] = k * dDOT(p,ofs); info->c[4] = k * dDOT(q,ofs); } // if the slider is powered, or has joint limits, add in the extra row joint->limot.addLimot (joint,info,5,ax1,0); } extern "C" void dJointSetSliderAxis (dxJointSlider *joint, dReal x, dReal y, dReal z) { int i; dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); setAxes (joint,x,y,z,joint->axis1,0); // compute initial relative rotation body1 -> body2, or env -> body1 // also compute center of body1 w.r.t body 2 if (joint->node[1].body) { dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); dVector3 c; for (i=0; i<3; i++) c[i] = joint->node[0].body->pos[i] - joint->node[1].body->pos[i]; dMULTIPLY1_331 (joint->offset,joint->node[1].body->R,c); } else { // set joint->qrel to the transpose of the first body's q joint->qrel[0] = joint->node[0].body->q[0]; for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; for (i=0; i<3; i++) joint->offset[i] = joint->node[0].body->pos[i]; } } extern "C" void dJointGetSliderAxis (dxJointSlider *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); getAxis (joint,result,joint->axis1); } extern "C" void dJointSetSliderParam (dxJointSlider *joint, int parameter, dReal value) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); joint->limot.set (parameter,value); } extern "C" dReal dJointGetSliderParam (dxJointSlider *joint, int parameter) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); return joint->limot.get (parameter); } extern "C" void dJointAddSliderForce (dxJointSlider *joint, dReal force) { dVector3 axis; dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); if (joint->flags & dJOINT_REVERSE) force -= force; getAxis (joint,axis,joint->axis1); axis[0] *= force; axis[1] *= force; axis[2] *= force; if (joint->node[0].body != 0) dBodyAddForce (joint->node[0].body,axis[0],axis[1],axis[2]); if (joint->node[1].body != 0) dBodyAddForce(joint->node[1].body, -axis[0], -axis[1], -axis[2]); } dxJoint::Vtable __dslider_vtable = { sizeof(dxJointSlider), (dxJoint::init_fn*) sliderInit, (dxJoint::getInfo1_fn*) sliderGetInfo1, (dxJoint::getInfo2_fn*) sliderGetInfo2, dJointTypeSlider}; //**************************************************************************** // contact static void contactInit (dxJointContact *j) { // default frictionless contact. hmmm, this info gets overwritten straight // away anyway, so why bother? #if 0 /* so don't bother ;) */ j->contact.surface.mode = 0; j->contact.surface.mu = 0; dSetZero (j->contact.geom.pos,4); dSetZero (j->contact.geom.normal,4); j->contact.geom.depth = 0; #endif } static void contactGetInfo1 (dxJointContact *j, dxJoint::Info1 *info) { // make sure mu's >= 0, then calculate number of constraint rows and number // of unbounded rows. int m = 1, nub=0; if (j->contact.surface.mu < 0) j->contact.surface.mu = 0; if (j->contact.surface.mode & dContactMu2) { if (j->contact.surface.mu > 0) m++; if (j->contact.surface.mu2 < 0) j->contact.surface.mu2 = 0; if (j->contact.surface.mu2 > 0) m++; if (j->contact.surface.mu == dInfinity) nub ++; if (j->contact.surface.mu2 == dInfinity) nub ++; } else { if (j->contact.surface.mu > 0) m += 2; if (j->contact.surface.mu == dInfinity) nub += 2; } j->the_m = m; info->m = m; info->nub = nub; } static void contactGetInfo2 (dxJointContact *j, dxJoint::Info2 *info) { int i,s = info->rowskip; int s2 = 2*s; // get normal, with sign adjusted for body1/body2 polarity dVector3 normal; if (j->flags & dJOINT_REVERSE) { normal[0] = - j->contact.geom.normal[0]; normal[1] = - j->contact.geom.normal[1]; normal[2] = - j->contact.geom.normal[2]; } else { normal[0] = j->contact.geom.normal[0]; normal[1] = j->contact.geom.normal[1]; normal[2] = j->contact.geom.normal[2]; } normal[3] = 0; // @@@ hmmm // c1,c2 = contact points with respect to body PORs dVector3 c1,c2; for (i=0; i<3; i++) c1[i] = j->contact.geom.pos[i] - j->node[0].body->pos[i]; // set jacobian for normal info->J1l[0] = normal[0]; info->J1l[1] = normal[1]; info->J1l[2] = normal[2]; dCROSS (info->J1a,=,c1,normal); if (j->node[1].body) { for (i=0; i<3; i++) c2[i] = j->contact.geom.pos[i] - j->node[1].body->pos[i]; info->J2l[0] = -normal[0]; info->J2l[1] = -normal[1]; info->J2l[2] = -normal[2]; dCROSS (info->J2a,= -,c2,normal); } // set right hand side and cfm value for normal dReal erp = info->erp; if (j->contact.surface.mode & dContactSoftERP) erp = j->contact.surface.soft_erp; dReal k = info->fps * erp; info->c[0] = k*j->contact.geom.depth; if (j->contact.surface.mode & dContactSoftCFM) info->cfm[0] = j->contact.surface.soft_cfm; // deal with bounce if (j->contact.surface.mode & dContactBounce) { // calculate outgoing velocity (-ve for incoming contact) dReal outgoing = dDOT(info->J1l,j->node[0].body->lvel) + dDOT(info->J1a,j->node[0].body->avel); if (j->node[1].body) { outgoing += dDOT(info->J2l,j->node[1].body->lvel) + dDOT(info->J2a,j->node[1].body->avel); } // only apply bounce if the outgoing velocity is greater than the // threshold, and if the resulting c[0] exceeds what we already have. if (j->contact.surface.bounce_vel >= 0 && (-outgoing) > j->contact.surface.bounce_vel) { dReal newc = - j->contact.surface.bounce * outgoing; if (newc > info->c[0]) info->c[0] = newc; } } // set LCP limits for normal info->lo[0] = 0; info->hi[0] = dInfinity; // now do jacobian for tangential forces dVector3 t1,t2; // two vectors tangential to normal // first friction direction if (j->the_m >= 2) { if (j->contact.surface.mode & dContactFDir1) { // use fdir1 ? t1[0] = j->contact.fdir1[0]; t1[1] = j->contact.fdir1[1]; t1[2] = j->contact.fdir1[2]; dCROSS (t2,=,normal,t1); } else { dPlaneSpace (normal,t1,t2); } info->J1l[s+0] = t1[0]; info->J1l[s+1] = t1[1]; info->J1l[s+2] = t1[2]; dCROSS (info->J1a+s,=,c1,t1); if (j->node[1].body) { info->J2l[s+0] = -t1[0]; info->J2l[s+1] = -t1[1]; info->J2l[s+2] = -t1[2]; dCROSS (info->J2a+s,= -,c2,t1); } // set right hand side if (j->contact.surface.mode & dContactMotion1) { info->c[1] = j->contact.surface.motion1; } // set LCP bounds and friction index. this depends on the approximation // mode info->lo[1] = -j->contact.surface.mu; info->hi[1] = j->contact.surface.mu; if (j->contact.surface.mode & dContactApprox1_1) info->findex[1] = 0; // set slip (constraint force mixing) if (j->contact.surface.mode & dContactSlip1) info->cfm[1] = j->contact.surface.slip1; } // second friction direction if (j->the_m >= 3) { info->J1l[s2+0] = t2[0]; info->J1l[s2+1] = t2[1]; info->J1l[s2+2] = t2[2]; dCROSS (info->J1a+s2,=,c1,t2); if (j->node[1].body) { info->J2l[s2+0] = -t2[0]; info->J2l[s2+1] = -t2[1]; info->J2l[s2+2] = -t2[2]; dCROSS (info->J2a+s2,= -,c2,t2); } // set right hand side if (j->contact.surface.mode & dContactMotion2) { info->c[2] = j->contact.surface.motion2; } // set LCP bounds and friction index. this depends on the approximation // mode if (j->contact.surface.mode & dContactMu2) { info->lo[2] = -j->contact.surface.mu2; info->hi[2] = j->contact.surface.mu2; } else { info->lo[2] = -j->contact.surface.mu; info->hi[2] = j->contact.surface.mu; } if (j->contact.surface.mode & dContactApprox1_2) info->findex[2] = 0; // set slip (constraint force mixing) if (j->contact.surface.mode & dContactSlip2) info->cfm[2] = j->contact.surface.slip2; } } dxJoint::Vtable __dcontact_vtable = { sizeof(dxJointContact), (dxJoint::init_fn*) contactInit, (dxJoint::getInfo1_fn*) contactGetInfo1, (dxJoint::getInfo2_fn*) contactGetInfo2, dJointTypeContact}; //**************************************************************************** // hinge 2. note that this joint must be attached to two bodies for it to work static dReal measureHinge2Angle (dxJointHinge2 *joint) { dVector3 a1,a2; dMULTIPLY0_331 (a1,joint->node[1].body->R,joint->axis2); dMULTIPLY1_331 (a2,joint->node[0].body->R,a1); dReal x = dDOT(joint->v1,a2); dReal y = dDOT(joint->v2,a2); return -dAtan2 (y,x); } static void hinge2Init (dxJointHinge2 *j) { dSetZero (j->anchor1,4); dSetZero (j->anchor2,4); dSetZero (j->axis1,4); j->axis1[0] = 1; dSetZero (j->axis2,4); j->axis2[1] = 1; j->c0 = 0; j->s0 = 0; dSetZero (j->v1,4); j->v1[0] = 1; dSetZero (j->v2,4); j->v2[1] = 1; j->limot1.init (j->world); j->limot2.init (j->world); j->susp_erp = j->world->global_erp; j->susp_cfm = j->world->global_cfm; j->flags |= dJOINT_TWOBODIES; } static void hinge2GetInfo1 (dxJointHinge2 *j, dxJoint::Info1 *info) { info->m = 4; info->nub = 4; // see if we're powered or at a joint limit for axis 1 int atlimit=0; if ((j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) && j->limot1.lostop <= j->limot1.histop) { dReal angle = measureHinge2Angle (j); if (j->limot1.testRotationalLimit (angle)) atlimit = 1; } if (atlimit || j->limot1.fmax > 0) info->m++; // see if we're powering axis 2 (we currently never limit this axis) j->limot2.limit = 0; if (j->limot2.fmax > 0) info->m++; } // macro that computes ax1,ax2 = axis 1 and 2 in global coordinates (they are // relative to body 1 and 2 initially) and then computes the constrained // rotational axis as the cross product of ax1 and ax2. // the sin and cos of the angle between axis 1 and 2 is computed, this comes // from dot and cross product rules. #define HINGE2_GET_AXIS_INFO(axis,sin_angle,cos_angle) \ dVector3 ax1,ax2; \ dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); \ dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); \ dCROSS (axis,=,ax1,ax2); \ sin_angle = dSqrt (axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]); \ cos_angle = dDOT (ax1,ax2); static void hinge2GetInfo2 (dxJointHinge2 *joint, dxJoint::Info2 *info) { // get information we need to set the hinge row dReal s,c; dVector3 q; HINGE2_GET_AXIS_INFO (q,s,c); dNormalize3 (q); // @@@ quicker: divide q by s ? // set the three ball-and-socket rows (aligned to the suspension axis ax1) setBall2 (joint,info,joint->anchor1,joint->anchor2,ax1,joint->susp_erp); // set the hinge row int s3=3*info->rowskip; info->J1a[s3+0] = q[0]; info->J1a[s3+1] = q[1]; info->J1a[s3+2] = q[2]; if (joint->node[1].body) { info->J2a[s3+0] = -q[0]; info->J2a[s3+1] = -q[1]; info->J2a[s3+2] = -q[2]; } // compute the right hand side for the constrained rotational DOF. // axis 1 and axis 2 are separated by an angle `theta'. the desired // separation angle is theta0. sin(theta0) and cos(theta0) are recorded // in the joint structure. the correcting angular velocity is: // |angular_velocity| = angle/time = erp*(theta0-theta) / stepsize // = (erp*fps) * (theta0-theta) // (theta0-theta) can be computed using the following small-angle-difference // approximation: // theta0-theta ~= tan(theta0-theta) // = sin(theta0-theta)/cos(theta0-theta) // = (c*s0 - s*c0) / (c*c0 + s*s0) // = c*s0 - s*c0 assuming c*c0 + s*s0 ~= 1 // where c = cos(theta), s = sin(theta) // c0 = cos(theta0), s0 = sin(theta0) dReal k = info->fps * info->erp; info->c[3] = k * (joint->c0 * s - joint->s0 * c); // if the axis1 hinge is powered, or has joint limits, add in more stuff int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1); // if the axis2 hinge is powered, add in more stuff joint->limot2.addLimot (joint,info,row,ax2,1); // set parameter for the suspension info->cfm[0] = joint->susp_cfm; } // compute vectors v1 and v2 (embedded in body1), used to measure angle // between body 1 and body 2 static void makeHinge2V1andV2 (dxJointHinge2 *joint) { if (joint->node[0].body) { // get axis 1 and 2 in global coords dVector3 ax1,ax2,v; dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); // don't do anything if the axis1 or axis2 vectors are zero or the same if ((ax1[0]==0 && ax1[1]==0 && ax1[2]==0) || (ax2[0]==0 && ax2[1]==0 && ax2[2]==0) || (ax1[0]==ax2[0] && ax1[1]==ax2[1] && ax1[2]==ax2[2])) return; // modify axis 2 so it's perpendicular to axis 1 dReal k = dDOT(ax1,ax2); for (int i=0; i<3; i++) ax2[i] -= k*ax1[i]; dNormalize3 (ax2); // make v1 = modified axis2, v2 = axis1 x (modified axis2) dCROSS (v,=,ax1,ax2); dMULTIPLY1_331 (joint->v1,joint->node[0].body->R,ax2); dMULTIPLY1_331 (joint->v2,joint->node[0].body->R,v); } } extern "C" void dJointSetHinge2Anchor (dxJointHinge2 *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); makeHinge2V1andV2 (joint); } extern "C" void dJointSetHinge2Axis1 (dxJointHinge2 *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[0].body) { dReal q[4]; q[0] = x; q[1] = y; q[2] = z; q[3] = 0; dNormalize3 (q); dMULTIPLY1_331 (joint->axis1,joint->node[0].body->R,q); joint->axis1[3] = 0; // compute the sin and cos of the angle between axis 1 and axis 2 dVector3 ax; HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); } makeHinge2V1andV2 (joint); } extern "C" void dJointSetHinge2Axis2 (dxJointHinge2 *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[1].body) { dReal q[4]; q[0] = x; q[1] = y; q[2] = z; q[3] = 0; dNormalize3 (q); dMULTIPLY1_331 (joint->axis2,joint->node[1].body->R,q); joint->axis1[3] = 0; // compute the sin and cos of the angle between axis 1 and axis 2 dVector3 ax; HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); } makeHinge2V1andV2 (joint); } extern "C" void dJointSetHinge2Param (dxJointHinge2 *joint, int parameter, dReal value) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if ((parameter & 0xff00) == 0x100) { joint->limot2.set (parameter & 0xff,value); } else { if (parameter == dParamSuspensionERP) joint->susp_erp = value; else if (parameter == dParamSuspensionCFM) joint->susp_cfm = value; else joint->limot1.set (parameter,value); } } extern "C" void dJointGetHinge2Anchor (dxJointHinge2 *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->flags & dJOINT_REVERSE) getAnchor2 (joint,result,joint->anchor2); else getAnchor (joint,result,joint->anchor1); } extern "C" void dJointGetHinge2Anchor2 (dxJointHinge2 *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->flags & dJOINT_REVERSE) getAnchor (joint,result,joint->anchor1); else getAnchor2 (joint,result,joint->anchor2); } extern "C" void dJointGetHinge2Axis1 (dxJointHinge2 *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[0].body) { dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis1); } } extern "C" void dJointGetHinge2Axis2 (dxJointHinge2 *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[1].body) { dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis2); } } extern "C" dReal dJointGetHinge2Param (dxJointHinge2 *joint, int parameter) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if ((parameter & 0xff00) == 0x100) { return joint->limot2.get (parameter & 0xff); } else { if (parameter == dParamSuspensionERP) return joint->susp_erp; else if (parameter == dParamSuspensionCFM) return joint->susp_cfm; else return joint->limot1.get (parameter); } } extern "C" dReal dJointGetHinge2Angle1 (dxJointHinge2 *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[0].body) return measureHinge2Angle (joint); else return 0; } extern "C" dReal dJointGetHinge2Angle1Rate (dxJointHinge2 *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[0].body) { dVector3 axis; dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1); dReal rate = dDOT(axis,joint->node[0].body->avel); if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); return rate; } else return 0; } extern "C" dReal dJointGetHinge2Angle2Rate (dxJointHinge2 *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[0].body && joint->node[1].body) { dVector3 axis; dMULTIPLY0_331 (axis,joint->node[1].body->R,joint->axis2); dReal rate = dDOT(axis,joint->node[0].body->avel); if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); return rate; } else return 0; } extern "C" void dJointAddHinge2Torques (dxJointHinge2 *joint, dReal torque1, dReal torque2) { dVector3 axis1, axis2; dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); if (joint->node[0].body && joint->node[1].body) { dMULTIPLY0_331 (axis1,joint->node[0].body->R,joint->axis1); dMULTIPLY0_331 (axis2,joint->node[1].body->R,joint->axis2); axis1[0] = axis1[0] * torque1 + axis2[0] * torque2; axis1[1] = axis1[1] * torque1 + axis2[1] * torque2; axis1[2] = axis1[2] * torque1 + axis2[2] * torque2; dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]); dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]); } } dxJoint::Vtable __dhinge2_vtable = { sizeof(dxJointHinge2), (dxJoint::init_fn*) hinge2Init, (dxJoint::getInfo1_fn*) hinge2GetInfo1, (dxJoint::getInfo2_fn*) hinge2GetInfo2, dJointTypeHinge2}; //**************************************************************************** // universal // I just realized that the universal joint is equivalent to a hinge 2 joint with // perfectly stiff suspension. By comparing the hinge 2 implementation to // the universal implementation, you may be able to improve this // implementation (or, less likely, the hinge2 implementation). static void universalInit (dxJointUniversal *j) { dSetZero (j->anchor1,4); dSetZero (j->anchor2,4); dSetZero (j->axis1,4); j->axis1[0] = 1; dSetZero (j->axis2,4); j->axis2[1] = 1; dSetZero(j->qrel1,4); dSetZero(j->qrel2,4); j->limot1.init (j->world); j->limot2.init (j->world); } static void getUniversalAxes(dxJointUniversal *joint, dVector3 ax1, dVector3 ax2) { // This says "ax1 = joint->node[0].body->R * joint->axis1" dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); if (joint->node[1].body) { dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); } else { ax2[0] = joint->axis2[0]; ax2[1] = joint->axis2[1]; ax2[2] = joint->axis2[2]; } } static dReal getUniversalAngle1(dxJointUniversal *joint) { if (joint->node[0].body) { // length 1 joint axis in global coordinates, from each body dVector3 ax1, ax2; dMatrix3 R; dQuaternion qcross, qq, qrel; getUniversalAxes (joint,ax1,ax2); // It should be possible to get both angles without explicitly // constructing the rotation matrix of the cross. Basically, // orientation of the cross about axis1 comes from body 2, // about axis 2 comes from body 1, and the perpendicular // axis can come from the two bodies somehow. (We don't really // want to assume it's 90 degrees, because in general the // constraints won't be perfectly satisfied, or even very well // satisfied.) // // However, we'd need a version of getHingeAngleFromRElativeQuat() // that CAN handle when its relative quat is rotated along a direction // other than the given axis. What I have here works, // although it's probably much slower than need be. dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]); dRtoQ (R,qcross); // This code is essential the same as getHingeAngle(), see the comments // there for details. // get qrel = relative rotation between node[0] and the cross dQMultiply1 (qq,joint->node[0].body->q,qcross); dQMultiply2 (qrel,qq,joint->qrel1); return getHingeAngleFromRelativeQuat(qrel, joint->axis1); } return 0; } static dReal getUniversalAngle2(dxJointUniversal *joint) { if (joint->node[0].body) { // length 1 joint axis in global coordinates, from each body dVector3 ax1, ax2; dMatrix3 R; dQuaternion qcross, qq, qrel; getUniversalAxes (joint,ax1,ax2); // It should be possible to get both angles without explicitly // constructing the rotation matrix of the cross. Basically, // orientation of the cross about axis1 comes from body 2, // about axis 2 comes from body 1, and the perpendicular // axis can come from the two bodies somehow. (We don't really // want to assume it's 90 degrees, because in general the // constraints won't be perfectly satisfied, or even very well // satisfied.) // // However, we'd need a version of getHingeAngleFromRElativeQuat() // that CAN handle when its relative quat is rotated along a direction // other than the given axis. What I have here works, // although it's probably much slower than need be. dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]); dRtoQ(R, qcross); if (joint->node[1].body) { dQMultiply1 (qq, joint->node[1].body->q, qcross); dQMultiply2 (qrel,qq,joint->qrel2); } else { // pretend joint->node[1].body->q is the identity dQMultiply2 (qrel,qcross, joint->qrel2); } return - getHingeAngleFromRelativeQuat(qrel, joint->axis2); } return 0; } static void universalGetInfo1 (dxJointUniversal *j, dxJoint::Info1 *info) { info->nub = 4; info->m = 4; // see if we're powered or at a joint limit. bool constraint1 = j->limot1.fmax > 0; bool constraint2 = j->limot2.fmax > 0; bool limiting1 = (j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) && j->limot1.lostop <= j->limot1.histop; bool limiting2 = (j->limot2.lostop >= -M_PI || j->limot2.histop <= M_PI) && j->limot2.lostop <= j->limot2.histop; // We need to call testRotationLimit() even if we're motored, since it // records the result. if (limiting1 || limiting2) { dReal angle1, angle2; angle1 = getUniversalAngle1(j); angle2 = getUniversalAngle2(j); if (limiting1 && j->limot1.testRotationalLimit (angle1)) constraint1 = true; if (limiting2 && j->limot2.testRotationalLimit (angle2)) constraint2 = true; } if (constraint1) info->m++; if (constraint2) info->m++; } static void universalGetInfo2 (dxJointUniversal *joint, dxJoint::Info2 *info) { // set the three ball-and-socket rows setBall (joint,info,joint->anchor1,joint->anchor2); // set the universal joint row. the angular velocity about an axis // perpendicular to both joint axes should be equal. thus the constraint // equation is // p*w1 - p*w2 = 0 // where p is a vector normal to both joint axes, and w1 and w2 // are the angular velocity vectors of the two bodies. // length 1 joint axis in global coordinates, from each body dVector3 ax1, ax2; dVector3 ax2_temp; // length 1 vector perpendicular to ax1 and ax2. Neither body can rotate // about this. dVector3 p; dReal k; getUniversalAxes(joint, ax1, ax2); k = dDOT(ax1, ax2); ax2_temp[0] = ax2[0] - k*ax1[0]; ax2_temp[1] = ax2[1] - k*ax1[1]; ax2_temp[2] = ax2[2] - k*ax1[2]; dCROSS(p, =, ax1, ax2_temp); dNormalize3(p); int s3=3*info->rowskip; info->J1a[s3+0] = p[0]; info->J1a[s3+1] = p[1]; info->J1a[s3+2] = p[2]; if (joint->node[1].body) { info->J2a[s3+0] = -p[0]; info->J2a[s3+1] = -p[1]; info->J2a[s3+2] = -p[2]; } // compute the right hand side of the constraint equation. set relative // body velocities along p to bring the axes back to perpendicular. // If ax1, ax2 are unit length joint axes as computed from body1 and // body2, we need to rotate both bodies along the axis p. If theta // is the angle between ax1 and ax2, we need an angular velocity // along p to cover the angle erp * (theta - Pi/2) in one step: // // |angular_velocity| = angle/time = erp*(theta - Pi/2) / stepsize // = (erp*fps) * (theta - Pi/2) // // if theta is close to Pi/2, // theta - Pi/2 ~= cos(theta), so // |angular_velocity| ~= (erp*fps) * (ax1 dot ax2) info->c[3] = info->fps * info->erp * - dDOT(ax1, ax2); // if the first angle is powered, or has joint limits, add in the stuff int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1); // if the second angle is powered, or has joint limits, add in more stuff joint->limot2.addLimot (joint,info,row,ax2,1); } static void universalComputeInitialRelativeRotations (dxJointUniversal *joint) { if (joint->node[0].body) { dVector3 ax1, ax2; dMatrix3 R; dQuaternion qcross; getUniversalAxes(joint, ax1, ax2); // Axis 1. dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]); dRtoQ(R, qcross); dQMultiply1 (joint->qrel1, joint->node[0].body->q, qcross); // Axis 2. dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]); dRtoQ(R, qcross); if (joint->node[1].body) { dQMultiply1 (joint->qrel2, joint->node[1].body->q, qcross); } else { // set joint->qrel to qcross for (int i=0; i<4; i++) joint->qrel2[i] = qcross[i]; } } } extern "C" void dJointSetUniversalAnchor (dxJointUniversal *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); universalComputeInitialRelativeRotations(joint); } extern "C" void dJointSetUniversalAxis1 (dxJointUniversal *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) setAxes (joint,x,y,z,NULL,joint->axis2); else setAxes (joint,x,y,z,joint->axis1,NULL); universalComputeInitialRelativeRotations(joint); } extern "C" void dJointSetUniversalAxis2 (dxJointUniversal *joint, dReal x, dReal y, dReal z) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) setAxes (joint,x,y,z,joint->axis1,NULL); else setAxes (joint,x,y,z,NULL,joint->axis2); universalComputeInitialRelativeRotations(joint); } extern "C" void dJointGetUniversalAnchor (dxJointUniversal *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) getAnchor2 (joint,result,joint->anchor2); else getAnchor (joint,result,joint->anchor1); } extern "C" void dJointGetUniversalAnchor2 (dxJointUniversal *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) getAnchor (joint,result,joint->anchor1); else getAnchor2 (joint,result,joint->anchor2); } extern "C" void dJointGetUniversalAxis1 (dxJointUniversal *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) getAxis2 (joint,result,joint->axis2); else getAxis (joint,result,joint->axis1); } extern "C" void dJointGetUniversalAxis2 (dxJointUniversal *joint, dVector3 result) { dUASSERT(joint,"bad joint argument"); dUASSERT(result,"bad result argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) getAxis (joint,result,joint->axis1); else getAxis2 (joint,result,joint->axis2); } extern "C" void dJointSetUniversalParam (dxJointUniversal *joint, int parameter, dReal value) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if ((parameter & 0xff00) == 0x100) { joint->limot2.set (parameter & 0xff,value); } else { joint->limot1.set (parameter,value); } } extern "C" dReal dJointGetUniversalParam (dxJointUniversal *joint, int parameter) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if ((parameter & 0xff00) == 0x100) { return joint->limot2.get (parameter & 0xff); } else { return joint->limot1.get (parameter); } } extern "C" dReal dJointGetUniversalAngle1 (dxJointUniversal *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) return getUniversalAngle2 (joint); else return getUniversalAngle1 (joint); } extern "C" dReal dJointGetUniversalAngle2 (dxJointUniversal *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) return getUniversalAngle1 (joint); else return getUniversalAngle2 (joint); } extern "C" dReal dJointGetUniversalAngle1Rate (dxJointUniversal *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->node[0].body) { dVector3 axis; if (joint->flags & dJOINT_REVERSE) getAxis2 (joint,axis,joint->axis2); else getAxis (joint,axis,joint->axis1); dReal rate = dDOT(axis, joint->node[0].body->avel); if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel); return rate; } return 0; } extern "C" dReal dJointGetUniversalAngle2Rate (dxJointUniversal *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->node[0].body) { dVector3 axis; if (joint->flags & dJOINT_REVERSE) getAxis (joint,axis,joint->axis1); else getAxis2 (joint,axis,joint->axis2); dReal rate = dDOT(axis, joint->node[0].body->avel); if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel); return rate; } return 0; } extern "C" void dJointAddUniversalTorques (dxJointUniversal *joint, dReal torque1, dReal torque2) { dVector3 axis1, axis2; dAASSERT(joint); dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); if (joint->flags & dJOINT_REVERSE) { dReal temp = torque1; torque1 = - torque2; torque2 = - temp; } getAxis (joint,axis1,joint->axis1); getAxis2 (joint,axis2,joint->axis2); axis1[0] = axis1[0] * torque1 + axis2[0] * torque2; axis1[1] = axis1[1] * torque1 + axis2[1] * torque2; axis1[2] = axis1[2] * torque1 + axis2[2] * torque2; if (joint->node[0].body != 0) dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]); if (joint->node[1].body != 0) dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]); } dxJoint::Vtable __duniversal_vtable = { sizeof(dxJointUniversal), (dxJoint::init_fn*) universalInit, (dxJoint::getInfo1_fn*) universalGetInfo1, (dxJoint::getInfo2_fn*) universalGetInfo2, dJointTypeUniversal}; //**************************************************************************** // angular motor static void amotorInit (dxJointAMotor *j) { int i; j->num = 0; j->mode = dAMotorUser; for (i=0; i<3; i++) { j->rel[i] = 0; dSetZero (j->axis[i],4); j->limot[i].init (j->world); j->angle[i] = 0; } dSetZero (j->reference1,4); dSetZero (j->reference2,4); j->flags |= dJOINT_TWOBODIES; } // compute the 3 axes in global coordinates static void amotorComputeGlobalAxes (dxJointAMotor *joint, dVector3 ax[3]) { if (joint->mode == dAMotorEuler) { // special handling for euler mode dMULTIPLY0_331 (ax[0],joint->node[0].body->R,joint->axis[0]); dMULTIPLY0_331 (ax[2],joint->node[1].body->R,joint->axis[2]); dCROSS (ax[1],=,ax[2],ax[0]); dNormalize3 (ax[1]); } else { for (int i=0; i < joint->num; i++) { if (joint->rel[i] == 1) { // relative to b1 dMULTIPLY0_331 (ax[i],joint->node[0].body->R,joint->axis[i]); } if (joint->rel[i] == 2) { // relative to b2 dMULTIPLY0_331 (ax[i],joint->node[1].body->R,joint->axis[i]); } else { // global - just copy it ax[i][0] = joint->axis[i][0]; ax[i][1] = joint->axis[i][1]; ax[i][2] = joint->axis[i][2]; } } } } static void amotorComputeEulerAngles (dxJointAMotor *joint, dVector3 ax[3]) { // assumptions: // global axes already calculated --> ax // axis[0] is relative to body 1 --> global ax[0] // axis[2] is relative to body 2 --> global ax[2] // ax[1] = ax[2] x ax[0] // original ax[0] and ax[2] are perpendicular // reference1 is perpendicular to ax[0] (in body 1 frame) // reference2 is perpendicular to ax[2] (in body 2 frame) // all ax[] and reference vectors are unit length // calculate references in global frame dVector3 ref1,ref2; dMULTIPLY0_331 (ref1,joint->node[0].body->R,joint->reference1); dMULTIPLY0_331 (ref2,joint->node[1].body->R,joint->reference2); // get q perpendicular to both ax[0] and ref1, get first euler angle dVector3 q; dCROSS (q,=,ax[0],ref1); joint->angle[0] = -dAtan2 (dDOT(ax[2],q),dDOT(ax[2],ref1)); // get q perpendicular to both ax[0] and ax[1], get second euler angle dCROSS (q,=,ax[0],ax[1]); joint->angle[1] = -dAtan2 (dDOT(ax[2],ax[0]),dDOT(ax[2],q)); // get q perpendicular to both ax[1] and ax[2], get third euler angle dCROSS (q,=,ax[1],ax[2]); joint->angle[2] = -dAtan2 (dDOT(ref2,ax[1]), dDOT(ref2,q)); } // set the reference vectors as follows: // * reference1 = current axis[2] relative to body 1 // * reference2 = current axis[0] relative to body 2 // this assumes that: // * axis[0] is relative to body 1 // * axis[2] is relative to body 2 static void amotorSetEulerReferenceVectors (dxJointAMotor *j) { if (j->node[0].body && j->node[1].body) { dVector3 r; // axis[2] and axis[0] in global coordinates dMULTIPLY0_331 (r,j->node[1].body->R,j->axis[2]); dMULTIPLY1_331 (j->reference1,j->node[0].body->R,r); dMULTIPLY0_331 (r,j->node[0].body->R,j->axis[0]); dMULTIPLY1_331 (j->reference2,j->node[1].body->R,r); } } static void amotorGetInfo1 (dxJointAMotor *j, dxJoint::Info1 *info) { info->m = 0; info->nub = 0; // compute the axes and angles, if in euler mode if (j->mode == dAMotorEuler) { dVector3 ax[3]; amotorComputeGlobalAxes (j,ax); amotorComputeEulerAngles (j,ax); } // see if we're powered or at a joint limit for each axis for (int i=0; i < j->num; i++) { if (j->limot[i].testRotationalLimit (j->angle[i]) || j->limot[i].fmax > 0) { info->m++; } } } static void amotorGetInfo2 (dxJointAMotor *joint, dxJoint::Info2 *info) { int i; // compute the axes (if not global) dVector3 ax[3]; amotorComputeGlobalAxes (joint,ax); // in euler angle mode we do not actually constrain the angular velocity // along the axes axis[0] and axis[2] (although we do use axis[1]) : // // to get constrain w2-w1 along ...not // ------ --------------------- ------ // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0] // d(angle[1])/dt = 0 ax[1] // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2] // // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0. // to prove the result for angle[0], write the expression for angle[0] from // GetInfo1 then take the derivative. to prove this for angle[2] it is // easier to take the euler rate expression for d(angle[2])/dt with respect // to the components of w and set that to 0. dVector3 *axptr[3]; axptr[0] = &ax[0]; axptr[1] = &ax[1]; axptr[2] = &ax[2]; dVector3 ax0_cross_ax1; dVector3 ax1_cross_ax2; if (joint->mode == dAMotorEuler) { dCROSS (ax0_cross_ax1,=,ax[0],ax[1]); axptr[2] = &ax0_cross_ax1; dCROSS (ax1_cross_ax2,=,ax[1],ax[2]); axptr[0] = &ax1_cross_ax2; } int row=0; for (i=0; i < joint->num; i++) { row += joint->limot[i].addLimot (joint,info,row,*(axptr[i]),1); } } extern "C" void dJointSetAMotorNumAxes (dxJointAMotor *joint, int num) { dAASSERT(joint && num >= 0 && num <= 3); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); if (joint->mode == dAMotorEuler) { joint->num = 3; } else { if (num < 0) num = 0; if (num > 3) num = 3; joint->num = num; } } extern "C" void dJointSetAMotorAxis (dxJointAMotor *joint, int anum, int rel, dReal x, dReal y, dReal z) { dAASSERT(joint && anum >= 0 && anum <= 2 && rel >= 0 && rel <= 2); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); if (anum < 0) anum = 0; if (anum > 2) anum = 2; joint->rel[anum] = rel; // x,y,z is always in global coordinates regardless of rel, so we may have // to convert it to be relative to a body dVector3 r; r[0] = x; r[1] = y; r[2] = z; r[3] = 0; if (rel > 0) { if (rel==1) { dMULTIPLY1_331 (joint->axis[anum],joint->node[0].body->R,r); } else { dMULTIPLY1_331 (joint->axis[anum],joint->node[1].body->R,r); } } else { joint->axis[anum][0] = r[0]; joint->axis[anum][1] = r[1]; joint->axis[anum][2] = r[2]; } dNormalize3 (joint->axis[anum]); if (joint->mode == dAMotorEuler) amotorSetEulerReferenceVectors (joint); } extern "C" void dJointSetAMotorAngle (dxJointAMotor *joint, int anum, dReal angle) { dAASSERT(joint && anum >= 0 && anum < 3); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); if (joint->mode == dAMotorUser) { if (anum < 0) anum = 0; if (anum > 3) anum = 3; joint->angle[anum] = angle; } } extern "C" void dJointSetAMotorParam (dxJointAMotor *joint, int parameter, dReal value) { dAASSERT(joint); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); int anum = parameter >> 8; if (anum < 0) anum = 0; if (anum > 2) anum = 2; parameter &= 0xff; joint->limot[anum].set (parameter, value); } extern "C" void dJointSetAMotorMode (dxJointAMotor *joint, int mode) { dAASSERT(joint); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); joint->mode = mode; if (joint->mode == dAMotorEuler) { joint->num = 3; amotorSetEulerReferenceVectors (joint); } } extern "C" int dJointGetAMotorNumAxes (dxJointAMotor *joint) { dAASSERT(joint); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); return joint->num; } extern "C" void dJointGetAMotorAxis (dxJointAMotor *joint, int anum, dVector3 result) { dAASSERT(joint && anum >= 0 && anum < 3); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); if (anum < 0) anum = 0; if (anum > 2) anum = 2; if (joint->rel[anum] > 0) { if (joint->rel[anum]==1) { dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis[anum]); } else { dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis[anum]); } } else { result[0] = joint->axis[anum][0]; result[1] = joint->axis[anum][1]; result[2] = joint->axis[anum][2]; } } extern "C" int dJointGetAMotorAxisRel (dxJointAMotor *joint, int anum) { dAASSERT(joint && anum >= 0 && anum < 3); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); if (anum < 0) anum = 0; if (anum > 2) anum = 2; return joint->rel[anum]; } extern "C" dReal dJointGetAMotorAngle (dxJointAMotor *joint, int anum) { dAASSERT(joint && anum >= 0 && anum < 3); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); if (anum < 0) anum = 0; if (anum > 3) anum = 3; return joint->angle[anum]; } extern "C" dReal dJointGetAMotorAngleRate (dxJointAMotor *joint, int anum) { // @@@ dDebug (0,"not yet implemented"); return 0; } extern "C" dReal dJointGetAMotorParam (dxJointAMotor *joint, int parameter) { dAASSERT(joint); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); int anum = parameter >> 8; if (anum < 0) anum = 0; if (anum > 2) anum = 2; parameter &= 0xff; return joint->limot[anum].get (parameter); } extern "C" int dJointGetAMotorMode (dxJointAMotor *joint) { dAASSERT(joint); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); return joint->mode; } extern "C" void dJointAddAMotorTorques (dxJointAMotor *joint, dReal torque1, dReal torque2, dReal torque3) { dVector3 axes[3]; dAASSERT(joint); dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); if (joint->num == 0) return; dUASSERT((joint->flags & dJOINT_REVERSE) == 0, "dJointAddAMotorTorques not yet implemented for reverse AMotor joints"); amotorComputeGlobalAxes (joint,axes); axes[0][0] *= torque1; axes[0][1] *= torque1; axes[0][2] *= torque1; if (joint->num >= 2) { axes[0][0] += axes[1][0] * torque2; axes[0][1] += axes[1][0] * torque2; axes[0][2] += axes[1][0] * torque2; if (joint->num >= 3) { axes[0][0] += axes[2][0] * torque3; axes[0][1] += axes[2][0] * torque3; axes[0][2] += axes[2][0] * torque3; } } if (joint->node[0].body != 0) dBodyAddTorque (joint->node[0].body,axes[0][0],axes[0][1],axes[0][2]); if (joint->node[1].body != 0) dBodyAddTorque(joint->node[1].body, -axes[0][0], -axes[0][1], -axes[0][2]); } dxJoint::Vtable __damotor_vtable = { sizeof(dxJointAMotor), (dxJoint::init_fn*) amotorInit, (dxJoint::getInfo1_fn*) amotorGetInfo1, (dxJoint::getInfo2_fn*) amotorGetInfo2, dJointTypeAMotor}; //**************************************************************************** // fixed joint static void fixedInit (dxJointFixed *j) { dSetZero (j->offset,4); dSetZero (j->qrel,4); } static void fixedGetInfo1 (dxJointFixed *j, dxJoint::Info1 *info) { info->m = 6; info->nub = 6; } static void fixedGetInfo2 (dxJointFixed *joint, dxJoint::Info2 *info) { int s = info->rowskip; // Three rows for orientation setFixedOrientation(joint, info, joint->qrel, 3); // Three rows for position. // set jacobian info->J1l[0] = 1; info->J1l[s+1] = 1; info->J1l[2*s+2] = 1; dVector3 ofs; dMULTIPLY0_331 (ofs,joint->node[0].body->R,joint->offset); if (joint->node[1].body) { dCROSSMAT (info->J1a,ofs,s,+,-); info->J2l[0] = -1; info->J2l[s+1] = -1; info->J2l[2*s+2] = -1; } // set right hand side for the first three rows (linear) dReal k = info->fps * info->erp; if (joint->node[1].body) { for (int j=0; j<3; j++) info->c[j] = k * (joint->node[1].body->pos[j] - joint->node[0].body->pos[j] + ofs[j]); } else { for (int j=0; j<3; j++) info->c[j] = k * (joint->offset[j] - joint->node[0].body->pos[j]); } } extern "C" void dJointSetFixed (dxJointFixed *joint) { dUASSERT(joint,"bad joint argument"); dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not fixed"); int i; // This code is taken from sJointSetSliderAxis(), we should really put the // common code in its own function. // compute the offset between the bodies if (joint->node[0].body) { if (joint->node[1].body) { dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); dReal ofs[4]; for (i=0; i<4; i++) ofs[i] = joint->node[0].body->pos[i]; for (i=0; i<4; i++) ofs[i] -= joint->node[1].body->pos[i]; dMULTIPLY1_331 (joint->offset,joint->node[0].body->R,ofs); } else { // set joint->qrel to the transpose of the first body's q joint->qrel[0] = joint->node[0].body->q[0]; for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; for (i=0; i<4; i++) joint->offset[i] = joint->node[0].body->pos[i]; } } } dxJoint::Vtable __dfixed_vtable = { sizeof(dxJointFixed), (dxJoint::init_fn*) fixedInit, (dxJoint::getInfo1_fn*) fixedGetInfo1, (dxJoint::getInfo2_fn*) fixedGetInfo2, dJointTypeFixed}; //**************************************************************************** // null joint static void nullGetInfo1 (dxJointNull *j, dxJoint::Info1 *info) { info->m = 0; info->nub = 0; } static void nullGetInfo2 (dxJointNull *joint, dxJoint::Info2 *info) { dDebug (0,"this should never get called"); } dxJoint::Vtable __dnull_vtable = { sizeof(dxJointNull), (dxJoint::init_fn*) 0, (dxJoint::getInfo1_fn*) nullGetInfo1, (dxJoint::getInfo2_fn*) nullGetInfo2, dJointTypeNull}; /******************** breakable joint contribution ***********************/ extern "C" void dJointSetBreakable (dxJoint *joint, int b) { dAASSERT(joint); if (b) { // we want this joint to be breakable but we must first check if it // was already breakable if (!joint->breakInfo) { // allocate a dxJointBreakInfo struct joint->breakInfo = new dxJointBreakInfo; joint->breakInfo->flags = 0; for (int i = 0; i < 3; i++) { joint->breakInfo->b1MaxF[0] = 0; joint->breakInfo->b1MaxT[0] = 0; joint->breakInfo->b2MaxF[0] = 0; joint->breakInfo->b2MaxT[0] = 0; } joint->breakInfo->callback = 0; } else { // the joint was already breakable return; } } else { // we want this joint to be unbreakable mut we must first check if // it is alreay unbreakable if (joint->breakInfo) { // deallocate the dxJointBreakInfo struct delete joint->breakInfo; joint->breakInfo = 0; } else { // the joint was already unbreakable return; } } } extern "C" void dJointSetBreakCallback (dxJoint *joint, dJointBreakCallback *callbackFunc) { dAASSERT(joint); # ifndef dNODEBUG // only works for a breakable joint if (!joint->breakInfo) { dDebug (0, "dJointSetBreakCallback called on unbreakable joint"); } # endif joint->breakInfo->callback = callbackFunc; } extern "C" void dJointSetBreakMode (dxJoint *joint, int mode) { dAASSERT(joint); # ifndef dNODEBUG // only works for a breakable joint if (!joint->breakInfo) { dDebug (0, "dJointSetBreakMode called on unbreakable joint"); } # endif joint->breakInfo->flags = mode; } extern "C" int dJointGetBreakMode (dxJoint *joint) { dAASSERT(joint); # ifndef dNODEBUG // only works for a breakable joint if (!joint->breakInfo) { dDebug (0, "dJointGetBreakMode called on unbreakable joint"); } # endif return joint->breakInfo->flags; } extern "C" void dJointSetBreakForce (dxJoint *joint, int body, dReal x, dReal y, dReal z) { dAASSERT(joint); # ifndef dNODEBUG // only works for a breakable joint if (!joint->breakInfo) { dDebug (0, "dJointSetBreakForce called on unbreakable joint"); } # endif if (body) { joint->breakInfo->b2MaxF[0] = x; joint->breakInfo->b2MaxF[1] = y; joint->breakInfo->b2MaxF[2] = z; } else { joint->breakInfo->b1MaxF[0] = x; joint->breakInfo->b1MaxF[1] = y; joint->breakInfo->b1MaxF[2] = z; } } extern "C" void dJointSetBreakTorque (dxJoint *joint, int body, dReal x, dReal y, dReal z) { dAASSERT(joint); # ifndef dNODEBUG // only works for a breakable joint if (!joint->breakInfo) { dDebug (0, "dJointSetBreakTorque called on unbreakable joint"); } # endif if (body) { joint->breakInfo->b2MaxT[0] = x; joint->breakInfo->b2MaxT[1] = y; joint->breakInfo->b2MaxT[2] = z; } else { joint->breakInfo->b1MaxT[0] = x; joint->breakInfo->b1MaxT[1] = y; joint->breakInfo->b1MaxT[2] = z; } } extern "C" int dJointIsBreakable (dxJoint *joint) { dAASSERT(joint); return joint->breakInfo != 0; } extern "C" void dJointGetBreakForce (dxJoint *joint, int body, dReal *force) { dAASSERT(joint); # ifndef dNODEBUG // only works for a breakable joint if (!joint->breakInfo) { dDebug (0, "dJointGetBreakForce called on unbreakable joint"); } # endif if (body) for (int i=0; i<3; i++) force[i]=joint->breakInfo->b2MaxF[i]; else for (int i=0; i<3; i++) force[i]=joint->breakInfo->b1MaxF[i]; } extern "C" void dJointGetBreakTorque (dxJoint *joint, int body, dReal *torque) { dAASSERT(joint); # ifndef dNODEBUG // only works for a breakable joint if (!joint->breakInfo) { dDebug (0, "dJointGetBreakTorque called on unbreakable joint"); } # endif if (body) for (int i=0; i<3; i++) torque[i]=joint->breakInfo->b2MaxT[i]; else for (int i=0; i<3; i++) torque[i]=joint->breakInfo->b1MaxT[i]; } /*************************************************************************/ ode-0.14/contrib/BreakableJoints/joint.h0000644000000000000000000002440712635011627016710 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_JOINT_H_ #define _ODE_JOINT_H_ #include "objects.h" #include #include "obstack.h" // joint flags enum { // if this flag is set, the joint was allocated in a joint group dJOINT_INGROUP = 1, // if this flag is set, the joint was attached with arguments (0,body). // our convention is to treat all attaches as (body,0), i.e. so node[0].body // is always nonzero, so this flag records the fact that the arguments were // swapped. dJOINT_REVERSE = 2, // if this flag is set, the joint can not have just one body attached to it, // it must have either zero or two bodies attached. dJOINT_TWOBODIES = 4 }; // there are two of these nodes in the joint, one for each connection to a // body. these are node of a linked list kept by each body of it's connecting // joints. but note that the body pointer in each node points to the body that // makes use of the *other* node, not this node. this trick makes it a bit // easier to traverse the body/joint graph. struct dxJointNode { dxJoint *joint; // pointer to enclosing dxJoint object dxBody *body; // *other* body this joint is connected to dxJointNode *next; // next node in body's list of connected joints }; /******************** breakable joint contribution ***********************/ struct dxJointBreakInfo : public dBase { int flags; dReal b1MaxF[3]; // maximum force on body 1 dReal b1MaxT[3]; // maximum torque on body 1 dReal b2MaxF[3]; // maximum force on body 2 dReal b2MaxT[3]; // maximum torque on body 2 dJointBreakCallback *callback; // function that is called when this joint breaks }; /*************************************************************************/ struct dxJoint : public dObject { // naming convention: the "first" body this is connected to is node[0].body, // and the "second" body is node[1].body. if this joint is only connected // to one body then the second body is 0. // info returned by getInfo1 function. the constraint dimension is m (<=6). // i.e. that is the total number of rows in the jacobian. `nub' is the // number of unbounded variables (which have lo,hi = -/+ infinity). struct Info1 { int m,nub; }; // info returned by getInfo2 function struct Info2 { // integrator parameters: frames per second (1/stepsize), default error // reduction parameter (0..1). dReal fps,erp; // for the first and second body, pointers to two (linear and angular) // n*3 jacobian sub matrices, stored by rows. these matrices will have // been initialized to 0 on entry. if the second body is zero then the // J2xx pointers may be 0. dReal *J1l,*J1a,*J2l,*J2a; // elements to jump from one row to the next in J's int rowskip; // right hand sides of the equation J*v = c + cfm * lambda. cfm is the // "constraint force mixing" vector. c is set to zero on entry, cfm is // set to a constant value (typically very small or zero) value on entry. dReal *c,*cfm; // lo and hi limits for variables (set to -/+ infinity on entry). dReal *lo,*hi; // findex vector for variables. see the LCP solver interface for a // description of what this does. this is set to -1 on entry. // note that the returned indexes are relative to the first index of // the constraint. int *findex; }; // virtual function table: size of the joint structure, function pointers. // we do it this way instead of using C++ virtual functions because // sometimes we need to allocate joints ourself within a memory pool. typedef void init_fn (dxJoint *joint); typedef void getInfo1_fn (dxJoint *joint, Info1 *info); typedef void getInfo2_fn (dxJoint *joint, Info2 *info); struct Vtable { int size; init_fn *init; getInfo1_fn *getInfo1; getInfo2_fn *getInfo2; int typenum; // a dJointTypeXXX type number }; Vtable *vtable; // virtual function table int flags; // dJOINT_xxx flags dxJointNode node[2]; // connections to bodies. node[1].body can be 0 dJointFeedback *feedback; // optional feedback structure /******************** breakable joint contribution ***********************/ // optional break info structure. if this is not NULL the the joint is // breakable. dxJointBreakInfo *breakInfo; /*************************************************************************/ }; // joint group. NOTE: any joints in the group that have their world destroyed // will have their world pointer set to 0. struct dxJointGroup : public dBase { int num; // number of joints on the stack dObStack stack; // a stack of (possibly differently sized) dxJoint }; // objects. // common limit and motor information for a single joint axis of movement struct dxJointLimitMotor { dReal vel,fmax; // powered joint: velocity, max force dReal lostop,histop; // joint limits, relative to initial position dReal fudge_factor; // when powering away from joint limits dReal normal_cfm; // cfm to use when not at a stop dReal stop_erp,stop_cfm; // erp and cfm for when at joint limit dReal bounce; // restitution factor // variables used between getInfo1() and getInfo2() int limit; // 0=free, 1=at lo limit, 2=at hi limit dReal limit_err; // if at limit, amount over limit void init (dxWorld *); void set (int num, dReal value); dReal get (int num); int testRotationalLimit (dReal angle); int addLimot (dxJoint *joint, dxJoint::Info2 *info, int row, dVector3 ax1, int rotational); }; // ball and socket struct dxJointBall : public dxJoint { dVector3 anchor1; // anchor w.r.t first body dVector3 anchor2; // anchor w.r.t second body }; extern struct dxJoint::Vtable __dball_vtable; // hinge struct dxJointHinge : public dxJoint { dVector3 anchor1; // anchor w.r.t first body dVector3 anchor2; // anchor w.r.t second body dVector3 axis1; // axis w.r.t first body dVector3 axis2; // axis w.r.t second body dQuaternion qrel; // initial relative rotation body1 -> body2 dxJointLimitMotor limot; // limit and motor information }; extern struct dxJoint::Vtable __dhinge_vtable; // universal struct dxJointUniversal : public dxJoint { dVector3 anchor1; // anchor w.r.t first body dVector3 anchor2; // anchor w.r.t second body dVector3 axis1; // axis w.r.t first body dVector3 axis2; // axis w.r.t second body dQuaternion qrel1; // initial relative rotation body1 -> virtual cross piece dQuaternion qrel2; // initial relative rotation virtual cross piece -> body2 dxJointLimitMotor limot1; // limit and motor information for axis1 dxJointLimitMotor limot2; // limit and motor information for axis2 }; extern struct dxJoint::Vtable __duniversal_vtable; // slider. if body2 is 0 then qrel is the absolute rotation of body1 and // offset is the position of body1 center along axis1. struct dxJointSlider : public dxJoint { dVector3 axis1; // axis w.r.t first body dQuaternion qrel; // initial relative rotation body1 -> body2 dVector3 offset; // point relative to body2 that should be // aligned with body1 center along axis1 dxJointLimitMotor limot; // limit and motor information }; extern struct dxJoint::Vtable __dslider_vtable; // contact struct dxJointContact : public dxJoint { int the_m; // number of rows computed by getInfo1 dContact contact; }; extern struct dxJoint::Vtable __dcontact_vtable; // hinge 2 struct dxJointHinge2 : public dxJoint { dVector3 anchor1; // anchor w.r.t first body dVector3 anchor2; // anchor w.r.t second body dVector3 axis1; // axis 1 w.r.t first body dVector3 axis2; // axis 2 w.r.t second body dReal c0,s0; // cos,sin of desired angle between axis 1,2 dVector3 v1,v2; // angle ref vectors embedded in first body dxJointLimitMotor limot1; // limit+motor info for axis 1 dxJointLimitMotor limot2; // limit+motor info for axis 2 dReal susp_erp,susp_cfm; // suspension parameters (erp,cfm) }; extern struct dxJoint::Vtable __dhinge2_vtable; // angular motor struct dxJointAMotor : public dxJoint { int num; // number of axes (0..3) int mode; // a dAMotorXXX constant int rel[3]; // what the axes are relative to (global,b1,b2) dVector3 axis[3]; // three axes dxJointLimitMotor limot[3]; // limit+motor info for axes dReal angle[3]; // user-supplied angles for axes // these vectors are used for calculating euler angles dVector3 reference1; // original axis[2], relative to body 1 dVector3 reference2; // original axis[0], relative to body 2 }; extern struct dxJoint::Vtable __damotor_vtable; // fixed struct dxJointFixed : public dxJoint { dQuaternion qrel; // initial relative rotation body1 -> body2 dVector3 offset; // relative offset between the bodies }; extern struct dxJoint::Vtable __dfixed_vtable; // null joint, for testing only struct dxJointNull : public dxJoint { }; extern struct dxJoint::Vtable __dnull_vtable; #endif ode-0.14/contrib/BreakableJoints/objects.h0000644000000000000000000002514012635011627017211 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_OBJECTS_H_ #define _ODE_OBJECTS_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /* world */ dWorldID dWorldCreate(); void dWorldDestroy (dWorldID); void dWorldSetGravity (dWorldID, dReal x, dReal y, dReal z); void dWorldGetGravity (dWorldID, dVector3 gravity); void dWorldSetERP (dWorldID, dReal erp); dReal dWorldGetERP (dWorldID); void dWorldSetCFM (dWorldID, dReal cfm); dReal dWorldGetCFM (dWorldID); void dWorldStep (dWorldID, dReal stepsize); void dWorldImpulseToForce (dWorldID, dReal stepsize, dReal ix, dReal iy, dReal iz, dVector3 force); /* StepFast1 functions */ void dWorldStepFast1(dWorldID, dReal stepsize, int maxiterations); void dWorldSetAutoEnableDepthSF1(dWorldID, int autoEnableDepth); int dWorldGetAutoEnableDepthSF1(dWorldID); void dBodySetAutoDisableThresholdSF1(dBodyID, dReal autoDisableThreshold); /* These functions are not yet implemented by ODE. */ /* dReal dBodyGetAutoDisableThresholdSF1(dBodyID); void dBodySetAutoDisableStepsSF1(dBodyID, int AutoDisableSteps); int dBodyGetAutoDisableStepsSF1(dBodyID); void dBodySetAutoDisableSF1(dBodyID, int doAutoDisable); int dBodyGetAutoDisableSF1(dBodyID); */ /* bodies */ dBodyID dBodyCreate (dWorldID); void dBodyDestroy (dBodyID); void dBodySetData (dBodyID, void *data); void *dBodyGetData (dBodyID); void dBodySetPosition (dBodyID, dReal x, dReal y, dReal z); void dBodySetRotation (dBodyID, const dMatrix3 R); void dBodySetQuaternion (dBodyID, const dQuaternion q); void dBodySetLinearVel (dBodyID, dReal x, dReal y, dReal z); void dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z); const dReal * dBodyGetPosition (dBodyID); const dReal * dBodyGetRotation (dBodyID); /* ptr to 4x3 rot matrix */ const dReal * dBodyGetQuaternion (dBodyID); const dReal * dBodyGetLinearVel (dBodyID); const dReal * dBodyGetAngularVel (dBodyID); void dBodySetMass (dBodyID, const dMass *mass); void dBodyGetMass (dBodyID, dMass *mass); void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddRelForce (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddRelTorque (dBodyID, dReal fx, dReal fy, dReal fz); void dBodyAddForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); void dBodyAddForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); void dBodyAddRelForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); void dBodyAddRelForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); const dReal * dBodyGetForce (dBodyID); const dReal * dBodyGetTorque (dBodyID); void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z); void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z); void dBodyGetRelPointPos (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyGetRelPointVel (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyGetPointVel (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyGetPosRelPoint (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyVectorToWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodyVectorFromWorld (dBodyID, dReal px, dReal py, dReal pz, dVector3 result); void dBodySetFiniteRotationMode (dBodyID, int mode); void dBodySetFiniteRotationAxis (dBodyID, dReal x, dReal y, dReal z); int dBodyGetFiniteRotationMode (dBodyID); void dBodyGetFiniteRotationAxis (dBodyID, dVector3 result); int dBodyGetNumJoints (dBodyID b); dJointID dBodyGetJoint (dBodyID, int index); void dBodyEnable (dBodyID); void dBodyDisable (dBodyID); int dBodyIsEnabled (dBodyID); void dBodySetGravityMode (dBodyID b, int mode); int dBodyGetGravityMode (dBodyID b); /* joints */ dJointID dJointCreateBall (dWorldID, dJointGroupID); dJointID dJointCreateHinge (dWorldID, dJointGroupID); dJointID dJointCreateSlider (dWorldID, dJointGroupID); dJointID dJointCreateContact (dWorldID, dJointGroupID, const dContact *); dJointID dJointCreateHinge2 (dWorldID, dJointGroupID); dJointID dJointCreateUniversal (dWorldID, dJointGroupID); dJointID dJointCreateFixed (dWorldID, dJointGroupID); dJointID dJointCreateNull (dWorldID, dJointGroupID); dJointID dJointCreateAMotor (dWorldID, dJointGroupID); void dJointDestroy (dJointID); dJointGroupID dJointGroupCreate (int max_size); void dJointGroupDestroy (dJointGroupID); void dJointGroupEmpty (dJointGroupID); void dJointAttach (dJointID, dBodyID body1, dBodyID body2); void dJointSetData (dJointID, void *data); void *dJointGetData (dJointID); int dJointGetType (dJointID); dBodyID dJointGetBody (dJointID, int index); void dJointSetFeedback (dJointID, dJointFeedback *); dJointFeedback *dJointGetFeedback (dJointID); /******************** breakable joint contribution ***********************/ void dJointSetBreakable (dJointID, int b); void dJointSetBreakCallback (dJointID, dJointBreakCallback *callbackFunc); void dJointSetBreakMode (dJointID, int mode); int dJointGetBreakMode (dJointID); void dJointSetBreakForce (dJointID, int body, dReal x, dReal y, dReal z); void dJointSetBreakTorque (dJointID, int body, dReal x, dReal y, dReal z); int dJointIsBreakable (dJointID); void dJointGetBreakForce (dJointID, int body, dReal *force); void dJointGetBreakTorque (dJointID, int body, dReal *torque); /*************************************************************************/ void dJointSetBallAnchor (dJointID, dReal x, dReal y, dReal z); void dJointSetHingeAnchor (dJointID, dReal x, dReal y, dReal z); void dJointSetHingeAxis (dJointID, dReal x, dReal y, dReal z); void dJointSetHingeParam (dJointID, int parameter, dReal value); void dJointAddHingeTorque(dJointID joint, dReal torque); void dJointSetSliderAxis (dJointID, dReal x, dReal y, dReal z); void dJointSetSliderParam (dJointID, int parameter, dReal value); void dJointAddSliderForce(dJointID joint, dReal force); void dJointSetHinge2Anchor (dJointID, dReal x, dReal y, dReal z); void dJointSetHinge2Axis1 (dJointID, dReal x, dReal y, dReal z); void dJointSetHinge2Axis2 (dJointID, dReal x, dReal y, dReal z); void dJointSetHinge2Param (dJointID, int parameter, dReal value); void dJointAddHinge2Torques(dJointID joint, dReal torque1, dReal torque2); void dJointSetUniversalAnchor (dJointID, dReal x, dReal y, dReal z); void dJointSetUniversalAxis1 (dJointID, dReal x, dReal y, dReal z); void dJointSetUniversalAxis2 (dJointID, dReal x, dReal y, dReal z); void dJointSetUniversalParam (dJointID, int parameter, dReal value); void dJointAddUniversalTorques(dJointID joint, dReal torque1, dReal torque2); void dJointSetFixed (dJointID); void dJointSetAMotorNumAxes (dJointID, int num); void dJointSetAMotorAxis (dJointID, int anum, int rel, dReal x, dReal y, dReal z); void dJointSetAMotorAngle (dJointID, int anum, dReal angle); void dJointSetAMotorParam (dJointID, int parameter, dReal value); void dJointSetAMotorMode (dJointID, int mode); void dJointAddAMotorTorques (dJointID, dReal torque1, dReal torque2, dReal torque3); void dJointGetBallAnchor (dJointID, dVector3 result); void dJointGetBallAnchor2 (dJointID, dVector3 result); void dJointGetHingeAnchor (dJointID, dVector3 result); void dJointGetHingeAnchor2 (dJointID, dVector3 result); void dJointGetHingeAxis (dJointID, dVector3 result); dReal dJointGetHingeParam (dJointID, int parameter); dReal dJointGetHingeAngle (dJointID); dReal dJointGetHingeAngleRate (dJointID); dReal dJointGetSliderPosition (dJointID); dReal dJointGetSliderPositionRate (dJointID); void dJointGetSliderAxis (dJointID, dVector3 result); dReal dJointGetSliderParam (dJointID, int parameter); void dJointGetHinge2Anchor (dJointID, dVector3 result); void dJointGetHinge2Anchor2 (dJointID, dVector3 result); void dJointGetHinge2Axis1 (dJointID, dVector3 result); void dJointGetHinge2Axis2 (dJointID, dVector3 result); dReal dJointGetHinge2Param (dJointID, int parameter); dReal dJointGetHinge2Angle1 (dJointID); dReal dJointGetHinge2Angle1Rate (dJointID); dReal dJointGetHinge2Angle2Rate (dJointID); void dJointGetUniversalAnchor (dJointID, dVector3 result); void dJointGetUniversalAnchor2 (dJointID, dVector3 result); void dJointGetUniversalAxis1 (dJointID, dVector3 result); void dJointGetUniversalAxis2 (dJointID, dVector3 result); dReal dJointGetUniversalParam (dJointID, int parameter); dReal dJointGetUniversalAngle1 (dJointID); dReal dJointGetUniversalAngle2 (dJointID); dReal dJointGetUniversalAngle1Rate (dJointID); dReal dJointGetUniversalAngle2Rate (dJointID); int dJointGetAMotorNumAxes (dJointID); void dJointGetAMotorAxis (dJointID, int anum, dVector3 result); int dJointGetAMotorAxisRel (dJointID, int anum); dReal dJointGetAMotorAngle (dJointID, int anum); dReal dJointGetAMotorAngleRate (dJointID, int anum); dReal dJointGetAMotorParam (dJointID, int parameter); int dJointGetAMotorMode (dJointID); int dAreConnected (dBodyID, dBodyID); int dAreConnectedExcluding (dBodyID, dBodyID, int joint_type); #ifdef __cplusplus } #endif #endif ode-0.14/contrib/BreakableJoints/ode.cpp0000644000000000000000000010043712635011627016665 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifdef _MSC_VER #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" #endif // this source file is mostly concerned with the data structures, not the // numerics. #include "objects.h" #include #include "joint.h" #include #include #include "step.h" #include #include // misc defines #define ALLOCA dALLOCA16 //**************************************************************************** // utility static inline void initObject (dObject *obj, dxWorld *w) { obj->world = w; obj->next = 0; obj->tome = 0; obj->userdata = 0; obj->tag = 0; } // add an object `obj' to the list who's head pointer is pointed to by `first'. static inline void addObjectToList (dObject *obj, dObject **first) { obj->next = *first; obj->tome = first; if (*first) (*first)->tome = &obj->next; (*first) = obj; } // remove the object from the linked list static inline void removeObjectFromList (dObject *obj) { if (obj->next) obj->next->tome = obj->tome; *(obj->tome) = obj->next; // safeguard obj->next = 0; obj->tome = 0; } // remove the joint from neighbour lists of all connected bodies static void removeJointReferencesFromAttachedBodies (dxJoint *j) { for (int i=0; i<2; i++) { dxBody *body = j->node[i].body; if (body) { dxJointNode *n = body->firstjoint; dxJointNode *last = 0; while (n) { if (n->joint == j) { if (last) last->next = n->next; else body->firstjoint = n->next; break; } last = n; n = n->next; } } } j->node[0].body = 0; j->node[0].next = 0; j->node[1].body = 0; j->node[1].next = 0; } //**************************************************************************** // island processing // this groups all joints and bodies in a world into islands. all objects // in an island are reachable by going through connected bodies and joints. // each island can be simulated separately. // note that joints that are not attached to anything will not be included // in any island, an so they do not affect the simulation. // // this function starts new island from unvisited bodies. however, it will // never start a new islands from a disabled body. thus islands of disabled // bodies will not be included in the simulation. disabled bodies are // re-enabled if they are found to be part of an active island. static void processIslands (dxWorld *world, dReal stepsize) { dxBody *b,*bb,**body; dxJoint *j,**joint; // nothing to do if no bodies if (world->nb <= 0) return; // make arrays for body and joint lists (for a single island) to go into body = (dxBody**) ALLOCA (world->nb * sizeof(dxBody*)); joint = (dxJoint**) ALLOCA (world->nj * sizeof(dxJoint*)); int bcount = 0; // number of bodies in `body' int jcount = 0; // number of joints in `joint' // set all body/joint tags to 0 for (b=world->firstbody; b; b=(dxBody*)b->next) b->tag = 0; for (j=world->firstjoint; j; j=(dxJoint*)j->next) j->tag = 0; // allocate a stack of unvisited bodies in the island. the maximum size of // the stack can be the lesser of the number of bodies or joints, because // new bodies are only ever added to the stack by going through untagged // joints. all the bodies in the stack must be tagged! int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; dxBody **stack = (dxBody**) ALLOCA (stackalloc * sizeof(dxBody*)); for (bb=world->firstbody; bb; bb=(dxBody*)bb->next) { // get bb = the next enabled, untagged body, and tag it if (bb->tag || (bb->flags & dxBodyDisabled)) continue; bb->tag = 1; // tag all bodies and joints starting from bb. int stacksize = 0; b = bb; body[0] = bb; bcount = 1; jcount = 0; goto quickstart; while (stacksize > 0) { b = stack[--stacksize]; // pop body off stack body[bcount++] = b; // put body on body list quickstart: // traverse and tag all body's joints, add untagged connected bodies // to stack for (dxJointNode *n=b->firstjoint; n; n=n->next) { if (!n->joint->tag) { n->joint->tag = 1; joint[jcount++] = n->joint; if (n->body && !n->body->tag) { n->body->tag = 1; stack[stacksize++] = n->body; } } } dIASSERT(stacksize <= world->nb); dIASSERT(stacksize <= world->nj); } // now do something with body and joint lists dInternalStepIsland (world,body,bcount,joint,jcount,stepsize); // what we've just done may have altered the body/joint tag values. // we must make sure that these tags are nonzero. // also make sure all bodies are in the enabled state. int i; for (i=0; itag = 1; body[i]->flags &= ~dxBodyDisabled; } for (i=0; itag = 1; } // if debugging, check that all objects (except for disabled bodies, // unconnected joints, and joints that are connected to disabled bodies) // were tagged. # ifndef dNODEBUG for (b=world->firstbody; b; b=(dxBody*)b->next) { if (b->flags & dxBodyDisabled) { if (b->tag) dDebug (0,"disabled body tagged"); } else { if (!b->tag) dDebug (0,"enabled body not tagged"); } } for (j=world->firstjoint; j; j=(dxJoint*)j->next) { if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled)==0) || (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled)==0)) { if (!j->tag) dDebug (0,"attached enabled joint not tagged"); } else { if (j->tag) dDebug (0,"unattached or disabled joint tagged"); } } # endif /******************** breakable joint contribution ***********************/ dxJoint* nextJ; if (!world->firstjoint) nextJ = 0; else nextJ = (dxJoint*)world->firstjoint->next; for (j=world->firstjoint; j; j=nextJ) { nextJ = (dxJoint*)j->next; // check if joint is breakable and broken if (j->breakInfo && j->breakInfo->flags & dJOINT_BROKEN) { // detach (break) the joint dJointAttach (j, 0, 0); // call the callback function if it is set if (j->breakInfo->callback) j->breakInfo->callback (j); // finally destroy the joint if the dJOINT_DELETE_ON_BREAK is set if (j->breakInfo->flags & dJOINT_DELETE_ON_BREAK) dJointDestroy (j); } } /*************************************************************************/ } //**************************************************************************** // debugging // see if an object list loops on itself (if so, it's bad). static int listHasLoops (dObject *first) { if (first==0 || first->next==0) return 0; dObject *a=first,*b=first->next; int skip=0; while (b) { if (a==b) return 1; b = b->next; if (skip) a = a->next; skip ^= 1; } return 0; } // check the validity of the world data structures static void checkWorld (dxWorld *w) { dxBody *b; dxJoint *j; // check there are no loops if (listHasLoops (w->firstbody)) dDebug (0,"body list has loops"); if (listHasLoops (w->firstjoint)) dDebug (0,"joint list has loops"); // check lists are well formed (check `tome' pointers) for (b=w->firstbody; b; b=(dxBody*)b->next) { if (b->next && b->next->tome != &b->next) dDebug (0,"bad tome pointer in body list"); } for (j=w->firstjoint; j; j=(dxJoint*)j->next) { if (j->next && j->next->tome != &j->next) dDebug (0,"bad tome pointer in joint list"); } // check counts int n = 0; for (b=w->firstbody; b; b=(dxBody*)b->next) n++; if (w->nb != n) dDebug (0,"body count incorrect"); n = 0; for (j=w->firstjoint; j; j=(dxJoint*)j->next) n++; if (w->nj != n) dDebug (0,"joint count incorrect"); // set all tag values to a known value static int count = 0; count++; for (b=w->firstbody; b; b=(dxBody*)b->next) b->tag = count; for (j=w->firstjoint; j; j=(dxJoint*)j->next) j->tag = count; // check all body/joint world pointers are ok for (b=w->firstbody; b; b=(dxBody*)b->next) if (b->world != w) dDebug (0,"bad world pointer in body list"); for (j=w->firstjoint; j; j=(dxJoint*)j->next) if (j->world != w) dDebug (0,"bad world pointer in joint list"); /* // check for half-connected joints - actually now these are valid for (j=w->firstjoint; j; j=(dxJoint*)j->next) { if (j->node[0].body || j->node[1].body) { if (!(j->node[0].body && j->node[1].body)) dDebug (0,"half connected joint found"); } } */ // check that every joint node appears in the joint lists of both bodies it // attaches for (j=w->firstjoint; j; j=(dxJoint*)j->next) { for (int i=0; i<2; i++) { if (j->node[i].body) { int ok = 0; for (dxJointNode *n=j->node[i].body->firstjoint; n; n=n->next) { if (n->joint == j) ok = 1; } if (ok==0) dDebug (0,"joint not in joint list of attached body"); } } } // check all body joint lists (correct body ptrs) for (b=w->firstbody; b; b=(dxBody*)b->next) { for (dxJointNode *n=b->firstjoint; n; n=n->next) { if (&n->joint->node[0] == n) { if (n->joint->node[1].body != b) dDebug (0,"bad body pointer in joint node of body list (1)"); } else { if (n->joint->node[0].body != b) dDebug (0,"bad body pointer in joint node of body list (2)"); } if (n->joint->tag != count) dDebug (0,"bad joint node pointer in body"); } } // check all body pointers in joints, check they are distinct for (j=w->firstjoint; j; j=(dxJoint*)j->next) { if (j->node[0].body && (j->node[0].body == j->node[1].body)) dDebug (0,"non-distinct body pointers in joint"); if ((j->node[0].body && j->node[0].body->tag != count) || (j->node[1].body && j->node[1].body->tag != count)) dDebug (0,"bad body pointer in joint"); } } void dWorldCheck (dxWorld *w) { checkWorld (w); } //**************************************************************************** // body dxBody *dBodyCreate (dxWorld *w) { dAASSERT (w); dxBody *b = new dxBody; initObject (b,w); b->firstjoint = 0; b->flags = 0; b->geom = 0; dMassSetParameters (&b->mass,1,0,0,0,1,1,1,0,0,0); dSetZero (b->invI,4*3); b->invI[0] = 1; b->invI[5] = 1; b->invI[10] = 1; b->invMass = 1; dSetZero (b->pos,4); dSetZero (b->q,4); b->q[0] = 1; dRSetIdentity (b->R); dSetZero (b->lvel,4); dSetZero (b->avel,4); dSetZero (b->facc,4); dSetZero (b->tacc,4); dSetZero (b->finite_rot_axis,4); addObjectToList (b,(dObject **) &w->firstbody); w->nb++; return b; } void dBodyDestroy (dxBody *b) { dAASSERT (b); // all geoms that link to this body must be notified that the body is about // to disappear. note that the call to dGeomSetBody(geom,0) will result in // dGeomGetBodyNext() returning 0 for the body, so we must get the next body // before setting the body to 0. dxGeom *next_geom = 0; for (dxGeom *geom = b->geom; geom; geom = next_geom) { next_geom = dGeomGetBodyNext (geom); dGeomSetBody (geom,0); } // detach all neighbouring joints, then delete this body. dxJointNode *n = b->firstjoint; while (n) { // sneaky trick to speed up removal of joint references (black magic) n->joint->node[(n == n->joint->node)].body = 0; dxJointNode *next = n->next; n->next = 0; removeJointReferencesFromAttachedBodies (n->joint); n = next; } removeObjectFromList (b); b->world->nb--; delete b; } void dBodySetData (dBodyID b, void *data) { dAASSERT (b); b->userdata = data; } void *dBodyGetData (dBodyID b) { dAASSERT (b); return b->userdata; } void dBodySetPosition (dBodyID b, dReal x, dReal y, dReal z) { dAASSERT (b); b->pos[0] = x; b->pos[1] = y; b->pos[2] = z; // notify all attached geoms that this body has moved for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) dGeomMoved (geom); } void dBodySetRotation (dBodyID b, const dMatrix3 R) { dAASSERT (b && R); dQuaternion q; dRtoQ (R,q); dNormalize4 (q); b->q[0] = q[0]; b->q[1] = q[1]; b->q[2] = q[2]; b->q[3] = q[3]; dQtoR (b->q,b->R); // notify all attached geoms that this body has moved for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) dGeomMoved (geom); } void dBodySetQuaternion (dBodyID b, const dQuaternion q) { dAASSERT (b && q); b->q[0] = q[0]; b->q[1] = q[1]; b->q[2] = q[2]; b->q[3] = q[3]; dNormalize4 (b->q); dQtoR (b->q,b->R); // notify all attached geoms that this body has moved for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) dGeomMoved (geom); } void dBodySetLinearVel (dBodyID b, dReal x, dReal y, dReal z) { dAASSERT (b); b->lvel[0] = x; b->lvel[1] = y; b->lvel[2] = z; } void dBodySetAngularVel (dBodyID b, dReal x, dReal y, dReal z) { dAASSERT (b); b->avel[0] = x; b->avel[1] = y; b->avel[2] = z; } const dReal * dBodyGetPosition (dBodyID b) { dAASSERT (b); return b->pos; } const dReal * dBodyGetRotation (dBodyID b) { dAASSERT (b); return b->R; } const dReal * dBodyGetQuaternion (dBodyID b) { dAASSERT (b); return b->q; } const dReal * dBodyGetLinearVel (dBodyID b) { dAASSERT (b); return b->lvel; } const dReal * dBodyGetAngularVel (dBodyID b) { dAASSERT (b); return b->avel; } void dBodySetMass (dBodyID b, const dMass *mass) { dAASSERT (b && mass); memcpy (&b->mass,mass,sizeof(dMass)); if (dInvertPDMatrix (b->mass.I,b->invI,3)==0) { dDEBUGMSG ("inertia must be positive definite"); dRSetIdentity (b->invI); } b->invMass = dRecip(b->mass.mass); } void dBodyGetMass (dBodyID b, dMass *mass) { dAASSERT (b && mass); memcpy (mass,&b->mass,sizeof(dMass)); } void dBodyAddForce (dBodyID b, dReal fx, dReal fy, dReal fz) { dAASSERT (b); b->facc[0] += fx; b->facc[1] += fy; b->facc[2] += fz; } void dBodyAddTorque (dBodyID b, dReal fx, dReal fy, dReal fz) { dAASSERT (b); b->tacc[0] += fx; b->tacc[1] += fy; b->tacc[2] += fz; } void dBodyAddRelForce (dBodyID b, dReal fx, dReal fy, dReal fz) { dAASSERT (b); dVector3 t1,t2; t1[0] = fx; t1[1] = fy; t1[2] = fz; t1[3] = 0; dMULTIPLY0_331 (t2,b->R,t1); b->facc[0] += t2[0]; b->facc[1] += t2[1]; b->facc[2] += t2[2]; } void dBodyAddRelTorque (dBodyID b, dReal fx, dReal fy, dReal fz) { dAASSERT (b); dVector3 t1,t2; t1[0] = fx; t1[1] = fy; t1[2] = fz; t1[3] = 0; dMULTIPLY0_331 (t2,b->R,t1); b->tacc[0] += t2[0]; b->tacc[1] += t2[1]; b->tacc[2] += t2[2]; } void dBodyAddForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dAASSERT (b); b->facc[0] += fx; b->facc[1] += fy; b->facc[2] += fz; dVector3 f,q; f[0] = fx; f[1] = fy; f[2] = fz; q[0] = px - b->pos[0]; q[1] = py - b->pos[1]; q[2] = pz - b->pos[2]; dCROSS (b->tacc,+=,q,f); } void dBodyAddForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dAASSERT (b); dVector3 prel,f,p; f[0] = fx; f[1] = fy; f[2] = fz; f[3] = 0; prel[0] = px; prel[1] = py; prel[2] = pz; prel[3] = 0; dMULTIPLY0_331 (p,b->R,prel); b->facc[0] += f[0]; b->facc[1] += f[1]; b->facc[2] += f[2]; dCROSS (b->tacc,+=,p,f); } void dBodyAddRelForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dAASSERT (b); dVector3 frel,f; frel[0] = fx; frel[1] = fy; frel[2] = fz; frel[3] = 0; dMULTIPLY0_331 (f,b->R,frel); b->facc[0] += f[0]; b->facc[1] += f[1]; b->facc[2] += f[2]; dVector3 q; q[0] = px - b->pos[0]; q[1] = py - b->pos[1]; q[2] = pz - b->pos[2]; dCROSS (b->tacc,+=,q,f); } void dBodyAddRelForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dAASSERT (b); dVector3 frel,prel,f,p; frel[0] = fx; frel[1] = fy; frel[2] = fz; frel[3] = 0; prel[0] = px; prel[1] = py; prel[2] = pz; prel[3] = 0; dMULTIPLY0_331 (f,b->R,frel); dMULTIPLY0_331 (p,b->R,prel); b->facc[0] += f[0]; b->facc[1] += f[1]; b->facc[2] += f[2]; dCROSS (b->tacc,+=,p,f); } const dReal * dBodyGetForce (dBodyID b) { dAASSERT (b); return b->facc; } const dReal * dBodyGetTorque (dBodyID b) { dAASSERT (b); return b->tacc; } void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z) { dAASSERT (b); b->facc[0] = x; b->facc[1] = y; b->facc[2] = z; } void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z) { dAASSERT (b); b->tacc[0] = x; b->tacc[1] = y; b->tacc[2] = z; } void dBodyGetRelPointPos (dBodyID b, dReal px, dReal py, dReal pz, dVector3 result) { dAASSERT (b); dVector3 prel,p; prel[0] = px; prel[1] = py; prel[2] = pz; prel[3] = 0; dMULTIPLY0_331 (p,b->R,prel); result[0] = p[0] + b->pos[0]; result[1] = p[1] + b->pos[1]; result[2] = p[2] + b->pos[2]; } void dBodyGetRelPointVel (dBodyID b, dReal px, dReal py, dReal pz, dVector3 result) { dAASSERT (b); dVector3 prel,p; prel[0] = px; prel[1] = py; prel[2] = pz; prel[3] = 0; dMULTIPLY0_331 (p,b->R,prel); result[0] = b->lvel[0]; result[1] = b->lvel[1]; result[2] = b->lvel[2]; dCROSS (result,+=,b->avel,p); } void dBodyGetPointVel (dBodyID b, dReal px, dReal py, dReal pz, dVector3 result) { dAASSERT (b); dVector3 p; p[0] = px - b->pos[0]; p[1] = py - b->pos[1]; p[2] = pz - b->pos[2]; p[3] = 0; result[0] = b->lvel[0]; result[1] = b->lvel[1]; result[2] = b->lvel[2]; dCROSS (result,+=,b->avel,p); } void dBodyGetPosRelPoint (dBodyID b, dReal px, dReal py, dReal pz, dVector3 result) { dAASSERT (b); dVector3 prel; prel[0] = px - b->pos[0]; prel[1] = py - b->pos[1]; prel[2] = pz - b->pos[2]; prel[3] = 0; dMULTIPLY1_331 (result,b->R,prel); } void dBodyVectorToWorld (dBodyID b, dReal px, dReal py, dReal pz, dVector3 result) { dAASSERT (b); dVector3 p; p[0] = px; p[1] = py; p[2] = pz; p[3] = 0; dMULTIPLY0_331 (result,b->R,p); } void dBodyVectorFromWorld (dBodyID b, dReal px, dReal py, dReal pz, dVector3 result) { dAASSERT (b); dVector3 p; p[0] = px; p[1] = py; p[2] = pz; p[3] = 0; dMULTIPLY1_331 (result,b->R,p); } void dBodySetFiniteRotationMode (dBodyID b, int mode) { dAASSERT (b); b->flags &= ~(dxBodyFlagFiniteRotation | dxBodyFlagFiniteRotationAxis); if (mode) { b->flags |= dxBodyFlagFiniteRotation; if (b->finite_rot_axis[0] != 0 || b->finite_rot_axis[1] != 0 || b->finite_rot_axis[2] != 0) { b->flags |= dxBodyFlagFiniteRotationAxis; } } } void dBodySetFiniteRotationAxis (dBodyID b, dReal x, dReal y, dReal z) { dAASSERT (b); b->finite_rot_axis[0] = x; b->finite_rot_axis[1] = y; b->finite_rot_axis[2] = z; if (x != 0 || y != 0 || z != 0) { dNormalize3 (b->finite_rot_axis); b->flags |= dxBodyFlagFiniteRotationAxis; } else { b->flags &= ~dxBodyFlagFiniteRotationAxis; } } int dBodyGetFiniteRotationMode (dBodyID b) { dAASSERT (b); return ((b->flags & dxBodyFlagFiniteRotation) != 0); } void dBodyGetFiniteRotationAxis (dBodyID b, dVector3 result) { dAASSERT (b); result[0] = b->finite_rot_axis[0]; result[1] = b->finite_rot_axis[1]; result[2] = b->finite_rot_axis[2]; } int dBodyGetNumJoints (dBodyID b) { dAASSERT (b); int count=0; for (dxJointNode *n=b->firstjoint; n; n=n->next, count++); return count; } dJointID dBodyGetJoint (dBodyID b, int index) { dAASSERT (b); int i=0; for (dxJointNode *n=b->firstjoint; n; n=n->next, i++) { if (i == index) return n->joint; } return 0; } void dBodyEnable (dBodyID b) { dAASSERT (b); b->flags &= ~dxBodyDisabled; } void dBodyDisable (dBodyID b) { dAASSERT (b); b->flags |= dxBodyDisabled; } int dBodyIsEnabled (dBodyID b) { dAASSERT (b); return ((b->flags & dxBodyDisabled) == 0); } void dBodySetGravityMode (dBodyID b, int mode) { dAASSERT (b); if (mode) b->flags &= ~dxBodyNoGravity; else b->flags |= dxBodyNoGravity; } int dBodyGetGravityMode (dBodyID b) { dAASSERT (b); return ((b->flags & dxBodyNoGravity) == 0); } //**************************************************************************** // joints static void dJointInit (dxWorld *w, dxJoint *j) { dIASSERT (w && j); initObject (j,w); j->vtable = 0; j->flags = 0; j->node[0].joint = j; j->node[0].body = 0; j->node[0].next = 0; j->node[1].joint = j; j->node[1].body = 0; j->node[1].next = 0; addObjectToList (j,(dObject **) &w->firstjoint); w->nj++; } static dxJoint *createJoint (dWorldID w, dJointGroupID group, dxJoint::Vtable *vtable) { dIASSERT (w && vtable); dxJoint *j; if (group) { j = (dxJoint*) group->stack.alloc (vtable->size); group->num++; } else j = (dxJoint*) dAlloc (vtable->size); dJointInit (w,j); j->vtable = vtable; if (group) j->flags |= dJOINT_INGROUP; if (vtable->init) vtable->init (j); j->feedback = 0; /******************** breakable joint contribution ***********************/ j->breakInfo = 0; /*************************************************************************/ return j; } dxJoint * dJointCreateBall (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__dball_vtable); } dxJoint * dJointCreateHinge (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__dhinge_vtable); } dxJoint * dJointCreateSlider (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__dslider_vtable); } dxJoint * dJointCreateContact (dWorldID w, dJointGroupID group, const dContact *c) { dAASSERT (w && c); dxJointContact *j = (dxJointContact *) createJoint (w,group,&__dcontact_vtable); j->contact = *c; return j; } dxJoint * dJointCreateHinge2 (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__dhinge2_vtable); } dxJoint * dJointCreateUniversal (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__duniversal_vtable); } dxJoint * dJointCreateFixed (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__dfixed_vtable); } dxJoint * dJointCreateNull (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__dnull_vtable); } dxJoint * dJointCreateAMotor (dWorldID w, dJointGroupID group) { dAASSERT (w); return createJoint (w,group,&__damotor_vtable); } void dJointDestroy (dxJoint *j) { dAASSERT (j); if (j->flags & dJOINT_INGROUP) return; removeJointReferencesFromAttachedBodies (j); removeObjectFromList (j); /******************** breakable joint contribution ***********************/ if (j->breakInfo) delete j->breakInfo; /*************************************************************************/ j->world->nj--; dFree (j,j->vtable->size); } dJointGroupID dJointGroupCreate (int max_size) { // not any more ... dUASSERT (max_size > 0,"max size must be > 0"); dxJointGroup *group = new dxJointGroup; group->num = 0; return group; } void dJointGroupDestroy (dJointGroupID group) { dAASSERT (group); dJointGroupEmpty (group); delete group; } void dJointGroupEmpty (dJointGroupID group) { // the joints in this group are detached starting from the most recently // added (at the top of the stack). this helps ensure that the various // linked lists are not traversed too much, as the joints will hopefully // be at the start of those lists. // if any group joints have their world pointer set to 0, their world was // previously destroyed. no special handling is required for these joints. dAASSERT (group); int i; dxJoint **jlist = (dxJoint**) ALLOCA (group->num * sizeof(dxJoint*)); dxJoint *j = (dxJoint*) group->stack.rewind(); for (i=0; i < group->num; i++) { jlist[i] = j; j = (dxJoint*) (group->stack.next (j->vtable->size)); } for (i=group->num-1; i >= 0; i--) { if (jlist[i]->world) { removeJointReferencesFromAttachedBodies (jlist[i]); removeObjectFromList (jlist[i]); jlist[i]->world->nj--; } } group->num = 0; group->stack.freeAll(); } void dJointAttach (dxJoint *joint, dxBody *body1, dxBody *body2) { // check arguments dUASSERT (joint,"bad joint argument"); dUASSERT (body1 == 0 || body1 != body2,"can't have body1==body2"); dxWorld *world = joint->world; dUASSERT ( (!body1 || body1->world == world) && (!body2 || body2->world == world), "joint and bodies must be in same world"); // check if the joint can not be attached to just one body dUASSERT (!((joint->flags & dJOINT_TWOBODIES) && ((body1 != 0) ^ (body2 != 0))), "joint can not be attached to just one body"); // remove any existing body attachments if (joint->node[0].body || joint->node[1].body) { removeJointReferencesFromAttachedBodies (joint); } // if a body is zero, make sure that it is body2, so 0 --> node[1].body if (body1==0) { body1 = body2; body2 = 0; joint->flags |= dJOINT_REVERSE; } else { joint->flags &= (~dJOINT_REVERSE); } // attach to new bodies joint->node[0].body = body1; joint->node[1].body = body2; if (body1) { joint->node[1].next = body1->firstjoint; body1->firstjoint = &joint->node[1]; } else joint->node[1].next = 0; if (body2) { joint->node[0].next = body2->firstjoint; body2->firstjoint = &joint->node[0]; } else { joint->node[0].next = 0; } } void dJointSetData (dxJoint *joint, void *data) { dAASSERT (joint); joint->userdata = data; } void *dJointGetData (dxJoint *joint) { dAASSERT (joint); return joint->userdata; } int dJointGetType (dxJoint *joint) { dAASSERT (joint); return joint->vtable->typenum; } dBodyID dJointGetBody (dxJoint *joint, int index) { dAASSERT (joint); if (index >= 0 && index < 2) return joint->node[index].body; else return 0; } void dJointSetFeedback (dxJoint *joint, dJointFeedback *f) { dAASSERT (joint); joint->feedback = f; } dJointFeedback *dJointGetFeedback (dxJoint *joint) { dAASSERT (joint); return joint->feedback; } int dAreConnected (dBodyID b1, dBodyID b2) { dAASSERT (b1 && b2); // look through b1's neighbour list for b2 for (dxJointNode *n=b1->firstjoint; n; n=n->next) { if (n->body == b2) return 1; } return 0; } int dAreConnectedExcluding (dBodyID b1, dBodyID b2, int joint_type) { dAASSERT (b1 && b2); // look through b1's neighbour list for b2 for (dxJointNode *n=b1->firstjoint; n; n=n->next) { if (dJointGetType (n->joint) != joint_type && n->body == b2) return 1; } return 0; } //**************************************************************************** // world dxWorld * dWorldCreate() { dxWorld *w = new dxWorld; w->firstbody = 0; w->firstjoint = 0; w->nb = 0; w->nj = 0; dSetZero (w->gravity,4); w->global_erp = REAL(0.2); #if defined(dSINGLE) w->global_cfm = 1e-5f; #elif defined(dDOUBLE) w->global_cfm = 1e-10; #else #error dSINGLE or dDOUBLE must be defined #endif return w; } void dWorldDestroy (dxWorld *w) { // delete all bodies and joints dAASSERT (w); dxBody *nextb, *b = w->firstbody; while (b) { nextb = (dxBody*) b->next; delete b; b = nextb; } dxJoint *nextj, *j = w->firstjoint; while (j) { nextj = (dxJoint*)j->next; if (j->flags & dJOINT_INGROUP) { // the joint is part of a group, so "deactivate" it instead j->world = 0; j->node[0].body = 0; j->node[0].next = 0; j->node[1].body = 0; j->node[1].next = 0; dMessage (0,"warning: destroying world containing grouped joints"); } else { dFree (j,j->vtable->size); } j = nextj; } delete w; } void dWorldSetGravity (dWorldID w, dReal x, dReal y, dReal z) { dAASSERT (w); w->gravity[0] = x; w->gravity[1] = y; w->gravity[2] = z; } void dWorldGetGravity (dWorldID w, dVector3 g) { dAASSERT (w); g[0] = w->gravity[0]; g[1] = w->gravity[1]; g[2] = w->gravity[2]; } void dWorldSetERP (dWorldID w, dReal erp) { dAASSERT (w); w->global_erp = erp; } dReal dWorldGetERP (dWorldID w) { dAASSERT (w); return w->global_erp; } void dWorldSetCFM (dWorldID w, dReal cfm) { dAASSERT (w); w->global_cfm = cfm; } dReal dWorldGetCFM (dWorldID w) { dAASSERT (w); return w->global_cfm; } void dWorldStep (dWorldID w, dReal stepsize) { dUASSERT (w,"bad world argument"); dUASSERT (stepsize > 0,"stepsize must be > 0"); processIslands (w,stepsize); } void dWorldImpulseToForce (dWorldID w, dReal stepsize, dReal ix, dReal iy, dReal iz, dVector3 force) { dAASSERT (w); stepsize = dRecip(stepsize); force[0] = stepsize * ix; force[1] = stepsize * iy; force[2] = stepsize * iz; // @@@ force[3] = 0; } //**************************************************************************** // testing #define NUM 100 #define DO(x) extern "C" void dTestDataStructures() { int i; DO(printf ("testDynamicsStuff()\n")); dBodyID body [NUM]; int nb = 0; dJointID joint [NUM]; int nj = 0; for (i=0; i 0.5) { DO(printf ("creating body\n")); body[nb] = dBodyCreate (w); DO(printf ("\t--> %p\n",body[nb])); nb++; checkWorld (w); DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); } if (nj < NUM && nb > 2 && dRandReal() > 0.5) { dBodyID b1 = body [dRand() % nb]; dBodyID b2 = body [dRand() % nb]; if (b1 != b2) { DO(printf ("creating joint, attaching to %p,%p\n",b1,b2)); joint[nj] = dJointCreateBall (w,0); DO(printf ("\t-->%p\n",joint[nj])); checkWorld (w); dJointAttach (joint[nj],b1,b2); nj++; checkWorld (w); DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); } } if (nj > 0 && nb > 2 && dRandReal() > 0.5) { dBodyID b1 = body [dRand() % nb]; dBodyID b2 = body [dRand() % nb]; if (b1 != b2) { int k = dRand() % nj; DO(printf ("reattaching joint %p\n",joint[k])); dJointAttach (joint[k],b1,b2); checkWorld (w); DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); } } if (nb > 0 && dRandReal() > 0.5) { int k = dRand() % nb; DO(printf ("destroying body %p\n",body[k])); dBodyDestroy (body[k]); checkWorld (w); for (; k < (NUM-1); k++) body[k] = body[k+1]; nb--; DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); } if (nj > 0 && dRandReal() > 0.5) { int k = dRand() % nj; DO(printf ("destroying joint %p\n",joint[k])); dJointDestroy (joint[k]); checkWorld (w); for (; k < (NUM-1); k++) joint[k] = joint[k+1]; nj--; DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); } } /* printf ("creating world\n"); dWorldID w = dWorldCreate(); checkWorld (w); printf ("creating body\n"); dBodyID b1 = dBodyCreate (w); checkWorld (w); printf ("creating body\n"); dBodyID b2 = dBodyCreate (w); checkWorld (w); printf ("creating joint\n"); dJointID j = dJointCreateBall (w); checkWorld (w); printf ("attaching joint\n"); dJointAttach (j,b1,b2); checkWorld (w); printf ("destroying joint\n"); dJointDestroy (j); checkWorld (w); printf ("destroying body\n"); dBodyDestroy (b1); checkWorld (w); printf ("destroying body\n"); dBodyDestroy (b2); checkWorld (w); printf ("destroying world\n"); dWorldDestroy (w); */ } ode-0.14/contrib/BreakableJoints/step.cpp0000644000000000000000000011046512635011627017073 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include "objects.h" #include "joint.h" #include #include #include #include #include #include #include "lcp.h" //**************************************************************************** // misc defines #define FAST_FACTOR //#define TIMING #define ALLOCA dALLOCA16 //**************************************************************************** // debugging - comparison of various vectors and matrices produced by the // slow and fast versions of the stepper. //#define COMPARE_METHODS #ifdef COMPARE_METHODS #include "testing.h" dMatrixComparison comparator; #endif //**************************************************************************** // special matrix multipliers // this assumes the 4th and 8th rows of B and C are zero. static void Multiply2_p8r (dReal *A, dReal *B, dReal *C, int p, int r, int Askip) { int i,j; dReal sum,*bb,*cc; dIASSERT (p>0 && r>0 && A && B && C); bb = B; for (i=p; i; i--) { cc = C; for (j=r; j; j--) { sum = bb[0]*cc[0]; sum += bb[1]*cc[1]; sum += bb[2]*cc[2]; sum += bb[4]*cc[4]; sum += bb[5]*cc[5]; sum += bb[6]*cc[6]; *(A++) = sum; cc += 8; } A += Askip - r; bb += 8; } } // this assumes the 4th and 8th rows of B and C are zero. static void MultiplyAdd2_p8r (dReal *A, dReal *B, dReal *C, int p, int r, int Askip) { int i,j; dReal sum,*bb,*cc; dIASSERT (p>0 && r>0 && A && B && C); bb = B; for (i=p; i; i--) { cc = C; for (j=r; j; j--) { sum = bb[0]*cc[0]; sum += bb[1]*cc[1]; sum += bb[2]*cc[2]; sum += bb[4]*cc[4]; sum += bb[5]*cc[5]; sum += bb[6]*cc[6]; *(A++) += sum; cc += 8; } A += Askip - r; bb += 8; } } // this assumes the 4th and 8th rows of B are zero. static void Multiply0_p81 (dReal *A, dReal *B, dReal *C, int p) { int i; dIASSERT (p>0 && A && B && C); dReal sum; for (i=p; i; i--) { sum = B[0]*C[0]; sum += B[1]*C[1]; sum += B[2]*C[2]; sum += B[4]*C[4]; sum += B[5]*C[5]; sum += B[6]*C[6]; *(A++) = sum; B += 8; } } // this assumes the 4th and 8th rows of B are zero. static void MultiplyAdd0_p81 (dReal *A, dReal *B, dReal *C, int p) { int i; dIASSERT (p>0 && A && B && C); dReal sum; for (i=p; i; i--) { sum = B[0]*C[0]; sum += B[1]*C[1]; sum += B[2]*C[2]; sum += B[4]*C[4]; sum += B[5]*C[5]; sum += B[6]*C[6]; *(A++) += sum; B += 8; } } // this assumes the 4th and 8th rows of B are zero. static void MultiplyAdd1_8q1 (dReal *A, dReal *B, dReal *C, int q) { int k; dReal sum; dIASSERT (q>0 && A && B && C); sum = 0; for (k=0; k0 && A && B && C); sum = 0; for (k=0; kpos[j] += h * b->lvel[j]; if (b->flags & dxBodyFlagFiniteRotation) { dVector3 irv; // infitesimal rotation vector dQuaternion q; // quaternion for finite rotation if (b->flags & dxBodyFlagFiniteRotationAxis) { // split the angular velocity vector into a component along the finite // rotation axis, and a component orthogonal to it. dVector3 frv,irv; // finite rotation vector dReal k = dDOT (b->finite_rot_axis,b->avel); frv[0] = b->finite_rot_axis[0] * k; frv[1] = b->finite_rot_axis[1] * k; frv[2] = b->finite_rot_axis[2] * k; irv[0] = b->avel[0] - frv[0]; irv[1] = b->avel[1] - frv[1]; irv[2] = b->avel[2] - frv[2]; // make a rotation quaternion q that corresponds to frv * h. // compare this with the full-finite-rotation case below. h *= REAL(0.5); dReal theta = k * h; q[0] = dCos(theta); dReal s = sinc(theta) * h; q[1] = frv[0] * s; q[2] = frv[1] * s; q[3] = frv[2] * s; } else { // make a rotation quaternion q that corresponds to w * h dReal wlen = dSqrt (b->avel[0]*b->avel[0] + b->avel[1]*b->avel[1] + b->avel[2]*b->avel[2]); h *= REAL(0.5); dReal theta = wlen * h; q[0] = dCos(theta); dReal s = sinc(theta) * h; q[1] = b->avel[0] * s; q[2] = b->avel[1] * s; q[3] = b->avel[2] * s; } // do the finite rotation dQuaternion q2; dQMultiply0 (q2,q,b->q); for (j=0; j<4; j++) b->q[j] = q2[j]; // do the infitesimal rotation if required if (b->flags & dxBodyFlagFiniteRotationAxis) { dReal dq[4]; dWtoDQ (irv,b->q,dq); for (j=0; j<4; j++) b->q[j] += h * dq[j]; } } else { // the normal way - do an infitesimal rotation dReal dq[4]; dWtoDQ (b->avel,b->q,dq); for (j=0; j<4; j++) b->q[j] += h * dq[j]; } // normalize the quaternion and convert it to a rotation matrix dNormalize4 (b->q); dQtoR (b->q,b->R); // notify all attached geoms that this body has moved for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) dGeomMoved (geom); } //**************************************************************************** // the slow, but sure way // note that this does not do any joint feedback! // given lists of bodies and joints that form an island, perform a first // order timestep. // // `body' is the body array, `nb' is the size of the array. // `_joint' is the body array, `nj' is the size of the array. void dInternalStepIsland_x1 (dxWorld *world, dxBody * const *body, int nb, dxJoint * const *_joint, int nj, dReal stepsize) { int i,j,k; int n6 = 6*nb; # ifdef TIMING dTimerStart("preprocessing"); # endif // number all bodies in the body list - set their tag values for (i=0; itag = i; // make a local copy of the joint array, because we might want to modify it. // (the "dxJoint *const*" declaration says we're allowed to modify the joints // but not the joint array, because the caller might need it unchanged). dxJoint **joint = (dxJoint**) ALLOCA (nj * sizeof(dxJoint*)); memcpy (joint,_joint,nj * sizeof(dxJoint*)); // for all bodies, compute the inertia tensor and its inverse in the global // frame, and compute the rotational force and add it to the torque // accumulator. // @@@ check computation of rotational force. dReal *I = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); dReal *invI = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); //dSetZero (I,3*nb*4); //dSetZero (invI,3*nb*4); for (i=0; imass.I,body[i]->R); dMULTIPLY0_333 (I+i*12,body[i]->R,tmp); // compute inverse inertia tensor in global frame dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->R); dMULTIPLY0_333 (invI+i*12,body[i]->R,tmp); // compute rotational force dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); } // add the gravity force to all bodies for (i=0; iflags & dxBodyNoGravity)==0) { body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; } } // get m = total constraint dimension, nub = number of unbounded variables. // create constraint offset array and number-of-rows array for all joints. // the constraints are re-ordered as follows: the purely unbounded // constraints, the mixed unbounded + LCP constraints, and last the purely // LCP constraints. // // joints with m=0 are inactive and are removed from the joints array // entirely, so that the code that follows does not consider them. int m = 0; dxJoint::Info1 *info = (dxJoint::Info1*) ALLOCA (nj*sizeof(dxJoint::Info1)); int *ofs = (int*) ALLOCA (nj*sizeof(int)); for (i=0, j=0; jvtable->getInfo1 (joint[j],info+i); dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); if (info[i].m > 0) { joint[i] = joint[j]; i++; } } nj = i; // the purely unbounded constraints for (i=0; i 0 && info[i].nub < info[i].m) { ofs[i] = m; m += info[i].m; } // the purely LCP constraints for (i=0; iinvMass; MM[nskip+1] = body[i]->invMass; MM[2*nskip+2] = body[i]->invMass; MM += 3*nskip+3; for (j=0; j<3; j++) for (k=0; k<3; k++) { MM[j*nskip+k] = invI[i*12+j*4+k]; } } // assemble some body vectors: fe = external forces, v = velocities dReal *fe = (dReal*) ALLOCA (n6 * sizeof(dReal)); dReal *v = (dReal*) ALLOCA (n6 * sizeof(dReal)); //dSetZero (fe,n6); //dSetZero (v,n6); for (i=0; ifacc[j]; for (j=0; j<3; j++) fe[i*6+3+j] = body[i]->tacc[j]; for (j=0; j<3; j++) v[i*6+j] = body[i]->lvel[j]; for (j=0; j<3; j++) v[i*6+3+j] = body[i]->avel[j]; } // this will be set to the velocity update dReal *vnew = (dReal*) ALLOCA (n6 * sizeof(dReal)); dSetZero (vnew,n6); // if there are constraints, compute cforce if (m > 0) { // create a constraint equation right hand side vector `c', a constraint // force mixing vector `cfm', and LCP low and high bound vectors, and an // 'findex' vector. dReal *c = (dReal*) ALLOCA (m*sizeof(dReal)); dReal *cfm = (dReal*) ALLOCA (m*sizeof(dReal)); dReal *lo = (dReal*) ALLOCA (m*sizeof(dReal)); dReal *hi = (dReal*) ALLOCA (m*sizeof(dReal)); int *findex = (int*) alloca (m*sizeof(int)); dSetZero (c,m); dSetValue (cfm,m,world->global_cfm); dSetValue (lo,m,-dInfinity); dSetValue (hi,m, dInfinity); for (i=0; iglobal_erp; for (i=0; inode[0].body->tag; Jinfo.J1a = Jinfo.J1l + 3; if (joint[i]->node[1].body) { Jinfo.J2l = J + nskip*ofs[i] + 6*joint[i]->node[1].body->tag; Jinfo.J2a = Jinfo.J2l + 3; } else { Jinfo.J2l = 0; Jinfo.J2a = 0; } Jinfo.c = c + ofs[i]; Jinfo.cfm = cfm + ofs[i]; Jinfo.lo = lo + ofs[i]; Jinfo.hi = hi + ofs[i]; Jinfo.findex = findex + ofs[i]; joint[i]->vtable->getInfo2 (joint[i],&Jinfo); // adjust returned findex values for global index numbering for (j=0; j= 0) findex[ofs[i] + j] += ofs[i]; } } // compute A = J*invM*J' # ifdef TIMING dTimerNow ("compute A"); # endif dReal *JinvM = (dReal*) ALLOCA (m*nskip*sizeof(dReal)); //dSetZero (JinvM,m*nskip); dMultiply0 (JinvM,J,invM,m,n6,n6); int mskip = dPAD(m); dReal *A = (dReal*) ALLOCA (m*mskip*sizeof(dReal)); //dSetZero (A,m*mskip); dMultiply2 (A,JinvM,J,m,n6,m); // add cfm to the diagonal of A for (i=0; ilvel[j] = vnew[i*6+j]; for (j=0; j<3; j++) body[i]->avel[j] = vnew[i*6+3+j]; } // update the position and orientation from the new linear/angular velocity // (over the given timestep) # ifdef TIMING dTimerNow ("update position"); # endif for (i=0; ifacc[0] = 0; body[i]->facc[1] = 0; body[i]->facc[2] = 0; body[i]->facc[3] = 0; body[i]->tacc[0] = 0; body[i]->tacc[1] = 0; body[i]->tacc[2] = 0; body[i]->tacc[3] = 0; } # ifdef TIMING dTimerEnd(); if (m > 0) dTimerReport (stdout,1); # endif } //**************************************************************************** // an optimized version of dInternalStepIsland1() void dInternalStepIsland_x2 (dxWorld *world, dxBody * const *body, int nb, dxJoint * const *_joint, int nj, dReal stepsize) { int i,j,k; # ifdef TIMING dTimerStart("preprocessing"); # endif dReal stepsize1 = dRecip(stepsize); // number all bodies in the body list - set their tag values for (i=0; itag = i; // make a local copy of the joint array, because we might want to modify it. // (the "dxJoint *const*" declaration says we're allowed to modify the joints // but not the joint array, because the caller might need it unchanged). dxJoint **joint = (dxJoint**) ALLOCA (nj * sizeof(dxJoint*)); memcpy (joint,_joint,nj * sizeof(dxJoint*)); // for all bodies, compute the inertia tensor and its inverse in the global // frame, and compute the rotational force and add it to the torque // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. // @@@ check computation of rotational force. dReal *I = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); dReal *invI = (dReal*) ALLOCA (3*nb*4 * sizeof(dReal)); //dSetZero (I,3*nb*4); //dSetZero (invI,3*nb*4); for (i=0; imass.I,body[i]->R); dMULTIPLY0_333 (I+i*12,body[i]->R,tmp); // compute inverse inertia tensor in global frame dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->R); dMULTIPLY0_333 (invI+i*12,body[i]->R,tmp); // compute rotational force dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); } // add the gravity force to all bodies for (i=0; iflags & dxBodyNoGravity)==0) { body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; } } // get m = total constraint dimension, nub = number of unbounded variables. // create constraint offset array and number-of-rows array for all joints. // the constraints are re-ordered as follows: the purely unbounded // constraints, the mixed unbounded + LCP constraints, and last the purely // LCP constraints. this assists the LCP solver to put all unbounded // variables at the start for a quick factorization. // // joints with m=0 are inactive and are removed from the joints array // entirely, so that the code that follows does not consider them. // also number all active joints in the joint list (set their tag values). // inactive joints receive a tag value of -1. int m = 0; dxJoint::Info1 *info = (dxJoint::Info1*) ALLOCA (nj*sizeof(dxJoint::Info1)); int *ofs = (int*) ALLOCA (nj*sizeof(int)); for (i=0, j=0; jvtable->getInfo1 (joint[j],info+i); dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); if (info[i].m > 0) { joint[i] = joint[j]; joint[i]->tag = i; i++; } else { joint[j]->tag = -1; } } nj = i; // the purely unbounded constraints for (i=0; i 0 && info[i].nub < info[i].m) { ofs[i] = m; m += info[i].m; } // the purely LCP constraints for (i=0; i 0) { // create a constraint equation right hand side vector `c', a constraint // force mixing vector `cfm', and LCP low and high bound vectors, and an // 'findex' vector. dReal *c = (dReal*) ALLOCA (m*sizeof(dReal)); dReal *cfm = (dReal*) ALLOCA (m*sizeof(dReal)); dReal *lo = (dReal*) ALLOCA (m*sizeof(dReal)); dReal *hi = (dReal*) ALLOCA (m*sizeof(dReal)); int *findex = (int*) alloca (m*sizeof(int)); dSetZero (c,m); dSetValue (cfm,m,world->global_cfm); dSetValue (lo,m,-dInfinity); dSetValue (hi,m, dInfinity); for (i=0; iglobal_erp; for (i=0; ivtable->getInfo2 (joint[i],&Jinfo); // adjust returned findex values for global index numbering for (j=0; j= 0) findex[ofs[i] + j] += ofs[i]; } } // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same // format as J so we just go through the constraints in J multiplying by // the appropriate scalars and matrices. # ifdef TIMING dTimerNow ("compute A"); # endif dReal *JinvM = (dReal*) ALLOCA (2*m*8*sizeof(dReal)); dSetZero (JinvM,2*m*8); for (i=0; inode[0].body->tag; dReal body_invMass = body[b]->invMass; dReal *body_invI = invI + b*12; dReal *Jsrc = J + 2*8*ofs[i]; dReal *Jdst = JinvM + 2*8*ofs[i]; for (j=info[i].m-1; j>=0; j--) { for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); Jsrc += 8; Jdst += 8; } if (joint[i]->node[1].body) { b = joint[i]->node[1].body->tag; body_invMass = body[b]->invMass; body_invI = invI + b*12; for (j=info[i].m-1; j>=0; j--) { for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); Jsrc += 8; Jdst += 8; } } } // now compute A = JinvM * J'. A's rows and columns are grouped by joint, // i.e. in the same way as the rows of J. block (i,j) of A is only nonzero // if joints i and j have at least one body in common. this fact suggests // the algorithm used to fill A: // // for b = all bodies // n = number of joints attached to body b // for i = 1..n // for j = i+1..n // ii = actual joint number for i // jj = actual joint number for j // // (ii,jj) will be set to all pairs of joints around body b // compute blockwise: A(ii,jj) += JinvM(ii) * J(jj)' // // this algorithm catches all pairs of joints that have at least one body // in common. it does not compute the diagonal blocks of A however - // another similar algorithm does that. int mskip = dPAD(m); dReal *A = (dReal*) ALLOCA (m*mskip*sizeof(dReal)); dSetZero (A,m*mskip); for (i=0; ifirstjoint; n1; n1=n1->next) { for (dxJointNode *n2=n1->next; n2; n2=n2->next) { // get joint numbers and ensure ofs[j1] >= ofs[j2] int j1 = n1->joint->tag; int j2 = n2->joint->tag; if (ofs[j1] < ofs[j2]) { int tmp = j1; j1 = j2; j2 = tmp; } // if either joint was tagged as -1 then it is an inactive (m=0) // joint that should not be considered if (j1==-1 || j2==-1) continue; // determine if body i is the 1st or 2nd body of joints j1 and j2 int jb1 = (joint[j1]->node[1].body == body[i]); int jb2 = (joint[j2]->node[1].body == body[i]); // jb1/jb2 must be 0 for joints with only one body dIASSERT(joint[j1]->node[1].body || jb1==0); dIASSERT(joint[j2]->node[1].body || jb2==0); // set block of A MultiplyAdd2_p8r (A + ofs[j1]*mskip + ofs[j2], JinvM + 2*8*ofs[j1] + jb1*8*info[j1].m, J + 2*8*ofs[j2] + jb2*8*info[j2].m, info[j1].m,info[j2].m, mskip); } } } // compute diagonal blocks of A for (i=0; inode[1].body) { MultiplyAdd2_p8r (A + ofs[i]*(mskip+1), JinvM + 2*8*ofs[i] + 8*info[i].m, J + 2*8*ofs[i] + 8*info[i].m, info[i].m,info[i].m, mskip); } } // add cfm to the diagonal of A for (i=0; iinvMass; dReal *body_invI = invI + i*12; for (j=0; j<3; j++) tmp1[i*8+j] = body[i]->facc[j] * body_invMass + body[i]->lvel[j] * stepsize1; dMULTIPLY0_331 (tmp1 + i*8 + 4,body_invI,body[i]->tacc); for (j=0; j<3; j++) tmp1[i*8+4+j] += body[i]->avel[j] * stepsize1; } // put J*tmp1 into rhs dReal *rhs = (dReal*) ALLOCA (m * sizeof(dReal)); //dSetZero (rhs,m); for (i=0; inode[0].body->tag, info[i].m); if (joint[i]->node[1].body) { MultiplyAdd0_p81 (rhs+ofs[i],JJ + 8*info[i].m, tmp1 + 8*joint[i]->node[1].body->tag, info[i].m); } } // complete rhs for (i=0; inode[0].body; dxBody* b2 = joint[i]->node[1].body; dJointFeedback *fb = joint[i]->feedback; /******************** breakable joint contribution ***********************/ // this saves us a few dereferences dxJointBreakInfo *jBI = joint[i]->breakInfo; // we need joint feedback if the joint is breakable or if the user // requested feedback. if (jBI||fb) { // we need feedback on the amount of force that this joint is // applying to the bodies. we use a slightly slower computation // that splits out the force components and puts them in the // feedback structure. dJointFeedback temp_fb; // temporary storage for joint feedback dReal data1[8],data2[8]; Multiply1_8q1 (data1, JJ, lambda+ofs[i], info[i].m); dReal *cf1 = cforce + 8*b1->tag; cf1[0] += (temp_fb.f1[0] = data1[0]); cf1[1] += (temp_fb.f1[1] = data1[1]); cf1[2] += (temp_fb.f1[2] = data1[2]); cf1[4] += (temp_fb.t1[0] = data1[4]); cf1[5] += (temp_fb.t1[1] = data1[5]); cf1[6] += (temp_fb.t1[2] = data1[6]); if (b2) { Multiply1_8q1 (data2, JJ + 8*info[i].m, lambda+ofs[i], info[i].m); dReal *cf2 = cforce + 8*b2->tag; cf2[0] += (temp_fb.f2[0] = data2[0]); cf2[1] += (temp_fb.f2[1] = data2[1]); cf2[2] += (temp_fb.f2[2] = data2[2]); cf2[4] += (temp_fb.t2[0] = data2[4]); cf2[5] += (temp_fb.t2[1] = data2[5]); cf2[6] += (temp_fb.t2[2] = data2[6]); } // if the user requested so we must copy the feedback information to // the feedback struct that the user suplied. if (fb) { // copy temp_fb to fb fb->f1[0] = temp_fb.f1[0]; fb->f1[1] = temp_fb.f1[1]; fb->f1[2] = temp_fb.f1[2]; fb->t1[0] = temp_fb.t1[0]; fb->t1[1] = temp_fb.t1[1]; fb->t1[2] = temp_fb.t1[2]; if (b2) { fb->f2[0] = temp_fb.f2[0]; fb->f2[1] = temp_fb.f2[1]; fb->f2[2] = temp_fb.f2[2]; fb->t2[0] = temp_fb.t2[0]; fb->t2[1] = temp_fb.t2[1]; fb->t2[2] = temp_fb.t2[2]; } } // if the joint is breakable we need to check the breaking conditions if (jBI) { dReal relCF1[3]; dReal relCT1[3]; // multiply the force and torque vectors by the rotation matrix of body 1 dMULTIPLY1_331 (&relCF1[0],b1->R,&temp_fb.f1[0]); dMULTIPLY1_331 (&relCT1[0],b1->R,&temp_fb.t1[0]); if (jBI->flags & dJOINT_BREAK_AT_B1_FORCE) { // check if the force is to high for (int i = 0; i < 3; i++) { if (relCF1[i] > jBI->b1MaxF[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } if (jBI->flags & dJOINT_BREAK_AT_B1_TORQUE) { // check if the torque is to high for (int i = 0; i < 3; i++) { if (relCT1[i] > jBI->b1MaxT[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } if (b2) { dReal relCF2[3]; dReal relCT2[3]; // multiply the force and torque vectors by the rotation matrix of body 2 dMULTIPLY1_331 (&relCF2[0],b2->R,&temp_fb.f2[0]); dMULTIPLY1_331 (&relCT2[0],b2->R,&temp_fb.t2[0]); if (jBI->flags & dJOINT_BREAK_AT_B2_FORCE) { // check if the force is to high for (int i = 0; i < 3; i++) { if (relCF2[i] > jBI->b2MaxF[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } if (jBI->flags & dJOINT_BREAK_AT_B2_TORQUE) { // check if the torque is to high for (int i = 0; i < 3; i++) { if (relCT2[i] > jBI->b2MaxT[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } } doneCheckingBreaks: ; } } /*************************************************************************/ else { // no feedback is required, let's compute cforce the faster way MultiplyAdd1_8q1 (cforce + 8*b1->tag,JJ, lambda+ofs[i], info[i].m); if (b2) { MultiplyAdd1_8q1 (cforce + 8*b2->tag, JJ + 8*info[i].m, lambda+ofs[i], info[i].m); } } } } // compute the velocity update # ifdef TIMING dTimerNow ("compute velocity update"); # endif // add fe to cforce for (i=0; ifacc[j]; for (j=0; j<3; j++) cforce[i*8+4+j] += body[i]->tacc[j]; } // multiply cforce by stepsize for (i=0; i < nb*8; i++) cforce[i] *= stepsize; // add invM * cforce to the body velocity for (i=0; iinvMass; dReal *body_invI = invI + i*12; for (j=0; j<3; j++) body[i]->lvel[j] += body_invMass * cforce[i*8+j]; dMULTIPLYADD0_331 (body[i]->avel,body_invI,cforce+i*8+4); } // update the position and orientation from the new linear/angular velocity // (over the given timestep) # ifdef TIMING dTimerNow ("update position"); # endif for (i=0; ilvel[j]; for (j=0; j<3; j++) tmp_vnew[i*6+3+j] = body[i]->avel[j]; } comparator.nextMatrix (tmp_vnew,nb*6,1,0,"vnew"); # endif # ifdef TIMING dTimerNow ("tidy up"); # endif // zero all force accumulators for (i=0; ifacc[0] = 0; body[i]->facc[1] = 0; body[i]->facc[2] = 0; body[i]->facc[3] = 0; body[i]->tacc[0] = 0; body[i]->tacc[1] = 0; body[i]->tacc[2] = 0; body[i]->tacc[3] = 0; } # ifdef TIMING dTimerEnd(); if (m > 0) dTimerReport (stdout,1); # endif } //**************************************************************************** void dInternalStepIsland (dxWorld *world, dxBody * const *body, int nb, dxJoint * const *joint, int nj, dReal stepsize) { # ifndef COMPARE_METHODS dInternalStepIsland_x2 (world,body,nb,joint,nj,stepsize); # endif # ifdef COMPARE_METHODS int i; // save body state dxBody *state = (dxBody*) ALLOCA (nb*sizeof(dxBody)); for (i=0; i #include #include #include #include #include #include #include "lcp.h" #include "step.h" // misc defines #define ALLOCA dALLOCA16 #define RANDOM_JOINT_ORDER //#define FAST_FACTOR //use a factorization approximation to the LCP solver (fast, theoretically less accurate) #define SLOW_LCP //use the old LCP solver //#define NO_ISLANDS //does not perform island creation code (3~4% of simulation time), body disabling doesn't work //#define TIMING static int autoEnableDepth = 2; void dWorldSetAutoEnableDepthSF1 (dxWorld *world, int autodepth) { if (autodepth > 0) autoEnableDepth = autodepth; else autoEnableDepth = 0; } int dWorldGetAutoEnableDepthSF1 (dxWorld *world) { return autoEnableDepth; } //little bit of math.... the _sym_ functions assume the return matrix will be symmetric static void Multiply2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) { int i, j; dReal sum, *aa, *ad, *bb, *cc; dIASSERT (p > 0 && A && B && C); bb = B; for (i = 0; i < p; i++) { //aa is going accross the matrix, ad down aa = ad = A; cc = C; for (j = i; j < p; j++) { sum = bb[0] * cc[0]; sum += bb[1] * cc[1]; sum += bb[2] * cc[2]; sum += bb[4] * cc[4]; sum += bb[5] * cc[5]; sum += bb[6] * cc[6]; *(aa++) = *ad = sum; ad += Askip; cc += 8; } bb += 8; A += Askip + 1; C += 8; } } static void MultiplyAdd2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) { int i, j; dReal sum, *aa, *ad, *bb, *cc; dIASSERT (p > 0 && A && B && C); bb = B; for (i = 0; i < p; i++) { //aa is going accross the matrix, ad down aa = ad = A; cc = C; for (j = i; j < p; j++) { sum = bb[0] * cc[0]; sum += bb[1] * cc[1]; sum += bb[2] * cc[2]; sum += bb[4] * cc[4]; sum += bb[5] * cc[5]; sum += bb[6] * cc[6]; *(aa++) += sum; *ad += sum; ad += Askip; cc += 8; } bb += 8; A += Askip + 1; C += 8; } } // this assumes the 4th and 8th rows of B are zero. static void Multiply0_p81 (dReal * A, dReal * B, dReal * C, int p) { int i; dIASSERT (p > 0 && A && B && C); dReal sum; for (i = p; i; i--) { sum = B[0] * C[0]; sum += B[1] * C[1]; sum += B[2] * C[2]; sum += B[4] * C[4]; sum += B[5] * C[5]; sum += B[6] * C[6]; *(A++) = sum; B += 8; } } // this assumes the 4th and 8th rows of B are zero. static void MultiplyAdd0_p81 (dReal * A, dReal * B, dReal * C, int p) { int i; dIASSERT (p > 0 && A && B && C); dReal sum; for (i = p; i; i--) { sum = B[0] * C[0]; sum += B[1] * C[1]; sum += B[2] * C[2]; sum += B[4] * C[4]; sum += B[5] * C[5]; sum += B[6] * C[6]; *(A++) += sum; B += 8; } } // this assumes the 4th and 8th rows of B are zero. static void Multiply1_8q1 (dReal * A, dReal * B, dReal * C, int q) { int k; dReal sum; dIASSERT (q > 0 && A && B && C); sum = 0; for (k = 0; k < q; k++) sum += B[k * 8] * C[k]; A[0] = sum; sum = 0; for (k = 0; k < q; k++) sum += B[1 + k * 8] * C[k]; A[1] = sum; sum = 0; for (k = 0; k < q; k++) sum += B[2 + k * 8] * C[k]; A[2] = sum; sum = 0; for (k = 0; k < q; k++) sum += B[4 + k * 8] * C[k]; A[4] = sum; sum = 0; for (k = 0; k < q; k++) sum += B[5 + k * 8] * C[k]; A[5] = sum; sum = 0; for (k = 0; k < q; k++) sum += B[6 + k * 8] * C[k]; A[6] = sum; } //**************************************************************************** // body rotation // return sin(x)/x. this has a singularity at 0 so special handling is needed // for small arguments. static inline dReal sinc (dReal x) { // if |x| < 1e-4 then use a taylor series expansion. this two term expansion // is actually accurate to one LS bit within this range if double precision // is being used - so don't worry! if (dFabs (x) < 1.0e-4) return REAL (1.0) - x * x * REAL (0.166666666666666666667); else return dSin (x) / x; } // given a body b, apply its linear and angular rotation over the time // interval h, thereby adjusting its position and orientation. static inline void moveAndRotateBody (dxBody * b, dReal h) { int j; // handle linear velocity for (j = 0; j < 3; j++) b->pos[j] += h * b->lvel[j]; if (b->flags & dxBodyFlagFiniteRotation) { dVector3 irv; // infitesimal rotation vector dQuaternion q; // quaternion for finite rotation if (b->flags & dxBodyFlagFiniteRotationAxis) { // split the angular velocity vector into a component along the finite // rotation axis, and a component orthogonal to it. dVector3 frv, irv; // finite rotation vector dReal k = dDOT (b->finite_rot_axis, b->avel); frv[0] = b->finite_rot_axis[0] * k; frv[1] = b->finite_rot_axis[1] * k; frv[2] = b->finite_rot_axis[2] * k; irv[0] = b->avel[0] - frv[0]; irv[1] = b->avel[1] - frv[1]; irv[2] = b->avel[2] - frv[2]; // make a rotation quaternion q that corresponds to frv * h. // compare this with the full-finite-rotation case below. h *= REAL (0.5); dReal theta = k * h; q[0] = dCos (theta); dReal s = sinc (theta) * h; q[1] = frv[0] * s; q[2] = frv[1] * s; q[3] = frv[2] * s; } else { // make a rotation quaternion q that corresponds to w * h dReal wlen = dSqrt (b->avel[0] * b->avel[0] + b->avel[1] * b->avel[1] + b->avel[2] * b->avel[2]); h *= REAL (0.5); dReal theta = wlen * h; q[0] = dCos (theta); dReal s = sinc (theta) * h; q[1] = b->avel[0] * s; q[2] = b->avel[1] * s; q[3] = b->avel[2] * s; } // do the finite rotation dQuaternion q2; dQMultiply0 (q2, q, b->q); for (j = 0; j < 4; j++) b->q[j] = q2[j]; // do the infitesimal rotation if required if (b->flags & dxBodyFlagFiniteRotationAxis) { dReal dq[4]; dWtoDQ (irv, b->q, dq); for (j = 0; j < 4; j++) b->q[j] += h * dq[j]; } } else { // the normal way - do an infitesimal rotation dReal dq[4]; dWtoDQ (b->avel, b->q, dq); for (j = 0; j < 4; j++) b->q[j] += h * dq[j]; } // normalize the quaternion and convert it to a rotation matrix dNormalize4 (b->q); dQtoR (b->q, b->R); // notify all attached geoms that this body has moved for (dxGeom * geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) dGeomMoved (geom); } //**************************************************************************** //This is an implementation of the iterated/relaxation algorithm. //Here is a quick overview of the algorithm per Sergi Valverde's posts to the //mailing list: // // for i=0..N-1 do // for c = 0..C-1 do // Solve constraint c-th // Apply forces to constraint bodies // next // next // Integrate bodies void dInternalStepFast (dxWorld * world, dxBody * body[2], dReal * GI[2], dReal * GinvI[2], dxJoint * joint, dxJoint::Info1 info, dxJoint::Info2 Jinfo, dReal stepsize) { int i, j, k; # ifdef TIMING dTimerNow ("constraint preprocessing"); # endif dReal stepsize1 = dRecip (stepsize); int m = info.m; // nothing to do if no constraints. if (m <= 0) return; int nub = 0; if (info.nub == info.m) nub = m; // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same // format as J so we just go through the constraints in J multiplying by // the appropriate scalars and matrices. # ifdef TIMING dTimerNow ("compute A"); # endif dReal JinvM[2 * 6 * 8]; //dSetZero (JinvM, 2 * m * 8); dReal *Jsrc = Jinfo.J1l; dReal *Jdst = JinvM; if (body[0]) { for (j = m - 1; j >= 0; j--) { for (k = 0; k < 3; k++) Jdst[k] = Jsrc[k] * body[0]->invMass; dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[0]); Jsrc += 8; Jdst += 8; } } if (body[1]) { Jsrc = Jinfo.J2l; Jdst = JinvM + 8 * m; for (j = m - 1; j >= 0; j--) { for (k = 0; k < 3; k++) Jdst[k] = Jsrc[k] * body[1]->invMass; dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[1]); Jsrc += 8; Jdst += 8; } } // now compute A = JinvM * J'. int mskip = dPAD (m); dReal A[6 * 8]; //dSetZero (A, 6 * 8); if (body[0]) Multiply2_sym_p8p (A, JinvM, Jinfo.J1l, m, mskip); if (body[1]) MultiplyAdd2_sym_p8p (A, JinvM + 8 * m, Jinfo.J2l, m, mskip); // add cfm to the diagonal of A for (i = 0; i < m; i++) A[i * mskip + i] += Jinfo.cfm[i] * stepsize1; // compute the right hand side `rhs' # ifdef TIMING dTimerNow ("compute rhs"); # endif dReal tmp1[16]; //dSetZero (tmp1, 16); // put v/h + invM*fe into tmp1 for (i = 0; i < 2; i++) { if (!body[i]) continue; for (j = 0; j < 3; j++) tmp1[i * 8 + j] = body[i]->facc[j] * body[i]->invMass + body[i]->lvel[j] * stepsize1; dMULTIPLY0_331 (tmp1 + i * 8 + 4, GinvI[i], body[i]->tacc); for (j = 0; j < 3; j++) tmp1[i * 8 + 4 + j] += body[i]->avel[j] * stepsize1; } // put J*tmp1 into rhs dReal rhs[6]; //dSetZero (rhs, 6); if (body[0]) Multiply0_p81 (rhs, Jinfo.J1l, tmp1, m); if (body[1]) MultiplyAdd0_p81 (rhs, Jinfo.J2l, tmp1 + 8, m); // complete rhs for (i = 0; i < m; i++) rhs[i] = Jinfo.c[i] * stepsize1 - rhs[i]; #ifdef SLOW_LCP // solve the LCP problem and get lambda. // this will destroy A but that's okay # ifdef TIMING dTimerNow ("solving LCP problem"); # endif dReal *lambda = (dReal *) ALLOCA (m * sizeof (dReal)); dReal *residual = (dReal *) ALLOCA (m * sizeof (dReal)); dReal lo[6], hi[6]; memcpy (lo, Jinfo.lo, m * sizeof (dReal)); memcpy (hi, Jinfo.hi, m * sizeof (dReal)); dSolveLCP (m, A, lambda, rhs, residual, nub, lo, hi, Jinfo.findex); #endif // LCP Solver replacement: // This algorithm goes like this: // Do a straightforward LDLT factorization of the matrix A, solving for // A*x = rhs // For each x[i] that is outside of the bounds of lo[i] and hi[i], // clamp x[i] into that range. // Substitute into A the now known x's // subtract the residual away from the rhs. // Remove row and column i from L, updating the factorization // place the known x's at the end of the array, keeping up with location in p // Repeat until all constraints have been clamped or all are within bounds // // This is probably only faster in the single joint case where only one repeat is // the norm. #ifdef FAST_FACTOR // factorize A (L*D*L'=A) # ifdef TIMING dTimerNow ("factorize A"); # endif dReal d[6]; dReal L[6 * 8]; memcpy (L, A, m * mskip * sizeof (dReal)); dFactorLDLT (L, d, m, mskip); // compute lambda # ifdef TIMING dTimerNow ("compute lambda"); # endif int left = m; //constraints left to solve. int remove[6]; dReal lambda[6]; dReal x[6]; int p[6]; for (i = 0; i < 6; i++) p[i] = i; while (true) { memcpy (x, rhs, left * sizeof (dReal)); dSolveLDLT (L, d, x, left, mskip); int fixed = 0; for (i = 0; i < left; i++) { j = p[i]; remove[i] = false; // This isn't the exact same use of findex as dSolveLCP.... since x[findex] // may change after I've already clamped x[i], but it should be close if (Jinfo.findex[j] > -1) { dReal f = fabs (Jinfo.hi[j] * x[p[Jinfo.findex[j]]]); if (x[i] > f) x[i] = f; else if (x[i] < -f) x[i] = -f; else continue; } else { if (x[i] > Jinfo.hi[j]) x[i] = Jinfo.hi[j]; else if (x[i] < Jinfo.lo[j]) x[i] = Jinfo.lo[j]; else continue; } remove[i] = true; fixed++; } if (fixed == 0 || fixed == left) //no change or all constraints solved break; for (i = 0; i < left; i++) //sub in to right hand side. if (remove[i]) for (j = 0; j < left; j++) if (!remove[j]) rhs[j] -= A[j * mskip + i] * x[i]; for (int r = left - 1; r >= 0; r--) //eliminate row/col for fixed variables { if (remove[r]) { //dRemoveLDLT adapted for use without row pointers. if (r == left - 1) { left--; continue; // deleting last row/col is easy } else if (r == 0) { dReal a[6]; for (i = 0; i < left; i++) a[i] = -A[i * mskip]; a[0] += REAL (1.0); dLDLTAddTL (L, d, a, left, mskip); } else { dReal t[6]; dReal a[6]; for (i = 0; i < r; i++) t[i] = L[r * mskip + i] / d[i]; for (i = 0; i < left - r; i++) a[i] = dDot (L + (r + i) * mskip, t, r) - A[(r + i) * mskip + r]; a[0] += REAL (1.0); dLDLTAddTL (L + r * mskip + r, d + r, a, left - r, mskip); } dRemoveRowCol (L, left, mskip, r); //end dRemoveLDLT left--; if (r < (left - 1)) { dReal tx = x[r]; memmove (d + r, d + r + 1, (left - r) * sizeof (dReal)); memmove (rhs + r, rhs + r + 1, (left - r) * sizeof (dReal)); //x will get written over by rhs anyway, no need to move it around //just store the fixed value we just discovered in it. x[left] = tx; for (i = 0; i < m; i++) if (p[i] > r && p[i] <= left) p[i]--; p[r] = left; } } } } for (i = 0; i < m; i++) lambda[i] = x[p[i]]; # endif // compute the constraint force `cforce' # ifdef TIMING dTimerNow ("compute constraint force"); #endif // compute cforce = J'*lambda dJointFeedback *fb = joint->feedback; dReal cforce[16]; //dSetZero (cforce, 16); /******************** breakable joint contribution ***********************/ // this saves us a few dereferences dxJointBreakInfo *jBI = joint->breakInfo; // we need joint feedback if the joint is breakable or if the user // requested feedback. if (jBI||fb) { // we need feedback on the amount of force that this joint is // applying to the bodies. we use a slightly slower computation // that splits out the force components and puts them in the // feedback structure. dJointFeedback temp_fb; // temporary storage for joint feedback dReal data1[8],data2[8]; if (body[0]) { Multiply1_8q1 (data1, Jinfo.J1l, lambda, m); dReal *cf1 = cforce; cf1[0] = (temp_fb.f1[0] = data1[0]); cf1[1] = (temp_fb.f1[1] = data1[1]); cf1[2] = (temp_fb.f1[2] = data1[2]); cf1[4] = (temp_fb.t1[0] = data1[4]); cf1[5] = (temp_fb.t1[1] = data1[5]); cf1[6] = (temp_fb.t1[2] = data1[6]); } if (body[1]) { Multiply1_8q1 (data2, Jinfo.J2l, lambda, m); dReal *cf2 = cforce + 8; cf2[0] = (temp_fb.f2[0] = data2[0]); cf2[1] = (temp_fb.f2[1] = data2[1]); cf2[2] = (temp_fb.f2[2] = data2[2]); cf2[4] = (temp_fb.t2[0] = data2[4]); cf2[5] = (temp_fb.t2[1] = data2[5]); cf2[6] = (temp_fb.t2[2] = data2[6]); } // if the user requested so we must copy the feedback information to // the feedback struct that the user suplied. if (fb) { // copy temp_fb to fb fb->f1[0] = temp_fb.f1[0]; fb->f1[1] = temp_fb.f1[1]; fb->f1[2] = temp_fb.f1[2]; fb->t1[0] = temp_fb.t1[0]; fb->t1[1] = temp_fb.t1[1]; fb->t1[2] = temp_fb.t1[2]; if (body[1]) { fb->f2[0] = temp_fb.f2[0]; fb->f2[1] = temp_fb.f2[1]; fb->f2[2] = temp_fb.f2[2]; fb->t2[0] = temp_fb.t2[0]; fb->t2[1] = temp_fb.t2[1]; fb->t2[2] = temp_fb.t2[2]; } } // if the joint is breakable we need to check the breaking conditions if (jBI) { dReal relCF1[3]; dReal relCT1[3]; // multiply the force and torque vectors by the rotation matrix of body 1 dMULTIPLY1_331 (&relCF1[0],body[0]->R,&temp_fb.f1[0]); dMULTIPLY1_331 (&relCT1[0],body[0]->R,&temp_fb.t1[0]); if (jBI->flags & dJOINT_BREAK_AT_B1_FORCE) { // check if the force is to high for (int i = 0; i < 3; i++) { if (relCF1[i] > jBI->b1MaxF[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } if (jBI->flags & dJOINT_BREAK_AT_B1_TORQUE) { // check if the torque is to high for (int i = 0; i < 3; i++) { if (relCT1[i] > jBI->b1MaxT[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } if (body[1]) { dReal relCF2[3]; dReal relCT2[3]; // multiply the force and torque vectors by the rotation matrix of body 2 dMULTIPLY1_331 (&relCF2[0],body[1]->R,&temp_fb.f2[0]); dMULTIPLY1_331 (&relCT2[0],body[1]->R,&temp_fb.t2[0]); if (jBI->flags & dJOINT_BREAK_AT_B2_FORCE) { // check if the force is to high for (int i = 0; i < 3; i++) { if (relCF2[i] > jBI->b2MaxF[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } if (jBI->flags & dJOINT_BREAK_AT_B2_TORQUE) { // check if the torque is to high for (int i = 0; i < 3; i++) { if (relCT2[i] > jBI->b2MaxT[i]) { jBI->flags |= dJOINT_BROKEN; goto doneCheckingBreaks; } } } } doneCheckingBreaks: ; } } /*************************************************************************/ else { // no feedback is required, let's compute cforce the faster way if (body[0]) Multiply1_8q1 (cforce, Jinfo.J1l, lambda, m); if (body[1]) Multiply1_8q1 (cforce + 8, Jinfo.J2l, lambda, m); } for (i = 0; i < 2; i++) { if (!body[i]) continue; for (j = 0; j < 3; j++) { body[i]->facc[j] += cforce[i * 8 + j]; body[i]->tacc[j] += cforce[i * 8 + 4 + j]; } } } void dInternalStepIslandFast (dxWorld * world, dxBody * const *bodies, int nb, dxJoint * const *_joints, int nj, dReal stepsize, int maxiterations) { # ifdef TIMING dTimerNow ("preprocessing"); # endif dxBody *bodyPair[2], *body; dReal *GIPair[2], *GinvIPair[2]; dxJoint *joint; int iter, b, j, i; dReal ministep = stepsize / maxiterations; // make a local copy of the joint array, because we might want to modify it. // (the "dxJoint *const*" declaration says we're allowed to modify the joints // but not the joint array, because the caller might need it unchanged). dxJoint **joints = (dxJoint **) ALLOCA (nj * sizeof (dxJoint *)); memcpy (joints, _joints, nj * sizeof (dxJoint *)); // get m = total constraint dimension, nub = number of unbounded variables. // create constraint offset array and number-of-rows array for all joints. // the constraints are re-ordered as follows: the purely unbounded // constraints, the mixed unbounded + LCP constraints, and last the purely // LCP constraints. this assists the LCP solver to put all unbounded // variables at the start for a quick factorization. // // joints with m=0 are inactive and are removed from the joints array // entirely, so that the code that follows does not consider them. // also number all active joints in the joint list (set their tag values). // inactive joints receive a tag value of -1. int m = 0; dxJoint::Info1 * info = (dxJoint::Info1 *) ALLOCA (nj * sizeof (dxJoint::Info1)); int *ofs = (int *) ALLOCA (nj * sizeof (int)); for (i = 0, j = 0; j < nj; j++) { // i=dest, j=src joints[j]->vtable->getInfo1 (joints[j], info + i); dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); if (info[i].m > 0) { joints[i] = joints[j]; joints[i]->tag = i; i++; } else { joints[j]->tag = -1; } } nj = i; // the purely unbounded constraints for (i = 0; i < nj; i++) { ofs[i] = m; m += info[i].m; } dReal *c = NULL; dReal *cfm = NULL; dReal *lo = NULL; dReal *hi = NULL; int *findex = NULL; dReal *J = NULL; dxJoint::Info2 * Jinfo = NULL; if (m) { // create a constraint equation right hand side vector `c', a constraint // force mixing vector `cfm', and LCP low and high bound vectors, and an // 'findex' vector. c = (dReal *) ALLOCA (m * sizeof (dReal)); cfm = (dReal *) ALLOCA (m * sizeof (dReal)); lo = (dReal *) ALLOCA (m * sizeof (dReal)); hi = (dReal *) ALLOCA (m * sizeof (dReal)); findex = (int *) ALLOCA (m * sizeof (int)); dSetZero (c, m); dSetValue (cfm, m, world->global_cfm); dSetValue (lo, m, -dInfinity); dSetValue (hi, m, dInfinity); for (i = 0; i < m; i++) findex[i] = -1; // get jacobian data from constraints. a (2*m)x8 matrix will be created // to store the two jacobian blocks from each constraint. it has this // format: // // l l l 0 a a a 0 \ . // l l l 0 a a a 0 }-- jacobian body 1 block for joint 0 (3 rows) // l l l 0 a a a 0 / // l l l 0 a a a 0 \ . // l l l 0 a a a 0 }-- jacobian body 2 block for joint 0 (3 rows) // l l l 0 a a a 0 / // l l l 0 a a a 0 }--- jacobian body 1 block for joint 1 (1 row) // l l l 0 a a a 0 }--- jacobian body 2 block for joint 1 (1 row) // etc... // // (lll) = linear jacobian data // (aaa) = angular jacobian data // # ifdef TIMING dTimerNow ("create J"); # endif J = (dReal *) ALLOCA (2 * m * 8 * sizeof (dReal)); dSetZero (J, 2 * m * 8); Jinfo = (dxJoint::Info2 *) ALLOCA (nj * sizeof (dxJoint::Info2)); for (i = 0; i < nj; i++) { Jinfo[i].rowskip = 8; Jinfo[i].fps = dRecip (stepsize); Jinfo[i].erp = world->global_erp; Jinfo[i].J1l = J + 2 * 8 * ofs[i]; Jinfo[i].J1a = Jinfo[i].J1l + 4; Jinfo[i].J2l = Jinfo[i].J1l + 8 * info[i].m; Jinfo[i].J2a = Jinfo[i].J2l + 4; Jinfo[i].c = c + ofs[i]; Jinfo[i].cfm = cfm + ofs[i]; Jinfo[i].lo = lo + ofs[i]; Jinfo[i].hi = hi + ofs[i]; Jinfo[i].findex = findex + ofs[i]; //joints[i]->vtable->getInfo2 (joints[i], Jinfo+i); } } dReal *saveFacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); dReal *saveTacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); dReal *globalI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); dReal *globalInvI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); for (b = 0; b < nb; b++) { for (i = 0; i < 4; i++) { saveFacc[b * 4 + i] = bodies[b]->facc[i]; saveTacc[b * 4 + i] = bodies[b]->tacc[i]; bodies[b]->tag = b; } } for (iter = 0; iter < maxiterations; iter++) { # ifdef TIMING dTimerNow ("applying inertia and gravity"); # endif dReal tmp[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; for (b = 0; b < nb; b++) { body = bodies[b]; // for all bodies, compute the inertia tensor and its inverse in the global // frame, and compute the rotational force and add it to the torque // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. // @@@ check computation of rotational force. // compute inertia tensor in global frame dMULTIPLY2_333 (tmp, body->mass.I, body->R); dMULTIPLY0_333 (globalI + b * 12, body->R, tmp); // compute inverse inertia tensor in global frame dMULTIPLY2_333 (tmp, body->invI, body->R); dMULTIPLY0_333 (globalInvI + b * 12, body->R, tmp); for (i = 0; i < 4; i++) body->tacc[i] = saveTacc[b * 4 + i]; // compute rotational force dMULTIPLY0_331 (tmp, globalI + b * 12, body->avel); dCROSS (body->tacc, -=, body->avel, tmp); // add the gravity force to all bodies if ((body->flags & dxBodyNoGravity) == 0) { body->facc[0] = saveFacc[b * 4 + 0] + body->mass.mass * world->gravity[0]; body->facc[1] = saveFacc[b * 4 + 1] + body->mass.mass * world->gravity[1]; body->facc[2] = saveFacc[b * 4 + 2] + body->mass.mass * world->gravity[2]; body->facc[3] = 0; } } #ifdef RANDOM_JOINT_ORDER #ifdef TIMING dTimerNow ("randomizing joint order"); #endif //randomize the order of the joints by looping through the array //and swapping the current joint pointer with a random one before it. for (j = 0; j < nj; j++) { joint = joints[j]; dxJoint::Info1 i1 = info[j]; dxJoint::Info2 i2 = Jinfo[j]; int r = rand () % (j + 1); joints[j] = joints[r]; info[j] = info[r]; Jinfo[j] = Jinfo[r]; joints[r] = joint; info[r] = i1; Jinfo[r] = i2; } #endif //now iterate through the random ordered joint array we created. for (j = 0; j < nj; j++) { #ifdef TIMING dTimerNow ("setting up joint"); #endif joint = joints[j]; bodyPair[0] = joint->node[0].body; bodyPair[1] = joint->node[1].body; if (bodyPair[0] && (bodyPair[0]->flags & dxBodyDisabled)) bodyPair[0] = 0; if (bodyPair[1] && (bodyPair[1]->flags & dxBodyDisabled)) bodyPair[1] = 0; //if this joint is not connected to any enabled bodies, skip it. if (!bodyPair[0] && !bodyPair[1]) continue; if (bodyPair[0]) { GIPair[0] = globalI + bodyPair[0]->tag * 12; GinvIPair[0] = globalInvI + bodyPair[0]->tag * 12; } if (bodyPair[1]) { GIPair[1] = globalI + bodyPair[1]->tag * 12; GinvIPair[1] = globalInvI + bodyPair[1]->tag * 12; } joints[j]->vtable->getInfo2 (joints[j], Jinfo + j); //dInternalStepIslandFast is an exact copy of the old routine with one //modification: the calculated forces are added back to the facc and tacc //vectors instead of applying them to the bodies and moving them. if (info[j].m > 0) { dInternalStepFast (world, bodyPair, GIPair, GinvIPair, joint, info[j], Jinfo[j], ministep); } } // } # ifdef TIMING dTimerNow ("moving bodies"); # endif //Now we can simulate all the free floating bodies, and move them. for (b = 0; b < nb; b++) { body = bodies[b]; for (i = 0; i < 4; i++) { body->facc[i] *= ministep; body->tacc[i] *= ministep; } //apply torque dMULTIPLYADD0_331 (body->avel, globalInvI + b * 12, body->tacc); //apply force for (i = 0; i < 3; i++) body->lvel[i] += body->invMass * body->facc[i]; //move It! moveAndRotateBody (body, ministep); } } for (b = 0; b < nb; b++) for (j = 0; j < 4; j++) bodies[b]->facc[j] = bodies[b]->tacc[j] = 0; } #ifdef NO_ISLANDS // Since the iterative algorithm doesn't care about islands of bodies, this is a // faster algorithm that just sends it all the joints and bodies in one array. // It's downfall is it's inability to handle disabled bodies as well as the old one. static void processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) { // nothing to do if no bodies if (world->nb <= 0) return; # ifdef TIMING dTimerStart ("creating joint and body arrays"); # endif dxBody **bodies, *body; dxJoint **joints, *joint; joints = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); bodies = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); int nj = 0; for (joint = world->firstjoint; joint; joint = (dxJoint *) joint->next) joints[nj++] = joint; int nb = 0; for (body = world->firstbody; body; body = (dxBody *) body->next) bodies[nb++] = body; dInternalStepIslandFast (world, bodies, nb, joints, nj, stepsize, maxiterations); # ifdef TIMING dTimerEnd (); dTimerReport (stdout, 1); # endif } #else //**************************************************************************** // island processing // this groups all joints and bodies in a world into islands. all objects // in an island are reachable by going through connected bodies and joints. // each island can be simulated separately. // note that joints that are not attached to anything will not be included // in any island, an so they do not affect the simulation. // // this function starts new island from unvisited bodies. however, it will // never start a new islands from a disabled body. thus islands of disabled // bodies will not be included in the simulation. disabled bodies are // re-enabled if they are found to be part of an active island. static void processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) { #ifdef TIMING dTimerStart ("Island Setup"); #endif dxBody *b, *bb, **body; dxJoint *j, **joint; // nothing to do if no bodies if (world->nb <= 0) return; // make arrays for body and joint lists (for a single island) to go into body = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); joint = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); int bcount = 0; // number of bodies in `body' int jcount = 0; // number of joints in `joint' int tbcount = 0; int tjcount = 0; // set all body/joint tags to 0 for (b = world->firstbody; b; b = (dxBody *) b->next) b->tag = 0; for (j = world->firstjoint; j; j = (dxJoint *) j->next) j->tag = 0; // allocate a stack of unvisited bodies in the island. the maximum size of // the stack can be the lesser of the number of bodies or joints, because // new bodies are only ever added to the stack by going through untagged // joints. all the bodies in the stack must be tagged! int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; dxBody **stack = (dxBody **) ALLOCA (stackalloc * sizeof (dxBody *)); int *autostack = (int *) ALLOCA (stackalloc * sizeof (int)); for (bb = world->firstbody; bb; bb = (dxBody *) bb->next) { #ifdef TIMING dTimerNow ("Island Processing"); #endif // get bb = the next enabled, untagged body, and tag it if (bb->tag || (bb->flags & dxBodyDisabled)) continue; bb->tag = 1; // tag all bodies and joints starting from bb. int stacksize = 0; int autoDepth = autoEnableDepth; b = bb; body[0] = bb; bcount = 1; jcount = 0; goto quickstart; while (stacksize > 0) { b = stack[--stacksize]; // pop body off stack autoDepth = autostack[stacksize]; body[bcount++] = b; // put body on body list quickstart: // traverse and tag all body's joints, add untagged connected bodies // to stack for (dxJointNode * n = b->firstjoint; n; n = n->next) { if (!n->joint->tag) { int thisDepth = autoEnableDepth; n->joint->tag = 1; joint[jcount++] = n->joint; if (n->body && !n->body->tag) { if (n->body->flags & dxBodyDisabled) thisDepth = autoDepth - 1; if (thisDepth < 0) continue; n->body->flags &= ~dxBodyDisabled; n->body->tag = 1; autostack[stacksize] = thisDepth; stack[stacksize++] = n->body; } } } dIASSERT (stacksize <= world->nb); dIASSERT (stacksize <= world->nj); } // now do something with body and joint lists dInternalStepIslandFast (world, body, bcount, joint, jcount, stepsize, maxiterations); // what we've just done may have altered the body/joint tag values. // we must make sure that these tags are nonzero. // also make sure all bodies are in the enabled state. int i; for (i = 0; i < bcount; i++) { body[i]->tag = 1; body[i]->flags &= ~dxBodyDisabled; } for (i = 0; i < jcount; i++) joint[i]->tag = 1; tbcount += bcount; tjcount += jcount; } #ifdef TIMING dMessage(0, "Total joints processed: %i, bodies: %i", tjcount, tbcount); #endif // if debugging, check that all objects (except for disabled bodies, // unconnected joints, and joints that are connected to disabled bodies) // were tagged. # ifndef dNODEBUG for (b = world->firstbody; b; b = (dxBody *) b->next) { if (b->flags & dxBodyDisabled) { if (b->tag) dDebug (0, "disabled body tagged"); } else { if (!b->tag) dDebug (0, "enabled body not tagged"); } } for (j = world->firstjoint; j; j = (dxJoint *) j->next) { if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled) == 0) || (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled) == 0)) { if (!j->tag) dDebug (0, "attached enabled joint not tagged"); } else { if (j->tag) dDebug (0, "unattached or disabled joint tagged"); } } # endif /******************** breakable joint contribution ***********************/ dxJoint* nextJ; if (!world->firstjoint) nextJ = 0; else nextJ = (dxJoint*)world->firstjoint->next; for (j=world->firstjoint; j; j=nextJ) { nextJ = (dxJoint*)j->next; // check if joint is breakable and broken if (j->breakInfo && j->breakInfo->flags & dJOINT_BROKEN) { // detach (break) the joint dJointAttach (j, 0, 0); // call the callback function if it is set if (j->breakInfo->callback) j->breakInfo->callback (j); // finally destroy the joint if the dJOINT_DELETE_ON_BREAK is set if (j->breakInfo->flags & dJOINT_DELETE_ON_BREAK) dJointDestroy (j); } } /*************************************************************************/ # ifdef TIMING dTimerEnd (); dTimerReport (stdout, 1); # endif } #endif void dWorldStepFast1 (dWorldID w, dReal stepsize, int maxiterations) { dUASSERT (w, "bad world argument"); dUASSERT (stepsize > 0, "stepsize must be > 0"); processIslandsFast (w, stepsize, maxiterations); } ode-0.14/contrib/BreakableJoints/test_breakable.cpp0000644000000000000000000003056712635011627021073 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* buggy with suspension. this also shows you how to use geom groups. */ #include #include #include #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCappedCylinder dsDrawCappedCylinderD #endif // some constants #define LENGTH 0.7 // chassis length #define WIDTH 0.4 // chassis width #define HEIGHT 0.2 // chassis height #define RADIUS 0.22 // wheel radius #define STARTZ 0.4 // starting height of chassis #define CMASS 1 // chassis mass #define WMASS 0.2 // wheel mass // dynamics and collision objects (chassis, 4 wheels, environment, obstacles, chain) static dWorldID world; static dSpaceID space; // chain stuff static const float chain_radius = 0.1; static const float chain_mass = 0.1; static const int chain_num = 10; static dBodyID chain_body[chain_num]; static dGeomID chain_geom[chain_num]; static dJointID chain_joint[chain_num-1]; // 1 chasses, 4 wheels static dBodyID body[5]; // joint[0] is left front wheel, joint[1] is right front wheel static dJointID joint[4]; static int joint_exists[4]; static dJointGroupID contactgroup; static dGeomID ground; static dSpaceID car_space; static dGeomID box[1]; static dGeomID sphere[4]; static dGeomID ground_box; static const int obstacle_num = 25; static dGeomID obstacle[obstacle_num]; // things that the user controls static dReal speed=0,steer=0; // user commands // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { int i,n; // // do not collide objects that are connected // dBodyID b1 = dGeomGetBody (o1), // b2 = dGeomGetBody (o2); // if (b1 && b2 && dAreConnected(b1, b2)) return; const int N = 10; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact)); if (n > 0) { for (i=0; i 0.1) v = 0.1; if (v < -0.1) v = -0.1; v *= 10.0; dJointSetHinge2Param (joint[i],dParamVel,v); dJointSetHinge2Param (joint[i],dParamFMax,0.2); dJointSetHinge2Param (joint[i],dParamLoStop,-0.75); dJointSetHinge2Param (joint[i],dParamHiStop,0.75); dJointSetHinge2Param (joint[i],dParamFudgeFactor,0.1); } } dSpaceCollide (space,0,&nearCallback); //dWorldStep (world,0.05); dWorldStepFast1 (world,0.05,5); // remove all contact joints dJointGroupEmpty (contactgroup); } dsSetColor (0,1,1); dsSetTexture (DS_WOOD); dReal sides[3] = {LENGTH,WIDTH,HEIGHT}; dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides); dsSetColor (1,1,1); for (i=1; i<=4; i++) dsDrawCylinder (dBodyGetPosition(body[i]), dBodyGetRotation(body[i]), 0.2, RADIUS); dVector3 ss; dGeomBoxGetLengths (ground_box,ss); dsDrawBox (dGeomGetPosition(ground_box),dGeomGetRotation(ground_box),ss); dsSetColor (1,0,0); for (i=0; i #include #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCappedCylinder dsDrawCappedCylinderD #endif // some constants #define LENGTH 0.7 // chassis length #define WIDTH 0.5 // chassis width #define HEIGHT 0.2 // chassis height #define RADIUS 0.18 // wheel radius #define STARTZ 0.5 // starting height of chassis #define CMASS 1 // chassis mass #define WMASS 0.2 // wheel mass // dynamics and collision objects (chassis, 3 wheels, environment) static dWorldID world; static dSpaceID space; static dBodyID body[4]; static dJointID joint[3]; // joint[0] is the front wheel static dJointGroupID contactgroup; static dGeomID ground; static dSpaceID car_space; static dGeomID box[1]; static dGeomID sphere[3]; static dGeomID ground_box; // things that the user controls static dReal speed=0,steer=0; // user commands // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { int i,n; // only collide things with the ground int g1 = (o1 == ground || o1 == ground_box); int g2 = (o2 == ground || o2 == ground_box); if (!(g1 ^ g2)) return; const int N = 10; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact)); if (n > 0) { for (i=0; i 0.1) v = 0.1; if (v < -0.1) v = -0.1; v *= 10.0; dJointSetHinge2Param (joint[0],dParamVel,v); dJointSetHinge2Param (joint[0],dParamFMax,0.2); dJointSetHinge2Param (joint[0],dParamLoStop,-0.75); dJointSetHinge2Param (joint[0],dParamHiStop,0.75); dJointSetHinge2Param (joint[0],dParamFudgeFactor,0.1); dSpaceCollide (space,0,&nearCallback); dWorldStep (world,0.05); // remove all contact joints dJointGroupEmpty (contactgroup); } dsSetColor (0,1,1); dsSetTexture (DS_WOOD); dReal sides[3] = {LENGTH,WIDTH,HEIGHT}; dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides); dsSetColor (1,1,1); for (i=1; i<=3; i++) dsDrawCylinder (dBodyGetPosition(body[i]), dBodyGetRotation(body[i]),0.02f,RADIUS); dVector3 ss; dGeomBoxGetLengths (ground_box,ss); dsDrawBox (dGeomGetPosition(ground_box),dGeomGetRotation(ground_box),ss); /* printf ("%.10f %.10f %.10f %.10f\n", dJointGetHingeAngle (joint[1]), dJointGetHingeAngle (joint[2]), dJointGetHingeAngleRate (joint[1]), dJointGetHingeAngleRate (joint[2])); */ } int main (int argc, char **argv) { int i; dMass m; // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = "../../drawstuff/textures"; if(argc==2) { fn.path_to_textures = argv[1]; } // create world world = dWorldCreate(); space = dHashSpaceCreate (0); contactgroup = dJointGroupCreate (0); dWorldSetGravity (world,0,0,-0.5); ground = dCreatePlane (space,0,0,1,0); // chassis body body[0] = dBodyCreate (world); dBodySetPosition (body[0],0,0,STARTZ); dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT); dMassAdjust (&m,CMASS); dBodySetMass (body[0],&m); box[0] = dCreateBox (0,LENGTH,WIDTH,HEIGHT); dGeomSetBody (box[0],body[0]); // wheel bodies for (i=1; i<=3; i++) { body[i] = dBodyCreate (world); dQuaternion q; dQFromAxisAndAngle (q,1,0,0,M_PI*0.5); dBodySetQuaternion (body[i],q); dMassSetSphere (&m,1,RADIUS); dMassAdjust (&m,WMASS); dBodySetMass (body[i],&m); sphere[i-1] = dCreateSphere (0,RADIUS); dGeomSetBody (sphere[i-1],body[i]); } dBodySetPosition (body[1],0.5*LENGTH,0,STARTZ-HEIGHT*0.5); dBodySetPosition (body[2],-0.5*LENGTH, WIDTH*0.5,STARTZ-HEIGHT*0.5); dBodySetPosition (body[3],-0.5*LENGTH,-WIDTH*0.5,STARTZ-HEIGHT*0.5); // front wheel hinge /* joint[0] = dJointCreateHinge2 (world,0); dJointAttach (joint[0],body[0],body[1]); const dReal *a = dBodyGetPosition (body[1]); dJointSetHinge2Anchor (joint[0],a[0],a[1],a[2]); dJointSetHinge2Axis1 (joint[0],0,0,1); dJointSetHinge2Axis2 (joint[0],0,1,0); */ // front and back wheel hinges for (i=0; i<3; i++) { joint[i] = dJointCreateHinge2 (world,0); dJointAttach (joint[i],body[0],body[i+1]); const dReal *a = dBodyGetPosition (body[i+1]); dJointSetHinge2Anchor (joint[i],a[0],a[1],a[2]); dJointSetHinge2Axis1 (joint[i],0,0,1); dJointSetHinge2Axis2 (joint[i],0,1,0); // breakable joints contribution // the wheels can break dJointSetBreakable (joint[i], 1); // the wheels wil break at a specific force dJointSetBreakMode (joint[i], dJOINT_BREAK_AT_B1_FORCE|dJOINT_BREAK_AT_B2_FORCE); // specify the force for the first body connected to the joint ... dJointSetBreakForce (joint[i], 0, 1.5, 1.5, 1.5); // and for the second body dJointSetBreakForce (joint[i], 1, 1.5, 1.5, 1.5); } // set joint suspension for (i=0; i<3; i++) { dJointSetHinge2Param (joint[i],dParamSuspensionERP,0.4); dJointSetHinge2Param (joint[i],dParamSuspensionCFM,0.8); } // lock back wheels along the steering axis for (i=1; i<3; i++) { // set stops to make sure wheels always stay in alignment dJointSetHinge2Param (joint[i],dParamLoStop,0); dJointSetHinge2Param (joint[i],dParamHiStop,0); // the following alternative method is no good as the wheels may get out // of alignment: // dJointSetHinge2Param (joint[i],dParamVel,0); // dJointSetHinge2Param (joint[i],dParamFMax,dInfinity); } // create car space and add it to the top level space car_space = dSimpleSpaceCreate (space); dSpaceSetCleanup (car_space,0); dSpaceAdd (car_space,box[0]); dSpaceAdd (car_space,sphere[0]); dSpaceAdd (car_space,sphere[1]); dSpaceAdd (car_space,sphere[2]); // environment ground_box = dCreateBox (space,2,1.5,1); dMatrix3 R; dRFromAxisAndAngle (R,0,1,0,-0.15); dGeomSetPosition (ground_box,2,0,-0.34); dGeomSetRotation (ground_box,R); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); dGeomDestroy (box[0]); dGeomDestroy (sphere[0]); dGeomDestroy (sphere[1]); dGeomDestroy (sphere[2]); return 0; } ode-0.14/contrib/DotNetManaged/0000775000000000000000000000000012635012023015011 5ustar rootrootode-0.14/contrib/DotNetManaged/AssemblyInfo.cpp0000644000000000000000000000434012635011627020120 0ustar rootroot#include "stdafx.h" using namespace System::Reflection; using namespace System::Runtime::CompilerServices; // // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. // [assembly:AssemblyTitleAttribute("")]; [assembly:AssemblyDescriptionAttribute("")]; [assembly:AssemblyConfigurationAttribute("")]; [assembly:AssemblyCompanyAttribute("")]; [assembly:AssemblyProductAttribute("")]; [assembly:AssemblyCopyrightAttribute("")]; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; // // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the value or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly:AssemblyVersionAttribute("1.0.*")]; // // In order to sign your assembly you must specify a key to use. Refer to the // Microsoft .NET Framework documentation for more information on assembly signing. // // Use the attributes below to control which key is used for signing. // // Notes: // (*) If no key is specified, the assembly is not signed. // (*) KeyName refers to a key that has been installed in the Crypto Service // Provider (CSP) on your machine. KeyFile refers to a file which contains // a key. // (*) If the KeyFile and the KeyName values are both specified, the // following processing occurs: // (1) If the KeyName can be found in the CSP, that key is used. // (2) If the KeyName does not exist and the KeyFile does exist, the key // in the KeyFile is installed into the CSP and used. // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. // When specifying the KeyFile, the location of the KeyFile should be // relative to the project directory. // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework // documentation for more information on this. // [assembly:AssemblyDelaySignAttribute(false)]; [assembly:AssemblyKeyFileAttribute("")]; [assembly:AssemblyKeyNameAttribute("")]; ode-0.14/contrib/DotNetManaged/Body.cpp0000644000000000000000000001432112635011627016422 0ustar rootroot#include "StdAfx.h" #include #include "Body.h" namespace ODEManaged { //Constructors Body::Body(void) { _id = 0; } Body::Body(World &world) { _id = dBodyCreate(world.Id()); } //Destructor Body::~Body(void) { dBodyDestroy(this->_id); } //Methods //Id dBodyID Body::Id() { return _id; } //SetData void Body::SetData(void *data) { dBodySetData(this->_id, data); } //GetData void *Body::GetData(void) { return dBodyGetData(this->_id); } //SetPosition void Body::SetPosition (double x, double y, double z) { dBodySetPosition(this->_id, x, y, z); } //Overloaded GetPosition Vector3 Body::GetPosition(void) { Vector3 retVal; const dReal *temp; temp = dBodyGetPosition(this->_id); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; }; void Body::GetPosition(double position __gc[]) { const dReal *temp; temp = dBodyGetPosition(this->_id); position[0] = temp[0]; position[1] = temp[1]; position[2] = temp[2]; } //SetRotationIdentity void Body::SetRotationIdentity(void) { dMatrix3 temp; dRSetIdentity(temp); dBodySetRotation(this->_id, temp); } //SetRotation (left handed system=>transpose) void Body::SetRotation(Matrix3 rotation) { dMatrix3 temp; temp[0] = rotation.m11; temp[4] = rotation.m12; temp[8] = rotation.m13; temp[1] = rotation.m21; temp[5] = rotation.m22; temp[9] = rotation.m23; temp[2] = rotation.m31; temp[6] = rotation.m32; temp[10] = rotation.m33; dBodySetRotation(this->_id, temp); } //GetRotation (left handed system=>transpose) Matrix3 Body::GetRotation(void) { Matrix3 retVal; //const dMatrix3 *m; const dReal *temp; temp = dBodyGetRotation(this->_id); retVal.m11 = temp[0]; retVal.m12 = temp[4]; retVal.m13 = temp[8]; retVal.m21 = temp[1]; retVal.m22 = temp[5]; retVal.m23 = temp[9]; retVal.m31 = temp[2]; retVal.m32 = temp[6]; retVal.m33 = temp[10]; return retVal; } //Overloaded SetMass void Body::SetMass(double mass, Vector3 centerOfGravity, Matrix3 inertia) { dMass *temp = new dMass(); dMassSetParameters(temp, mass, centerOfGravity.x, centerOfGravity.y, centerOfGravity.z, inertia.m11, inertia.m22, inertia.m33, inertia.m12, inertia.m13, inertia.m23); dBodySetMass(this->_id, temp); } //SetMassSphere void Body::SetMassSphere(double density, double radius) { dMass *temp = new dMass(); dMassSetSphere(temp, density, radius); dBodySetMass(this->_id, temp); } //SetMassBox void Body::SetMassBox(double density, double sideX, double sideY, double sideZ) { dMass *temp = new dMass(); dMassSetBox(temp, density, sideX, sideY, sideZ); dBodySetMass(this->_id, temp); } //SetMassCappedCylinder void Body::SetMassCappedCylinder(double density, int axis, double cylinderRadius, double cylinderLength) { dMass *temp = new dMass(); dMassSetCappedCylinder(temp, density, axis, cylinderRadius, cylinderLength); dBodySetMass(this->_id, temp); } //AddForce void Body::AddForce(double fX, double fY, double fZ) { dBodyAddForce(this->_id, fX, fY, fZ); } //AddRelForce void Body::AddRelForce(double fX, double fY, double fZ) { dBodyAddRelForce(this->_id, fX,fY,fZ); } //AddForceAtPos void Body::AddForceAtPos(double fX, double fY, double fZ, double pX, double pY, double pZ) { dBodyAddForceAtPos(this->_id, fX, fY, fZ, pX, pY, pZ); } //AddRelForceAtPos void Body::AddRelForceAtPos(double fX, double fY, double fZ, double pX, double pY, double pZ) { dBodyAddRelForceAtPos(this->_id, fX, fY, fZ, pX, pY, pZ); } //AddRelForceAtRelPos void Body::AddRelForceAtRelPos(double fX, double fY, double fZ, double pX, double pY, double pZ) { dBodyAddRelForceAtRelPos(this->_id, fX, fY, fZ, pX, pY, pZ); } //ApplyLinearVelocityDrag void Body::ApplyLinearVelocityDrag(double dragCoef) { const dReal *temp; double fX; double fY; double fZ; temp = dBodyGetLinearVel(this->_id); fX = temp[0]*dragCoef*-1; fY = temp[1]*dragCoef*-1; fZ = temp[2]*dragCoef*-1; dBodyAddForce(this->_id, fX, fY, fZ); } //ApplyAngularVelocityDrag void Body::ApplyAngularVelocityDrag(double dragCoef) { const dReal *temp; double fX; double fY; double fZ; temp = dBodyGetAngularVel(this->_id); fX = temp[0]*dragCoef*-1; fY = temp[1]*dragCoef*-1; fZ = temp[2]*dragCoef*-1; dBodyAddTorque(this->_id, fX, fY, fZ); } //AddTorque void Body::AddTorque(double fX, double fY, double fZ) { dBodyAddTorque(this->_id, fX, fY, fZ); } //AddRelTorque void Body::AddRelTorque(double fX, double fY, double fZ) { dBodyAddRelTorque(this->_id, fX,fY,fZ); } //SetLinearVelocity void Body::SetLinearVelocity(double x, double y, double z) { dBodySetLinearVel(this->_id, x, y, z); } //GetLinearVelocity Vector3 Body::GetLinearVelocity(void) { Vector3 retVal; const dReal *temp; temp = dBodyGetLinearVel(this->_id); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //SetAngularVelocity void Body::SetAngularVelocity(double x, double y, double z) { dBodySetAngularVel(this->_id, x, y, z); } //GetAngularVelocity Vector3 Body::GetAngularVelocity(void) { Vector3 retVal; const dReal *temp; temp = dBodyGetAngularVel(this->_id); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //GetRelPointPos Vector3 Body::GetRelPointPos(double pX, double pY, double pZ) { Vector3 retVal; dVector3 temp; dBodyGetRelPointPos(this->_id, pX, pY, pZ, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //GetRelPointVel Vector3 Body::GetRelPointVel(double pX, double pY, double pZ) { Vector3 retVal; dVector3 temp; dBodyGetRelPointVel(this->_id, pX, pY, pZ, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //ConnectedTo int Body::ConnectedTo(const Body &b) { return dAreConnected(this->_id, b._id); } } ode-0.14/contrib/DotNetManaged/Body.h0000644000000000000000000000366312635011627016076 0ustar rootroot#pragma once #include "World.h" #include "CommonMgd.h" namespace ODEManaged { __gc public class Body { public: //Constructors and Destructors Body(void); Body(World &world); ~Body(void); //Public Methods dBodyID Id(); void SetData (void *data); void *GetData (void); //POSITION void SetPosition(double x, double y, double z); Vector3 GetPosition(void); void GetPosition(double position __gc[]); //ROTATION void SetRotationIdentity(void); void SetRotation(Matrix3 rotation); Matrix3 GetRotation(void); //MASS void SetMass(double mass, Vector3 centerOfGravity, Matrix3 inertia); void SetMassSphere(double density, double radius); void SetMassBox(double density, double sideX, double sideY, double sideZ); void SetMassCappedCylinder(double density, int axis, double cylinderRadius, double cylinderLength); //FORCE AND TORQUE void AddForce(double fX, double fY, double fZ); void AddRelForce(double fX, double fY, double fZ); void AddForceAtPos(double fX, double fY, double fZ,double pX, double pY, double pZ); void AddRelForceAtPos(double fX, double fY, double fZ,double pX, double pY, double pZ); void AddRelForceAtRelPos(double fX, double fY, double fZ,double pX, double pY, double pZ); void ApplyLinearVelocityDrag(double dragCoef); void ApplyAngularVelocityDrag(double dragCoef); void AddTorque(double fX, double fY, double fZ); void AddRelTorque(double fX, double fY, double fZ); //LINEAR VELOCITY void SetLinearVelocity (double x, double y, double z); Vector3 GetLinearVelocity(void); //ANGULAR VELOCITY void SetAngularVelocity (double x, double y, double z); Vector3 GetAngularVelocity(void); //POINT Vector3 GetRelPointPos(double pX, double pY, double pZ); Vector3 GetRelPointVel(double pX, double pY, double pZ); //CONNECTED TO int ConnectedTo (const Body &b); private: dBodyID _id; }; } ode-0.14/contrib/DotNetManaged/CommonMgd.h0000644000000000000000000000072212635011627017052 0ustar rootroot#pragma once namespace ODEManaged { __value public struct Vector3 { double x; double y; double z; }; __value public struct Vector4 { double W; double x; double y; double z; }; __value public struct Matrix3 { double m11; double m12; double m13; double m21; double m22; double m23; double m31; double m32; double m33; }; //__value public struct NearCallback //{ // void *data; // dGeomID o1; // dGeomID o2; //}; }ode-0.14/contrib/DotNetManaged/DotNetManaged.sln0000644000000000000000000000161112635011627020207 0ustar rootrootMicrosoft Visual Studio Solution File, Format Version 7.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DotNetManaged", "DotNetManaged.vcproj", "{4B75AC19-971A-4CC6-A4F5-0695C9F8562F}" EndProject Global GlobalSection(SolutionConfiguration) = preSolution ConfigName.0 = Debug ConfigName.1 = Release EndGlobalSection GlobalSection(ProjectDependencies) = postSolution EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {4B75AC19-971A-4CC6-A4F5-0695C9F8562F}.Debug.ActiveCfg = Debug|Win32 {4B75AC19-971A-4CC6-A4F5-0695C9F8562F}.Debug.Build.0 = Debug|Win32 {4B75AC19-971A-4CC6-A4F5-0695C9F8562F}.Release.ActiveCfg = Release|Win32 {4B75AC19-971A-4CC6-A4F5-0695C9F8562F}.Release.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal ode-0.14/contrib/DotNetManaged/DotNetManaged.vcproj0000644000000000000000000002157212635011627020726 0ustar rootroot ode-0.14/contrib/DotNetManaged/Geom.cpp0000644000000000000000000000677012635011627016425 0ustar rootroot #include "StdAfx.h" #include #include "Geom.h" namespace ODEManaged { //Constructors Geom::Geom(void) { _id = 0; } //Destructor Geom::~Geom(void) { dGeomDestroy(this->_id); } //Methods //Id dGeomID Geom::Id(void) { return _id; } //GetBody dBodyID Geom::GetBody(void) { return dGeomGetBody(this->_id); } //Overloaded SetBody void Geom::SetBody(Body &body) { dGeomSetBody(this->_id, body.Id()); } //void Geom::SetBody(dBodyID b) //{ // dGeomSetBody(this->_id, b); //} //SetPosition void Geom::SetPosition(double x, double y, double z) { dGeomSetPosition(this->_id, x, y, z); } //SetRotation void Geom::SetRotation(Matrix3 rotation) { dMatrix3 temp; temp[0] = rotation.m11; temp[4] = rotation.m12; temp[8] = rotation.m13; temp[1] = rotation.m21; temp[5] = rotation.m22; temp[9] = rotation.m23; temp[2] = rotation.m31; temp[6] = rotation.m32; temp[10] = rotation.m33; dGeomSetRotation(_id, temp); } //Destroy void Geom::Destroy() { if(this->_id) dGeomDestroy(this->_id); _id = 0; } //SetData void Geom::SetData(void *data) { dGeomSetData(this->_id, data); } //GetData void *Geom::GetData(void) { return dGeomGetData(this->_id); } //GetPosition Vector3 Geom::GetPosition(void) { Vector3 retVal; const dReal *temp; temp = dGeomGetPosition(this->_id); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //GetRotation (left handed system=>transpose) Matrix3 Geom::GetRotation(void) { Matrix3 retVal; const dReal *temp; temp = dGeomGetRotation(this->_id); retVal.m11 = temp[0]; retVal.m12 = temp[4]; retVal.m13 = temp[8]; retVal.m21 = temp[1]; retVal.m22 = temp[5]; retVal.m23 = temp[9]; retVal.m31 = temp[2]; retVal.m32 = temp[6]; retVal.m33 = temp[10]; return retVal; } //CreateSphere void Geom::CreateSphere(Space &space, double radius) { if(this->_id) dGeomDestroy(this->_id); _id = dCreateSphere(space.Id(), radius); } //CreateBox void Geom::CreateBox(Space &space, double lx, double ly, double lz) { if(this->_id) dGeomDestroy(this->_id); _id = dCreateBox(space.Id(), lx, ly, lz); } //CreatePlane void Geom::CreatePlane(Space &space, double a, double b, double c, double d) { if(this->_id) dGeomDestroy(this->_id); _id = dCreatePlane(space.Id(), a, b, c, d); } //CreateCCylinder void Geom::CreateCCylinder(Space &space, double radius, double length) { if(this->_id) dGeomDestroy(this->_id); _id = dCreateCCylinder(space.Id(), radius, length); } //SphereGetRadius double Geom::SphereGetRadius(void) { return dGeomSphereGetRadius(this->_id); } //BoxGetLengths Vector3 Geom::BoxGetLengths(void) { Vector3 retVal; dVector3 temp; dGeomBoxGetLengths(this->_id, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //PlaneGetParams Vector4 Geom::PlaneGetParams(void) { Vector4 retVal; dVector4 temp; dGeomPlaneGetParams(this->_id, temp); retVal.W = temp[0]; retVal.x = temp[1]; retVal.y = temp[2]; retVal.z = temp[3]; return retVal; } //CCylinderGetParams void Geom::CCylinderGetParams(double *radius, double *length) { dGeomCCylinderGetParams(this->_id, radius, length); } //GetClass int Geom::GetClass(void) { return dGeomGetClass(this->_id); } } ode-0.14/contrib/DotNetManaged/Geom.h0000644000000000000000000000242712635011627016065 0ustar rootroot#pragma once #include "Body.h" #include "Space.h" #include "CommonMgd.h" namespace ODEManaged { __gc public class Geom { public: //Constructor Geom (void); //Destructor ~Geom (void); //Methods //Basic Stuff dGeomID Id (void); dBodyID GetBody (void); //Overloaded SetBody void SetBody (Body &body); /*void SetBody (dBodyID b);*/ Vector3 GetPosition (void); void SetPosition (double x, double y, double z); Matrix3 GetRotation (void); void SetRotation (Matrix3 rotation); void SetData (void *data); void *GetData (void); //Create Objects void CreateSphere (Space &space, double radius); void CreateBox (Space &space, double lx, double ly, double lz); void CreatePlane (Space &space, double a, double b, double c, double d); void CreateCCylinder (Space &space, double radius, double length); //Destroy Objects void Destroy (void); //Get Object's Parameters double SphereGetRadius (void); Vector3 BoxGetLengths (void); Vector4 PlaneGetParams (void); void CCylinderGetParams (double *radius, double *length); int GetClass (void); //Properties private: dGeomID _id; }; } ode-0.14/contrib/DotNetManaged/Joint.cpp0000644000000000000000000000051612635011627016611 0ustar rootroot#include "StdAfx.h" #include #include "joint.h" #include "CommonMgd.h" #include "world.h" namespace ODEManaged { //Constructor Joint::Joint(void) { _id=0; } //Destructor Joint::~Joint(void) { dJointDestroy(this->_id); } //Methods //Id dJointID Joint::Id(void) { return _id; } } ode-0.14/contrib/DotNetManaged/Joint.h0000644000000000000000000000042612635011627016256 0ustar rootroot#pragma once #include "JointGroup.h" #include "World.h" #include "Body.h" namespace ODEManaged { __gc public class Joint { protected: //Constructor and Destructor Defenition Joint(void); ~Joint(void); //Public Methods dJointID Id(void); dJointID _id; }; } ode-0.14/contrib/DotNetManaged/JointAMotor.cpp0000644000000000000000000000524412635011627017736 0ustar rootroot#include "StdAfx.h" #include #include "JointAMotor.h" namespace ODEManaged { //Constructors JointAMotor::JointAMotor(void) : Joint(){} JointAMotor::JointAMotor(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateAMotor(world.Id(), 0); } JointAMotor::JointAMotor(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateAMotor(world.Id(), jointGroup.Id()); } //Destructor JointAMotor::~JointAMotor(void){} //Methods //Overloaded Create void JointAMotor::Create(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateAMotor(world.Id(), jointGroup.Id()); } void JointAMotor::Create(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateAMotor(world.Id(), 0); } //Overloaded Attach void JointAMotor::Attach(Body &body1, Body &body2) { dJointAttach(this->_id, body1.Id(), body2.Id()); } void JointAMotor::Attach(Body &body1) { dJointAttach(this->_id, body1.Id(), 0); } //SetNumAxes void JointAMotor::SetNumAxes(int num) { dJointSetAMotorNumAxes(this->_id, num); } //GetNumAxes int JointAMotor::GetNumAxes(void) { return dJointGetAMotorNumAxes(this->_id); } //SetAxis void JointAMotor::SetAxis(int anum, int rel, double x, double y ,double z) { dJointSetAMotorAxis(this->_id, anum, rel, x, y, z); } //GetAxis Vector3 JointAMotor::GetAxis(int anum) { Vector3 retVal; dVector3 temp; dJointGetAMotorAxis(this->_id, anum, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //SetAngle void JointAMotor::SetAngle(int anum, double angle) { dJointSetAMotorAngle(this->_id, anum, angle); } //GetAngle double JointAMotor::GetAngle(int anum) { return dJointGetAMotorAngle(this->_id, anum); } //SetParam void JointAMotor::SetParam(int parameter, double value) { dJointSetAMotorParam(this->_id, parameter, value); } //GetParam double JointAMotor::GetParam(int parameter) { return dJointGetAMotorParam(this->_id, parameter); } //SetMode void JointAMotor::SetMode(int mode) { dJointSetAMotorMode(this->_id, mode); } //GetMode int JointAMotor::GetMode(void) { return dJointGetAMotorMode(this->_id); } //GetAxisRel int JointAMotor::GetAxisRel(int anum) { return dJointGetAMotorAxisRel(this->_id, anum); } //GetAngleRate double JointAMotor::GetAngleRate(int anum) { return dJointGetAMotorAngleRate(this->_id, anum); } } ode-0.14/contrib/DotNetManaged/JointAMotor.h0000644000000000000000000000206712635011627017403 0ustar rootroot#pragma once #include "Joint.h" namespace ODEManaged { __gc public class JointAMotor : public Joint { public: //Constructors JointAMotor (void); JointAMotor (World &world); JointAMotor (World &world, JointGroup &jointGroup); //Destructor virtual ~JointAMotor (void); //Methods //Basic Stuff //Overloaded Create void Create (World &world, JointGroup &jointGroup); void Create (World &world); void SetNumAxes (int num); int GetNumAxes (void); void SetAxis (int anum, int rel, double x, double y, double z); Vector3 GetAxis (int anum); void SetAngle (int anum, double angle); double GetAngle (int anum); void SetMode (int mode); int GetMode (void); int GetAxisRel (int anum); double GetAngleRate (int anum); //Overloaded Attach void Attach (Body &body1, Body &body2); void Attach (Body &body1); //Movement Parameters void SetParam (int parameter, double value); double GetParam (int parameter); }; } ode-0.14/contrib/DotNetManaged/JointBall.cpp0000644000000000000000000000261412635011627017405 0ustar rootroot#include "StdAfx.h" #include #include "jointball.h" namespace ODEManaged { //Constructors JointBall::JointBall(void) : Joint(){} JointBall::JointBall(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateBall(world.Id(), 0); } JointBall::JointBall(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateBall(world.Id(), jointGroup.Id()); } //Destructor JointBall::~JointBall(void){} //Methods //Overloaded Create void JointBall::Create(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateBall(world.Id(), jointGroup.Id()); } void JointBall::Create(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateBall(world.Id(), 0); } //Overloaded Attach void JointBall::Attach(Body &body1, Body &body2) { dJointAttach(this->_id, body1.Id(), body2.Id()); } void JointBall::Attach(Body &body1) { dJointAttach(this->_id, body1.Id(), 0); } //SetAnchor void JointBall::SetAnchor(double x, double y ,double z) { dJointSetBallAnchor(this->_id, x, y, z); } //GetAnchor Vector3 JointBall::GetAnchor(void) { Vector3 retVal; dVector3 temp; dJointGetBallAnchor(this->_id,temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } } ode-0.14/contrib/DotNetManaged/JointBall.h0000644000000000000000000000111712635011627017047 0ustar rootroot#pragma once #include "Joint.h" namespace ODEManaged { __gc public class JointBall : public Joint { public: //Constructors JointBall(void); JointBall(World &world); JointBall(World &world, JointGroup &jointGroup); //Destructors virtual ~JointBall(void); //Methods //Overloaded Create void Create(World &world, JointGroup &jointGroup); void Create(World &world); //Overloaded Attach void Attach(Body &body1, Body &body2); void Attach(Body &body1); void SetAnchor(double x, double y, double z); Vector3 GetAnchor(void); }; } ode-0.14/contrib/DotNetManaged/JointFixed.cpp0000644000000000000000000000222112635011627017564 0ustar rootroot#include "StdAfx.h" #include #include "jointfixed.h" namespace ODEManaged { //Constructors JointFixed::JointFixed(void) : Joint(){} JointFixed::JointFixed(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateFixed(world.Id(),0); } JointFixed::JointFixed(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateFixed(world.Id(), jointGroup.Id()); } //Destructor JointFixed::~JointFixed(void){} //Methods //Overloaded Create void JointFixed::Create(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateFixed(world.Id(), jointGroup.Id()); } void JointFixed::Create(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateFixed(world.Id(), 0); } //Overloaded Attach void JointFixed::Attach(Body &body1, Body &body2) { dJointAttach(this->_id, body1.Id(), body2.Id()); } void JointFixed::Attach(Body &body1) { dJointAttach(this->_id, body1.Id(), 0); } //Fixed void JointFixed::SetFixed(void) { dJointSetFixed(this->_id); } } ode-0.14/contrib/DotNetManaged/JointFixed.h0000644000000000000000000000103612635011627017234 0ustar rootroot#pragma once #include "Joint.h" namespace ODEManaged { __gc public class JointFixed : public Joint { public: //Constructors JointFixed(void); JointFixed(World &world); JointFixed(World &world, JointGroup &jointGroup); //Destructor virtual ~JointFixed(void); //Methods //Overloaded Create void Create(World &world, JointGroup &jointGroup); void Create(World &world); //Overloaded Attach void Attach(Body &body1, Body &body2); void Attach(Body &body1); void SetFixed(void); }; } ode-0.14/contrib/DotNetManaged/JointGroup.cpp0000644000000000000000000000117112635011627017624 0ustar rootroot#include "StdAfx.h" #include #include "jointgroup.h" namespace ODEManaged { //Constructors JointGroup::JointGroup(void) { _id=0; } JointGroup::JointGroup (int maxSize) { _id = dJointGroupCreate(maxSize); } //Destructor JointGroup::~JointGroup(void) { dJointGroupDestroy(this->_id); } //Methods //ID dJointGroupID JointGroup::Id() { return _id; } //Create void JointGroup::Create (int maxSize) { if(_id) dJointGroupDestroy(_id); _id = dJointGroupCreate(maxSize); } //Empty void JointGroup::Empty (void) { dJointGroupEmpty(this->_id); } } ode-0.14/contrib/DotNetManaged/JointGroup.h0000644000000000000000000000051112635011627017266 0ustar rootroot#pragma once namespace ODEManaged { __gc public class JointGroup { public: //Constructors JointGroup(void); JointGroup(int maxSize); //Destructor ~JointGroup(void); //Methods dJointGroupID Id(void); void Create(int maxSize); void Empty(void); private: dJointGroupID _id; }; } ode-0.14/contrib/DotNetManaged/JointHinge.cpp0000644000000000000000000000505512635011627017567 0ustar rootroot#include "stdafx.h" #include #include "jointhinge.h" namespace ODEManaged { //Constructors JointHinge::JointHinge(void) : Joint(){} JointHinge::JointHinge(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge(world.Id(), 0); } JointHinge::JointHinge(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge(world.Id(), jointGroup.Id()); } //Destructor JointHinge::~JointHinge(void){} //Methods //Overloaded Create void JointHinge::Create(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge(world.Id(), jointGroup.Id()); } void JointHinge::Create(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge(world.Id(), 0); } //Overloaded Attach void JointHinge::Attach(Body &body1, Body &body2) { dJointAttach(this->_id, body1.Id(), body2.Id()); } void JointHinge::Attach(Body &body1) { dJointAttach(this->_id, body1.Id(), 0); } //SetAxis void JointHinge::SetAxis(double x, double y, double z) { dJointSetHingeAxis(this->_id, x, y, z); } //GetAxis Vector3 JointHinge::GetAxis(void) { Vector3 retVal; dVector3 temp; dJointGetHingeAxis(this->_id, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //SetAnchor void JointHinge::SetAnchor(double x, double y, double z) { dJointSetHingeAnchor(this->_id, x, y, z); } //GetAnchor Vector3 JointHinge::GetAnchor(void) { Vector3 retVal; dVector3 temp; dJointGetHingeAnchor(this->_id, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //Movement Parameters //SetAllMovParams void JointHinge::SetAllMovParams(double LoStop, double HiStop, double Velocity, double MaxForce, double FudgeFactor, double Bounce, double StopERP, double StopCFM) { if (LoStop > -3.141592653 && LoStop <= 0) dJointSetHingeParam(this->_id, dParamLoStop, LoStop); if (HiStop < 3.141592653 && HiStop >= 0) dJointSetHingeParam(this->_id, dParamHiStop, HiStop); dJointSetHingeParam(this->_id, dParamVel, Velocity); dJointSetHingeParam(this->_id, dParamFMax, MaxForce); dJointSetHingeParam(this->_id, dParamFudgeFactor, FudgeFactor); dJointSetHingeParam(this->_id, dParamBounce, Bounce); dJointSetHingeParam(this->_id, dParamStopERP, StopERP); dJointSetHingeParam(this->_id, dParamStopCFM, StopCFM); } } ode-0.14/contrib/DotNetManaged/JointHinge.h0000644000000000000000000000742612635011627017240 0ustar rootroot#pragma once #include "Joint.h" #include "CommonMgd.h" namespace ODEManaged { __gc public class JointHinge : public Joint { public: //Constructors JointHinge(void); JointHinge(World &world); JointHinge(World &world, JointGroup &jointGroup); //Destructor virtual~JointHinge(void); //Methods //Overloaded Create void Create(World &world, JointGroup &jointGroup); void Create(World &world); //Overloaded Attach void Attach(Body &body1, Body &body2); void Attach(Body &body1); void SetAnchor(double x, double y, double z); Vector3 GetAnchor(void); void SetAxis(double x, double y, double z); Vector3 GetAxis(void); void SetAllMovParams(double LoStop, double HiStop, double Velocity, double MaxForce, double FudgeFactor, double Bounce, double StopERP, double StopCFM); //Properties //LoStop __property double get_LoStop(void) { return dJointGetHingeParam(this->_id, dParamLoStop); } __property void set_LoStop(double value) { if (value > -3.141592653 && value <= 0) dJointSetHingeParam(this->_id, dParamLoStop, value); } //HiStop __property double get_HiStop(void) { return dJointGetHingeParam(this->_id, dParamHiStop); } __property void set_HiStop(double value) { if (value < 3.141592653 && value >= 0) dJointSetHingeParam(this->_id, dParamHiStop, value); } //Velocity __property double get_Velocity(void) { return dJointGetHingeParam(this->_id, dParamVel); } __property void set_Velocity(double value) { dJointSetHingeParam(this->_id, dParamVel, value); } //MaxForce __property double get_MaxForce(void) { return dJointGetHingeParam(this->_id, dParamFMax); } __property void set_MaxForce(double value) { dJointSetHingeParam(this->_id, dParamFMax, value); } //FudgeFactor __property double get_FudgeFactor(void) { return dJointGetHingeParam(this->_id, dParamFudgeFactor); } __property void set_FudgeFactor(double value) { dJointSetHingeParam(this->_id, dParamFudgeFactor, value); } //Bounce __property double get_Bounce(void) { return dJointGetHingeParam(this->_id, dParamBounce); } __property void set_Bounce(double value) { dJointSetHingeParam(this->_id, dParamBounce, value); } //StopERP __property double get_StopERP(void) { return dJointGetHingeParam(this->_id, dParamStopERP); } __property void set_StopERP(double value) { dJointSetHingeParam(this->_id, dParamStopERP, value); } //StopCFM __property double get_StopCFM(void) { return dJointGetHingeParam(this->_id, dParamStopCFM); } __property void set_StopCFM(double value) { dJointSetHingeParam(this->_id, dParamStopCFM, value); } //GetAngle __property double get_Angle(void) { return dJointGetHingeAngle(this->_id); } //GetAngleRate __property double get_AngleRate(void) { return dJointGetHingeAngleRate(this->_id); } }; } // void SetSuspensionERP(double value); // double GetSuspensionERP(void); // void SetSuspensionCFM(double value); // double GetSuspensionCFM(void); /* //SetSuspensionERP void JointHinge::SetSuspensionERP(double value) { dJointSetHingeParam(this->_id, dParamSuspensionERP, value); } //GetSuspensionERP double JointHinge::GetSuspensionERP(void) { return dJointGetHingeParam(this->_id, dParamSuspensionERP); } //SetSuspensionCFM void JointHinge::SetSuspensionCFM(double value) { dJointSetHingeParam(this->_id, dParamSuspensionCFM, value); } //GetSuspensionCFM double JointHinge::GetSuspensionCFM(void) { return dJointGetHingeParam(this->_id, dParamSuspensionCFM); } */ ode-0.14/contrib/DotNetManaged/JointHinge2.cpp0000644000000000000000000000502012635011627017641 0ustar rootroot#include "StdAfx.h" #include #include "jointhinge2.h" namespace ODEManaged { //Constructors JointHinge2::JointHinge2(void) : Joint(){} JointHinge2::JointHinge2(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge2(world.Id(),0); } JointHinge2::JointHinge2(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge2(world.Id(), jointGroup.Id()); } //Destructor JointHinge2::~JointHinge2(void){} //CreateHinge2 (overload 1) void JointHinge2::Create(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge2(world.Id(), jointGroup.Id()); } //CreateHinge2 (overload 2) void JointHinge2::Create(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateHinge2(world.Id(),0); } //SetAnchor1 void JointHinge2::SetAnchor (double x, double y ,double z) { dJointSetHinge2Anchor(_id, x,y,z); } //GetAnchor1 Vector3 JointHinge2::GetAnchor() { Vector3 retVal; dVector3 temp; dJointGetHinge2Anchor(_id,temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //SetAxis1 void JointHinge2::SetAxis1 (double x, double y ,double z) { dJointSetHinge2Axis1(_id, x,y,z); } //GetAxis1 Vector3 JointHinge2::GetAxis1() { Vector3 retVal; dVector3 temp; dJointGetHinge2Axis1(_id,temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //SetAxis2 void JointHinge2::SetAxis2 (double x, double y ,double z) { dJointSetHinge2Axis2(_id, x,y,z); } //GetAxis2 Vector3 JointHinge2::GetAxis2() { Vector3 retVal; dVector3 temp; dJointGetHinge2Axis2(_id,temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //GetAngle1 double JointHinge2::GetAngle1 () { return dJointGetHinge2Angle1(this->_id); } //GetAngle1Rate double JointHinge2::GetAngle1Rate () { return dJointGetHinge2Angle1Rate(this->_id); } ////GetAngle hmm, this doesn't exist //double JointHinge2::GetAngle2 () //{ // return dJointGetHinge2Angle2(this->_id); //} //GetAngle2Rate double JointHinge2::GetAngle2Rate () { return dJointGetHinge2Angle2Rate(this->_id); } //Attach (overload 1) void JointHinge2::Attach (Body &body1, Body &body2) { dJointAttach(_id, body1.Id(),body2.Id()); } //Attach (overload 2) //TODO: possibly add an overload that takes anchor as a param also. void JointHinge2::Attach (Body &body1) { dJointAttach(_id, body1.Id(),0); } } ode-0.14/contrib/DotNetManaged/JointHinge2.h0000644000000000000000000000163212635011627017313 0ustar rootroot#pragma once #include "Joint.h" #include "CommonMgd.h" namespace ODEManaged { __gc public class JointHinge2 : public Joint { public: //Constructors JointHinge2 (void); JointHinge2 (World &world); JointHinge2 (World &world, JointGroup &jointGroup); //Destructors virtual ~JointHinge2 (void); //Methods //Overloaded Hinge.Create void Create (World &world, JointGroup &jointGroup); void Create (World &world); void SetAnchor (double x, double y, double z); Vector3 GetAnchor (void); void SetAxis1 (double x, double y, double z); Vector3 GetAxis1 (void); void SetAxis2 (double x, double y, double z); Vector3 GetAxis2 (void); double GetAngle1 (void); double GetAngle1Rate (void); //double GetAngle2 (void); double GetAngle2Rate (void); void Attach (Body &body1, Body &body2); void Attach( Body &body1); }; } ode-0.14/contrib/DotNetManaged/JointSlider.cpp0000644000000000000000000000426512635011627017761 0ustar rootroot#include "StdAfx.h" #include #include "jointslider.h" namespace ODEManaged { //Constructors JointSlider::JointSlider(void) : Joint(){} JointSlider::JointSlider(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateSlider(world.Id(), 0); } JointSlider::JointSlider(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateSlider(world.Id(), jointGroup.Id()); } //Destructor JointSlider::~JointSlider(void){} //Methods //Overloaded Create void JointSlider::Create(World &world, JointGroup &jointGroup) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateSlider(world.Id(), jointGroup.Id()); } void JointSlider::Create(World &world) { if(this->_id) dJointDestroy(this->_id); _id = dJointCreateSlider(world.Id(), 0); } //Overloaded Attach void JointSlider::Attach(Body &body1, Body &body2) { dJointAttach(this->_id, body1.Id(), body2.Id()); } void JointSlider::Attach(Body &body1) { dJointAttach(this->_id, body1.Id(), 0); } //SetAxis void JointSlider::SetAxis(double x, double y, double z) { dJointSetSliderAxis(this->_id, x, y, z); } //GetAxis Vector3 JointSlider::GetAxis(void) { Vector3 retVal; dVector3 temp; dJointGetSliderAxis(this->_id, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } //Movement Parameters //SetAllMovParams void JointSlider::SetAllMovParams(double LoStop, double HiStop, double Velocity, double MaxForce, double FudgeFactor, double Bounce, double StopERP, double StopCFM) { if (LoStop <= 0) dJointSetHingeParam(this->_id, dParamLoStop, LoStop); if (HiStop >= 0) dJointSetHingeParam(this->_id, dParamHiStop, HiStop); dJointSetSliderParam(this->_id, dParamVel, Velocity); dJointSetSliderParam(this->_id, dParamFMax, MaxForce); dJointSetSliderParam(this->_id, dParamFudgeFactor, FudgeFactor); dJointSetSliderParam(this->_id, dParamBounce, Bounce); dJointSetSliderParam(this->_id, dParamStopERP, StopERP); dJointSetSliderParam(this->_id, dParamStopCFM, StopCFM); } } ode-0.14/contrib/DotNetManaged/JointSlider.h0000644000000000000000000000571412635011627017426 0ustar rootroot#pragma once #include "Joint.h" #include "CommonMgd.h" namespace ODEManaged { __gc public class JointSlider : public Joint { public: //Constructors JointSlider(void); JointSlider(World &world); JointSlider(World &world, JointGroup &jointGroup); //Destructors virtual ~JointSlider(void); //Methods //Overloaded Create void Create(World &world, JointGroup &jointGroup); void Create(World &world); //Overloaded Attach void Attach(Body &body1, Body &body2); void Attach(Body &body1); void SetAxis(double x, double y, double z); Vector3 GetAxis(void); void SetAllMovParams(double LoStop, double HiStop, double Velocity, double MaxForce, double FudgeFactor, double Bounce, double StopERP, double StopCFM); //Properties //LoStop __property double get_LoStop(void) { return dJointGetSliderParam(this->_id, dParamLoStop); } __property void set_LoStop(double value) { if (value <=0) dJointSetSliderParam(this->_id, dParamLoStop, value); } //HiStop __property double get_HiStop(void) { return dJointGetSliderParam(this->_id, dParamHiStop); } __property void set_HiStop(double value) { if (value >= 0) dJointSetSliderParam(this->_id, dParamHiStop, value); } //Velocity __property double get_Velocity(void) { return dJointGetSliderParam(this->_id, dParamVel); } __property void set_Velocity(double value) { dJointSetSliderParam(this->_id, dParamVel, value); } //MaxForce __property double get_MaxForce(void) { return dJointGetSliderParam(this->_id, dParamFMax); } __property void set_MaxForce(double value) { dJointSetSliderParam(this->_id, dParamFMax, value); } //FudgeFactor __property double get_FudgeFactor(void) { return dJointGetSliderParam(this->_id, dParamFudgeFactor); } __property void set_FudgeFactor(double value) { dJointSetSliderParam(this->_id, dParamFudgeFactor, value); } //Bounce __property double get_Bounce(void) { return dJointGetSliderParam(this->_id, dParamBounce); } __property void set_Bounce(double value) { dJointSetSliderParam(this->_id, dParamBounce, value); } //StopERP __property double get_StopERP(void) { return dJointGetSliderParam(this->_id, dParamStopERP); } __property void set_StopERP(double value) { dJointSetSliderParam(this->_id, dParamStopERP, value); } //StopCFM __property double get_StopCFM(void) { return dJointGetSliderParam(this->_id, dParamStopCFM); } __property void set_StopCFM(double value) { dJointSetSliderParam(this->_id, dParamStopCFM, value); } //GetAngle __property double get_Position(void) { return dJointGetSliderPosition(this->_id); } //GetAngleRate __property double get_PositionRate(void) { return dJointGetSliderPositionRate(this->_id); } }; } ode-0.14/contrib/DotNetManaged/Release/0000775000000000000000000000000012635012023016371 5ustar rootrootode-0.14/contrib/DotNetManaged/Release/ode.dll0000755000000000000000000060000012635011627017643 0ustar rootrootMZ@ !L!This program cannot be run in DOS mode. $QzxQzxQzx^aSzx^8HzxYaTzxQzyzx^d+zx^eyzx^EPzxRichQzxPELa=! TPp$  8H.text `.rdata@@.data @.relocp @B0`2[XJ1QXJ X3 (  /Z 2XJ ,XXJZZ(T+ XZ(TXTT*0(*0(*0|@X(& X(&,@X( &+@X( &@X(&@X( &@X(&*%@́Tx3$TL$$P$\tT$$\R$\QRЃ K$XPhL$ jdQJT$$lRP$hQJ jT$RD$pPjƄ$_FJQD$ L$L$ tT$RT$ QRЃ YËD$T$PQhRYÐ0n# Y24Xd ZXXOXOZOOZXX XXY 5X1 OOZX XXY 5*0< Z  # #  2fXdbYO OZX ZXXYO ZXXO XO Z ZXXO Z X X  X  XY5X16O OZ ZXO Z X X  X  XY5OY WXXOYZXOZYW  X XX?*0< Z## # #     ? Xd   bY O OZXYXOZXYXOZXZ X Z X ZXXO XOZXXOZXXOX X ZXZ X Z X ZX Y  Bb X  1R  O OZXOZXOX X ZXZ X Z X ZX Y  5OYWZXO Y ZX WZXO XXO YZYWZXXZXXOY ZYWX X  X?X*0? Y=-Z (# ##   ?X\ZYO ZXXYO OZ ZWZXXYWZ X ZXZ X XO ZXXO XOZ ZXWZXXWZ X ZXZ X XO ZXXXO XOZ ZXWZXXXWZ X ZXZ X XO ZXXXO XOZ ZXWZXXXWZ X ZXZ X  XO ZXXXO  XOZ Z XWZXXXWZ X ZXZ X (XO ZXX XO (XOZ Z(XWZXX XWZ X ZXZ X 0X  0X YB X1YO ZXO OZ ZWZXWZ X ZXZ X X  X Y5ZXOYZXXO Y #?O Y[ ZXWZ ZXX#? ZY[WZXW X XX Y> Y9a.R8T ZZX (#   Y  ? X\Z X O  OZ WZ X XO  XOZ XWZ X XO  XOZ XWZ X XO  XOZ XWZ X  XO   XOZ  XWZ X (XO  (XOZ (XWZ X 0X 0X YBB X  1/ O  OZ WZ X X X Y5 ZX#?O Y[W*0Jb Z Y= ZX  ZYXdb# # ##   ?k  X \  ZYO OZX ZXXYOZ X  ZXXYOZX ZXXYOZXXO XOZX ZXXOZ X  ZXXOZX ZXXOZXXO XOZX ZXXXOZ X  ZXXXOZX ZXXXOZXXO XOZX ZXXXOZ X  ZXXXOZX ZXXXOZX XO  XOZX ZXXXOZ X  ZXXXOZX ZXXXOZX(XO (XOZX ZXX XOZ X  ZXX XOZX ZXX XOZX0XO 0XOZX ZXX(XOZ X  ZXX(XOZX ZXX(XOZX8XO 8XOZX ZXX0XOZ X  ZXX0XOZX ZXX0XOZX@XO @XOZX ZXX8XOZ X  ZXX8XOZX ZXX8XOZXHXO HXOZX ZXX@XOZ X  ZXX@XOZX ZXX@XOZXPXO PXOZX ZXXHXOZ X  ZXXHXOZX ZXXHXOZXXXO XXOZX ZXXPXOZ X  ZXXPXOZX ZXXPXOZX`X `XYB X1KO OZX ZXOZ X  ZXOZX ZXOZXX XY5OY WXO YZXOZY X WXOY ZXOZY ZXXO ZYXWXXOY ZXOZY ZXXO ZYXOZYWX X YBo>@XOjXOZ> XOjXOZX>OjOZX( Z"ZX%ZX XY #6* 6G X X::@XOjXOZ: XOjXOZX:OjOZX#4+TX88@XOjXOZ8 XOjXOZXjO8OZX( Z!ZX$ZX XY #6* 6I X X99@XOjXOZ9 XOjXOZX9OjOZX#4+TiXOZiXOZYZZ( % Z$ ZX ZX#ZXY #6*eYYXXXZZX( #6T#?[ Z  6?  h#ZWhXYZWhXZWZ#4+TiXOZiXOZYWW( & ZZX"ZX$ ZXY #6*eVVUUUZZX( #6T#?[ Z  6?  h#ZWhXVZWhXZWW#4+TiXOZiXOZYTT( Z!ZX& ZX% ZXY #6*eSSRRRZZX( #6U#?[ Z  6@  h#ZWhXSZWhXZWT#4+ TiOZiXOZYQQ( " Z! ZX ZX&ZXY #6*ePPOOOZZX( #6U#?[ Z  6@  hZWhX#ZWhXPZWQ#4+ TiOZiXOZYNN( # Z! ZXZX%ZXY #6*eMMLLLZZX( #6U#?[ Z  6@  hZWhX#ZWhXMZWN#4+ TiOZiXOZYKK( # Z" ZXZX$ZXY #6*eJJIIIZZX( #6U#?[ Z  6@  hZWhX#ZWhXJZWK#4+ TiXOZiOZYHH(  Z ZX#ZX&ZXY #6*eGGFZFFZX( #6U#?[ Z  6@  hGZWhXZWhX#ZWH#4+ TiXOZiOZYEE(   Z ZX"ZX%ZXY #6*eDDCCCZZX( #6U#?[ Z  6@  hDZWhXZWhX#ZWE#4+TiXOZiOZYBB(   Z ZX!ZX$ZXY #6*eAA@@@ZZX( #6T#?[ Z  6? hAZWhXZWhX#ZWB#4+T+# , OWX  XOWX @XOW+ h( ,OeWXXOeWXXOeW eWJ''> gYbZgXbZXgXOWX 2@XOXOZOOZX XOXOZX#6 #? + #  <ZgX Z?#?[Y.AY>'>X.XOOYWX'Y''5AXOEXOZAXOEXOZXAOEOZX6AXODXOZAXODXOZXAODOZX55Z6YZ56ZYZEYCY  XXOZOXWXY5DY BY  X XOZOXWXY5 e4 8 6 8 - e4 8 6 8@XCXOBXOYWX2,I@XOEXOZ@XOEXOZX@OEOZX41 4#0/4#4 +X 9@XODXOZ@XODXOZX@ODOZXe3 1 3#0 <3#A /X// ?8#4DDOeWDXDXOeWDXDXOeW Y.?Y=,= X .XO OYW X ,Y,,5?XOEXOZ?XOEXOZX?OEOZX e2 eY1 Y02162+1 04 +0B _?AEY7CY8)8X7XOZOXWX)Y))5X<DY9BY:":X9XOp >0,J2 XJ,XJ-   ( (~J ( (XJTXXJTX XJT XXJTXTXJ XT~~J ~XJ/ ~ XT+~ X(JZXJXYTX ~!Z(~!XJXZb*0~,~!, 2 ~J2   y( ~XJZXJXJ ( ~XJZXJTXTXT (  XTX XT(XJ(*0x#0   h( ~32TX~+TX~,T XTXT(~( ,( XW*0#6#6 #0   }( ~33 TX~-TX~.T XTXT(~( ,( XW XXW XXW*0#6 #0   ( ~ 33TX~/TX~0T XTXT( ~ ( ,( XW XXW*0~33 TX~1TX~2T XTXT(~( ,(ZZXZX #6<#?( [  XZW XXZW XXZW XXZW+@ X#?W XX#W XX#W XX#W*0! XJ XJ#?WZXJXX#?WZ XJXX#?W  XJ PX( XJX XOWXJX XOeWXJZX XOeWXJZXX OWXJ X XOW XJXX OeW,XJ9XJ#WZXJXX#W XJXX#W,XJ PX( XJXXOeWXJXXOWXJZXXOWXJZXXOeWXJ XXOeW XJXXOWXOOZ,XJ,E$X JX,XJ XXOXOX XOY XJ XXOYZWX 2+G$X  Y  YJX XXO XOY XJX XXOYZWX 2*0" XJ(XJXXOWX2 ZXJX ZXOW X X 2 ZXJX ZXOW X X 2 XJ PX XOXOZXOXOZXOOZXWX XXOXOZ XXOXOZX XOOZXWX@XXOXOZ@XXOXOZXO@XOZXWXJXOXOZXOXOZYWXJXOXOZXOOZYWXJXXOOZOXOZYWZXJXXOXOZXOXOZYWXJZXXOXOZXOOZYWZXXJXXOOZOXOZYWXJXXOXOZXOXOZYWXJXXOXOZXOOZYWXJXXXOOZOXOZYW,XJ9XJXXOeWX2 ZXJX ZXOeW X X 2  XJ X ZXOeW X  X 2,XJ PX XOXOZXOXOZXOOZXWX XXOXOZ XXOXOZXO XOZXWX@XXOXOZ@XXOXOZX@XOOZXWXJXOXOZXOXOZYeWXJXOXOZXOOZYeWXJXXOOZOXOZYeWZXJXXOXOZXOXOZYeWXJZXXXOOZOXOZYeWZXXJXOXOZXOOZYeWXJXXOXOZXOXOZYeWXJXXXOOZOXOZYeWXJXXOXOZXOOZYeWOZXOOZ  XJ X ZXZXO OXWX  X 2,XJ9  X ZX OZXOXWX  X 2$XJXOXOZXOXOZXOOZXXOXOZXOXOZXOOZXYZW$XJXOOZXOXOZXXOXOZXOOZXOXOZXXOXOZXYZW$XJXOOZXOXOZXXOXOZXOOZXOXOZXXOXOZXYZW8$XJOOZXOXOZXXOXOZXXOXOZXOXOZXOOZXYZW$XJXXOXOZOOZXXOXOZXOOZXOXOZXXOXOZXYZW$XJXXOXOZOOZXXOXOZXOOZXOXOZXXOXOZXYZW*0# XJ 9 XOYWX XOYWX XOYWX#W PX( ,XJ ,M XOYWX XOYWX XOYWX#W PX( +WXWXWX#WX#W*0$ XJ9zWXWXWX#W( XJ PX( ,;,XJ , PX( +WXWXWX#WX#W*0%,! 0X 0X((+ 0X(XOXOZXOXOZXXOXOZX( XOXOZXOXOZXOXOZX#7O( #@Z +Oe( #@Z #-DT! @6 #-DT!@Y e*0E"':Zbj+nXO5fXW+^XO7VXW+NW+I#7=XW+6#7*#?5 XW+8XW+(XW+0XW*0^E"(+,XO*XO*O*XO* XO*8XO*(XO*0XO*#*0@XO5@XTHXXOYW*XO7@XTHXXOYW*@XT*0& XJZXO#6+ @XJ-*, XJ+ XJ+ XJ+XJZXOWZXXXOWZXXXOW,XJ,.ZXOeWZXXXOeWZXXXOeW@XJ,XOXO;9-.$XJZXOW,XJZXXOeW0XJZXXOW8XO O#6e 3 O#03O#4 XOZ ,I XJOZeXOZeXOZe(,XJ,dOZXOZXOZ(+G XJOZeXOZeXOZe(,XJ,OZXOZXOZ(@XJ9Z $XJX(XOOZHXOZeWXOXO3",XJXjOeW0XJXjOW8@XJ3!,XJX#W0XJXjOW+ ,XJXjOeW0XJX#W(XJX0XOW8XO#C?,p XJ X  XOXOZ XOXOZXO OZX ,XJ 9  XXOXOZ XXOXOZXO XOZXY +k XJ XXOXOZXOXOZXOOZX ,XJ ,3  XXOXOZ XXOXOZX XOOZXY @XJ3- #4L 8XOZe $XJX   O62  W++ #6 8XOZe $XJX   O4  W*08X(XX(*%<0 TXT*%@08XXX(6*%D0K-43 ( XJD.53 ( 8XXX(8*%H0-43 ( -63 ( XJD.53 (  XJ ,N PX8X(  XJ XOOXWX XJ XOXOXWX XJ XOXOXW*%L0'8X(XX(xX (#?W X (#?W X(J  X#W XX#W XXjOeW XXjOW X X#?W X(X0XOW X0X8XOW X8X#W X@XT XHX#W*%P0(XT XO#6T+T XO#-DT! / XO#-DT! @5? XO XO5- XJ,XJxX X(:  X(=,T*%T0)8XXX(6  XJ PXxX(  ( XJZ b ZXJXOWXJZXXXOWZXXJXXOWZXJXOWXJZXXXOWZXXJXXOW,XJ,hXJZXOeWZXJXXXOeWXJZXXXOeWXJZXOeWZXJXXXOeWXJZXXXOeW,XJ , PX X( +& XOWX XOWX XOW XOXOZ XOXOZYWX XOOZ OXOZYWX OXOZ XOOZYWXOOZ $XJXXOXOZXOXOZXOOZXZW$XJ XXOXOZXOXOZXOOZXZW X (>&*%X0c* XJ ,Y,XJ , X 0X 0X(+4 X 0XOW 8 xY X XJXOeWX  P2*0Q-43 ( XJC.73 ( 8XXX(8(G*%\0T-43 ( XJC.73 ( xX X(9(G*%`0-43 ( -63 ( XJC.73 (  XJ ,N PX8X(  XJ XOOXWX XJ XOXOXWX XJ XOXOXW*%d0l-43 ( -63 ( XJC.73 (  XJ , PXxX( *%h0H-43 ( XJC.73 (  X(;*%l0G-43 ( XJC.73 (  X(<*%p0c- 3 ( XJC.73 (  XJ ,,XJxX X(:*#*%t0+- 3 ( XJC.83 (  XJ 9{ PXxX(  XJ X XOXOZXOXOZXOOZX ,XJ ,3 XXOXOZ XXOXOZX XOOZXY *#*%x0,8X (#?WXX(xX(J  X#W XX#W XXjOeW XXjOW X X#?W X(X0XOW X0X8XOW X8X#W X@XT XHX#W*%|0--43 ( XJ@.93 (  XJ PX8X( ,XJ ,P PXxX(  ,XJ  X  XJYZX XOZXOY OYWX X 2+7 xX XJ XZXOOYWX XX2XOXOZXOXOZXOOZX*%0.-43 ( XJ@.93 (  XJ PX8X( ,XJ ,\ XJ X XOXOZXOXOZXOOZX XXOXOZ XXOXOZX XOOZXY* XJ X XOXOZXOXOZXOOZX*%0(XT XO#6T+T XT XOjOe0 XOjO4m XO XO5[(Q  XO5  XT X XOYWT+) XO7 XT X XOYWT*%0k/ XJbZb XJ X PX#,XJ,G X PX Y"-Y!!X"XOOYWXY5+ XJ#?WXJZXX#?WZXXJX#?W,XJ,<XJ#WXJZXX#WZXXJX#W,#8X( ,+*(,XJ9)+XO-XOZ+XO-XOZY#?ZW)X+O-XOZ-O+XOZY#?ZW)X-O+XOZ+O-XOZY#?ZW ZXJX Z)XOW X X 2 ZXJX Z)XOW X X 2)*XO-XOZ*XO-XOZY#?ZW)X*O-XOZ*XO-OZY#?ZW)X*XO-OZ*O-XOZY#?ZW ZXJX Z)XOW X X 2 ZXJX Z)XOW X X 2 ZXJX Z+XOeW X X 2ZXJXZ*XOeWXX2bXJXZ+XOWXX2 bXJXZ*XOWX X2,XJ,)( XJ 0X 0X('(XX(+' XJ 0XXX('O#4%'X'XOeW'X'XOeW'X'XOeW XJ PX &XO'XOZXO'XOZXO'XOZXW&X XXO'XOZ XXO'XOZX XO'XOZXW&X@XXO'XOZ@XXO'XOZX@XO'XOZXWXOOZ $XJ&O Z#@ZW$XJX&XO Z#@ZW$XJX&XO Z#@ZW,XJ9 %XOxXXOZXOxXXOZXxXOOZXW%X XXOxXXOZ XXOxXXOZXxXO XOZXW%X@XXOxXXOZ@XXOxXXOZX@XOxXOZXW-X%XO-XOXWX2$XJX-O+OZ-XO+XOZX+XO-XOZX ZW$XJ X*O-OZ*XO-XOZX*XO-XOZX ZW8 xX$Y Z$XO X$XOYWX X2$XJX$XO+XOZ$XO+XOZX$O+OZX ZW$XJ X$XO*XOZ$XO*XOZX$O*OZX ZW X,(>&*%0d0-43 ( XJ@.93 ( 8X XJ,; W XW XW X#W ( XJ PX ( X#W,XJ ,hXX XJ 0X 0X(,XJ  X  XJYZ X XO OYWX X 2xX PX ( +bXX XJ 0XOW 8  YX XJXOeWX  P2   YX XJXOWX  (2*%0l-43 ( -63 ( XJ@.93 (  XJ , PX8X( *%0H-43 ( XJ@.93 (  X(;*%0G-43 ( XJ@.93 (  X(<*%0@8XT@X#W X( X( X#W*%01  @XO#4@X#W8XJ_,f@XO#6 HXO#4HX#WHXO#6X @XOjO3 HXOjO3'X +!@XO#6 @XOjO3 4XTTXT*%02 XJ b XJ_,( XOWX XOWX XOW+) XOeWX XOeWX XOeWX#W  XJ X  X ZX O OYW X  X  X 2XJOWXJXXOWXJXXOWXJXOXOZXOXOZYWXJXXOOZOXOZYWXJXOXOZXOOZYW,XJ 9  X  X ZX O OYW X  X  X 2XJOeWXJXXOeWXJXXOeWXJXOXOZXOXOZYeWXJXXOOZOXOZYeWXJXOXOZXOOZYeWXO8XJ_,`XO$XJOZ XOZW8XJ_, (XJhXOW8XJ_96 XJXJ XJXO XXOZXO XXOZXO XOZX XO XXOZ XO XXOZX XO OZXX,XJ 9tXJXJXO XXOZXO XXOZXO XOZXXO XXOZXO XXOZXO XOZXXXXXO#7(eXXO6PXOZe$XJO6W,XJ#W0XJjOW4XJ?-8XJ_9w XOWX XOWX XOWXOXOZXOXOZYWXOXOZXOOZYWXXOOZOXOZYW+ (XJZXOWZXJXXXOWXJZXXXOWXJZXXOXOZXOXOZYWZXJXXOXOZXOOZYWXJZXXXOOZOXOZYW,XJ9ZXJXOeWXJZXXXOeWZXXJXXOeWXJZXXOXOZXOXOZYeWZXJXXOXOZXOOZYeWXJZXXXOOZOXOZYeW8XJ _, $XJXpXOW,XJX@XOeW0XJX@XOW8XJ _, 4XJXT8XJ _,(XJX XOW4XJ?XJZXOWZXJXXXOWXJZXXXOWXJZXXOXOZXOXOZYWZXJXXOXOZXOOZYWXJZXXXOOZOXOZYW,XJ9ZXJXOeWXJZXXXOeWZXXJXXOeWXJZXXOXOZXOXOZYeWZXJXXOXOZXOOZYeWXJZXXXOOZOXOZYeW8XJ@_,$XJXxXOW8XJ_,,XJXHXOeW0XJXHXOW+,XJX@XOeW0XJX@XOW8XJ _, 4XJXT8XJ _,(XJX XOW*%03,XJ PX X(  XJ PX(  XXOXOZ XXOXOZX XOOZX XXOXOZ XXOXOZX XOOZX( e*0448X(XX(xX(#?W X( X#?W X#W X#W X ( #?W X( X#?WJ  X#W XX#W XXjOeW XXjOW X X#?W X(X0XOW X0X8XOW X8X#W X@XT XHX#WJ  XX#W XXX#W XXXjOeW XXXjOW XX X#?W XX(X0XOW XX0X8XOW XX8X#W XX@XT XXHX#WJ  X0XOW X8XOWXXJ`T*%0(TXT XO#-DT! / XO#-DT! @5( XO XO5(\  X(=- XO#6JXT XT `XO#6JXT*%05 XJ PXxX( ,XJ PX X( XOXOZXOXOZYWXOXOZOXOZYWXOXOZOXOZYWXOXOZXOXOZXOOZX( OOZXOXOZXXOXOZX (8XXX XO(7 XJZ ZXJXOWXJZXXXOWZXXJXXOW,XJ,4ZXJXOeWXJZXXXOeWZXXJXXOeW$XJX XO Z XOZYXOOZZW X(>X  XX(>&(XJ XOW*%06 XJ 9{ PXxX( ,XJ PX X( O#3$XO#3XO#;O#3$XO#3XO#;OO3XOXO3XOXO;XOXOZXOXOZXOOZX  XXOXOZYWX 2(XOXOZXOXOZYWXOXOZXOOZYWXXOOZOXOZYW X XJ PX(  X XJ PX( *0Q-43 I( XJA.:3 J( 8XXX(8(`*%0l7-43 S( XJA.:3 T(  XJ9"WXWXWX#W(xX  XJ PX(  X#W XJ PX( ,XJ PX X( XOXOZXOXOZYWXOXOZOXOZYWXOXOZOXOZYW XXOXOZXOXOZXOOZX( W XOOZXOXOZXXOXOZXW(`*%0l7-43 j( XJA.:3 k( ,XJ9"WXWXWX#W( X ,XJ PX(  X#W XJ PXxX( ,XJ PX( XOXOZXOXOZYWXOXOZOXOZYWXOXOZOXOZYW XXOXOZXOXOZXOOZX( W XOOZXOXOZXXOXOZXW(`*%0-43 ( -63 ( XJA.:3 (  XJ ,N PX8X(  XJ XOOXWX XJ XOXOXWX XJ XOXOXW*%0l-43 ( -63 ( XJA.:3 (  XJ , PXxX( *%0o-43 ( -63 ( XJA.:3 ( ,XJ , PX X( *%0Q-43 ( XJA.:3 (  XJ,(\*#*%0+-43 ( XJA.:3 (  XJ 9{ PXxX(  XJ X XOXOZXOXOZXOOZX ,XJ ,3 XXOXOZ XXOXOZX XOOZXY *#*%0+-43 ( XJA.:3 (  XJ9,XJ 9~ PX X(  XJ X XOXOZXOXOZXOOZX ,XJ ,3 XXOXOZ XXOXOZX XOOZXY *#*%084XT8XT XHX X X PX 4XJ2*%0G,21 3 ( 8XJ34XT+/+14XT*%0=,2 021 3 ( /+1ZX,22 3 ( /+1ZX /0XJZZ(XJXZ XJXJX XXJ2(XJ,XJXJXJ(XJXJXJb(XJ,XJXJXJXJ(XJXJ( XJ/ZHXJXTX XJ2XJ LXT@XJ,pJY 2d@XJZXJ2HJ XJXJXJXJ XJ$XJDXJ}  /74XX(XJLXJZXZJXZJXOWX LXJ2 X LXJZ,XJX#?ZZJXJXO4XJ0XJLXJ(Y[W+! X ,XJ#?ZZJXJXO[WJXJXJXJ XJ$XJDXJ> XZJXJ XJ/ 0X Z JX ZXOW X XJ2XJ LXJ/.HX 0X Z JXZ JXJZXOWX LXJ2(XJ0XJLXJXJ(  LXJ/3,X 4XZJXZ0XJXOZ JXOZWX LXJ2 LXJ//4XXJLXJZXZ(XJXZJXOWX LXJ2LXJZ,XJX#?ZZJXJXO4XJ0XJLXJ(Y[W+# X,XJ#?ZZJXJXO[WJXJXJXJ XJ$XJDXJC PXJ/3 X LXJ LXJXZXXZJXJ(WX PXJ2*0wHLXJZZ XJXJX10 PXJ/TLXJXZX ZXO OXWX PXJ2+. PXJ/$LXJXZX OZXOYWX PXJ2*0ILXJ>Z XJXJXJ/%0XZJXZXOWXXJ2XJ LXJ/.HX0X Z JXZJXJZXOWX LXJ2(XJ0XJLXJXJ(  LXJ/3,X 4X Z JXZ0XJXOZ JXOZWX LXJ2:LXJ/-4X 8X  JZXZ JXOWXLXJ2(XJ8XJLXJXJ( 16 LXJ/_HX ZJXJZX Z8XJXOeW X LXJ2+3 LXJ/)HXZJXJZXZ8XJXOWX LXJ2*0JJZ XY`X XJ  J/&DXZJXJZXJXZXOWX J2XJJb J/&DXZJXJZXJXZXOWX J2*0K1,,,,,, 21 F H( )1 Y`X + 2+ ( (b(8//SY  XO#5O#/LF X( XY5 ZZX ZX5ZXY`X ZXY`XZX4ZX3ZX ZXY`X(ZX ZXY`X6 Y`X5Y`X4Y`X3Y`X(Y`XY`X(&6XJ6XJ 6XJ<6XJZ ,X Y2Y1YY'Y):9xZ2XXJ2k /Z(XJZXZXOWX 2 /AXY0ZXJZXOOZ( !!W0X!eWX X2)6LXJZ 6 XJZX%%JXX6PXJ(+%J6LXJ(+XX1XOY   W'XO#3(#76PX6PXJXTZXT8eXO#3(#56PX6PXJXTZXT8-#36 (6(8X#'XXO#5#?+#6 (6 (6(Z6 XJXJZXO* 6LXJ(*ZX#WO[e 1'OjO4BOZXOY[ 4. +&OjOe6OZXOY[ 4  6PXJ<6LXJZX 6LXJZXY.Y/Y J- O#2+X O#6J  X.XO#3  XO#.%  X/XO O[e 4 6LXJXX X X 6PXJ?w 6LXJ<,XY Y" YXO#43 XOjOe6$ XO"XOYXO[ 4  XO#6,OjO4!O"XOYXO[ 4  X X6LXJ?i #>6LXJ/1 Y-6LXJ -XO ZOXWX Y  5ZX ZZXOXW6PXJ/56LXJZX6PXJ XO ZOXWX Y  5 #OZOXWYEAb~8#W6(8ZXOWZXT6PX6PXJXT8ZXOWZXT6PX6PXJXT+`ZX#W6(+DZXZXOWZXT6(+!ZXZXOWZXT6(= X X ?+3K ( Y/!Y$Z&&X$(&X$(6(*0y XOXOZOOZXXOXOZXW X X XOXOZ XOXOZX OOZXW@X X XOXOZ XOXOZX OOZXW X    X XOXOZ XOXOZX OOZXW X  (XXO XOZXO XOZX OOZXW@X 0XXOXOZXOXOZXOOZXW@X@XXOXOZXOXOZXOOZXW X  HXXO XOZXO XOZXO OZXW@X  PXXOXOZXOXOZXOOZXW*0LO#5NM%( *(X (-OM)( * (XXOeWXXOW XXOW0XXOeW@XXOeWHXXOW(   ZXZXOOZOXWX X  2(-PM@( **05- MI( #WX((X (*0M-$ MU(  MI( #WX ((X  (WWXWXWWPXWxXW0XW8X WXX WHXWhX WpX W(&*0N-$ Mj(  MI( #WX((X  (ZZZ#es-8R@Z WZZ#?Z WPXWxXW(&*0 O- M|( 21QM}( - MI( #WX((X (ZZZ#-DT! @Z Z#es-8R@Z XWZZ #?Z #?ZXZ #UUUUUU?Z#?ZXZX WPXWxXW(ZX#?Z#?ZXZZW(&*0P-' M (  MI( #WX((X (ZZZ WZ Z  XZ#UUUUUU?ZWZ PXXZ#UUUUUU?ZWxX XZ#UUUUUU?ZW(&*08,/ R ( 1 #WXY 5*00,/ R*( 1 WXY 5*0"Q1- Rw( 1 Y`X+ZXY`X <Z   /QY O ,!  XOOZY X Y  5 ZXOZWZ X X X 2 O ,!O   ZY XY5#1<(   WZX#? [WZXX  X ?5+**0fR1,- R ( 1 Y`X + ZXY`X<ZXZ Y# /%  ZXO OZX X X 2XOYO[WX X XX2Y ?ZYZXZXZX XZ eY# X /' XZX ZXO OZX X Z X 2XOY O[WY  X  X Y/*0S1,- R ( 1 Y`X+ZZXY`XZZXY`X (-*(/lb  Y  Z X#WX 2 X#?W ( Z XOWX  X2X Y5*0JT1- R ( 1 Y`X+ZZ XY`X (*0AU,,/ R ( / Y  XOOZWX Y 5*0D,, , 1/ R ( ( (( *0V,, , 1/ R ( ?ZXY`XZXY`X#W#W/HX Y%Y$Y% XO#;f?Z W$ XW X Y5O#?Z#?X#;f?Z #?Y#;f?ZO   ZZ#?X[  Z #?ZZYZ#?Y ZY/XX Z#ZXY"Y O O   ZYW" XZ ZXW#X X Y5<bX YY XO OZZX[ OZZ  XOZZY[  XOZ!XZWO XOX/3YZYb ZX X(& X Y5Z     ZZXZXZXYYZ X XY5YZY ZZXZX XZXZXX YY  X  X Y 5*0JX,*,',$,!112/ 2/ R ;(  /1ZXJ22SR =( X 2Y;:ZXY`X /EZXJ J   1 Z ZXJXO+ Z ZXJXOZXeWX 2O#?XW(8 ZXY`X Y ZXY`X /8 ZZX  Y  OXO[W X X  Y  5   ZXY`X  XJZXY`XJ ,XTXJ -XJ  , XT XJ  - XJXJ  /+ ZXY`XJ 9[XJ:FXJ_::XT   TXJ,WJXJ-?TZXJTXXJ  , XJ- XTZXXJTX XJ-XJ1ZY (  XJ1[Y ( 1 Y ZXJ Z XTX8A (//Z XJXTZ XJXJ_TX2 / ZXJXT X  2XJ :J,=XJ_,XJ, \( +XJ- ]( XJ-XJ ,X  XJ, XJ_, ,XJ,XJ_- XJ-^( + XJ, _( XJ -*0b- Y g( XJ ,-JX ZX XTXJ XTJ( -XJ ,XXJTXJXJTXTXTJX JXT P(*0- Y |(  XT*0- Y (  XJ*04- Y (  XW XW XW*0nc,- Y ( (( 0X OW 8XXOW @XXOW HXXOW PX(*04- Y (  XW XW XW*04- Y (  XW XW XW*0 - Y (  X*0 - Y (  PX*0 - Y (  X*0 - Y (  X*0od,- Y (  X  X HX(-OY ( ( X#? XO[W*0a- Y (  X XOXW X XOXW X XOXW*0a- Y (  X XOXW X XOXW X XOXW*03- Y ( WXWXWX#W PX(  X XOOXW X XOXOXW X XOXOXW*03- Y ( WXWXWX#W PX(  X XOOXW X XOXOXW X XOXOXW*0e- Y &(  X XOXW X XOXW X XOXW XOYWX XOYWX XOYW XXOZXOZY XOXW XXOZOZY XOXW XOZXOZY XOXW*0Qf- Y M( WXWXWX#W PX(  X XOOXW X XOXOXW X XOXOXW XOYWX XOYWX XOYW XXOXOZXOXOZY XOXW XXOOZOXOZY XOXW XOXOZXOOZY XOXW*0Qg- Y b( WXWXWX#WWXWXWX#W PX ( (  X XOOXW X XOXOXW X XOXOXW XXOXOZXOXOZY XOXW XXOOZOXOZY XOXW XOXOZXOOZY XOXW*03- Y ( WXWXWX#W PX(  XOOXWX XOXOXWX XOXOXW*03- Y ( WXWXWX#W PX(  XOWX XOWX XOWXO XOZXO XOZYOXWXO XOZ XOXOZYXOXWX XOXOZO XOZYXOXW*0h,-`Y ( TX TXT XTXTXTXTXT XT$XT(XT,XT0XTX JTXTJ ,XTT X XJXT*0fi,-aY ( ,XJ( JXT+J( (XT, XXJ`TXJ ,)_*0%- Y "( D(*0%- Y )( C(*0%- Y 0( @(*0%- Y B( A(*0%- Y I( ?(*0%- Y W( B(*0c- Y ^( XJ_-A(XJ ,XXJTXJXJTXTXTJ X JXTXJJ(*0 X(*0j- Y ( JZXY`X X( J/!Z XTXJJ(X J2JY 2]Z XJJ,H(Z XJ XJ, XXJTXJXJTXTXTZ XJJ XJXTY /T(*0k-4Y ( ,3bY ( J ,J3,J.cY ( XJ_,(3+3+a,dY (  XJ-,XJ,(-XXJ_T+ XXJ`T XT,XT,0XXJTX(XT+0XT,$XXJTXXT+$XT*09l,- Y ( XJ ,XJ. XJ -+**0Ck@( TXTXT XTX(0X#?W8X#|=W*0m- Y ( J ,XJ  P( -XJ ,GXJ XJ_,(T XT$XT,XT0XTe( + XJJ( -@(*0+- Y $( XWXW XW*03- Y -( XOWXXOWX XOW*00XW*00XO*08XW*08XO*0A-fY N( #0gY O( (* 0  - Y K( P( ,  X(   P(TX TXT XTXTXTXT X#?####?#?#?###( X (#?W X#?W X#?W X#?W X( 0X(#?W PX( X( X( X( X( 0X(JTXTJ , XTTXXJXT*A#7 @ 0*1( , X(&  (T*A @00- Y r( (,((*0n- h6( O XO XO ( ( ( 6\0\#?[  Z  Z #?ZZX#?X( [  ZWX (WX ZW86V#?[Z Z #?ZZX#?X( [  ZWX ZWX (W8#5:ihV( #?WX#WX#W+Q#?[Z Z #?ZZX#?X( [  (WX ZWX ZW*0o- h~( XOXO O XO Z ZXZXZX #6;#?( [ OZWXXOZWXXOZWXXOZW+Iih ( #?WX#WX#WX#W*0p,,- h ( XO( #;f?6lXOXO ZZX#?( [ #WXXOZeWXXOZWZWXXOOZeWXOXOZW+dXO OZZX #? ( [ XOZeWXOZWX#WXOXOZeWXXOOZWX ZW*0- k4( #?WX#WX#WX#W X#W(X#?W0X#W8X#W@X#WHX#WPX#?WXX#W*0,,- k ( OOZXOXOZYXOXOZYXOXOZYWXXOOZXOXOZXOXOZXXOXOZYWXXOOZXOXOZXOXOZXXOXOZYWXXOOZXOXOZXOXOZXXOXOZYW*0,,- k ( XOXOZXOXOZXXOXOZXOOZXWXXOOZXOOZYXOXOZYXOXOZXWXXOOZXOOZYXOXOZYXOXOZXWXOXOZXOOZYXOXOZYXOXOZXW*0,,- k ( XOXOZXOXOZXXOXOZXOOZXWXXOOZXOOZYXOXOZYXOXOZXWXXOOZXOOZYXOXOZYXOXOZXWXXOOZOXOZYXOXOZYXOXOZXW*0,,- k ( OOZXOXOZYXOXOZYXOXOZYWXXOXOZXOOZOXOZXYXOXOZYWXXOXOZXOOZOXOZXYXOXOZYWXXOXOZXOOZOXOZXYXOXOZYW*0Up,- k ( XOZ#@ZXOZ#@Z XO Z#@Z #? YYWXXOXOZOXOZY#@ZWXXOXOZXOOZX#@ZW XXOXOZOXOZX#@ZW#?Y (XYW0XXOXOZXOOZY#@ZW@XXOXOZXOOZY#@ZWHXXOXOZXOOZX#@ZWPX YW*0) ,- k ( (XOPXOX OX #7m#?X( #?ZW#?[#?Z XHXO0XOYZWXXO@XOYZWX XOXOYZW8(XOOCPXO(XO=(XOPXOOXY#?X( X#?ZW#?[#?Z XHXO0XOXZWX XOXOXZWXO@XOYZW8PXOOCwPXO(XOOXY#?X( X#?ZW#?[#?Z X@XOXOXZWXHXO0XOXZW XOXOYZW+kOY#?X( X#?ZW#?[#?Z X XOXOXZWX@XOXOXZWHXO0XOYZW*0,,- k ( XOOZeXOXOZYXOXOZY#?ZWXOOZXOXOZXXOXOZY#?ZWXXOXOZXOOZYXOOZX#?ZWXXOOZXOXOZYXOOZX#?ZW*0vXJ XJ3-sOXO0kXOO2cXOXO0WXOXO2K XO(XO0?(XO XO23JXJ , )q,JXJ , )q, )r*0:w- l ( XJ ,XJ ( - (*%0S,- l ( XJ-XJ,ml ( XXJTXTXT*%0ww,- l ( XJ-nl (  XJ ,5.  XJ -+$, XXJT+ XXJTXTXT*%0x,- l ( XJ  ,XXJ-0ZXY`X  ,( JXJ) XT0XXJ -XJ ,A XJ ,$0X (0X XJ -0XXJ -XJ ,XTXJ -*%0:w- l T( XJ ,XJ ( -(*%0F1ol b( XJ .pl c(  XTXT*0S,- l l( XJ-XJ,ml n( XXJTXTXT*%0ww,- l w( XJ-nl x(  XJ ,5.  XJ -+$, XXJT+ XXJTXTXT*%0y,- l ( (  XJYXJ 9[X3(X(oY`XXJXJ) XXTTXTXXOOY XOXOY 6 (XO XOY 6  jO3  + -( &-  XJ* */*  3J= T 8X T 1 #? ( ,#?,[+wX  XJ>GJ:  9 X4 XJ>X4XJ> Z4XZ4XJcTX 2 X   X  >@J:  ,7 ,'TX"X// X"J TXJ( J -J-,7J ,'TX"X00 X"J TXJ( J -J-XJ ,XTXJ -*%0 JJ)s*0 JXJ)t*0 JXJ)t*0J XJ)u* 0D1( ,sT  (X TXT XTX T*A % 061 ( ,tT   (X TXT*A %0}XOXOZXOXOZXOOZXOXWX XXOXOZ XXOXOZX XOOZXXOXWX@XXOXOZ@XXOXOZX@XOOZXXOXW*0|11 ,,-vu>( 9YZX  ,kYXX XX  YOYOZYOOZXOOZXXOOZXXOOZX XOOZXWX@X Y 5X@X Y B{*0|11 ,,-vuY( 9YZX  ,nYXX XX  YOYOZYOOZXOOZXXOOZXXOOZX XOOZXOXWX@X Y 5X@X Y Bx*0}1 ,,-wur( ,dXX X (X 0X  OOZXOOZXXOOZX XO OZX(XOOZX0XOOZXWX@XY 5*0}1 ,,-wu ( ,gXX X (X 0X  OOZXOOZXXOOZX XO OZX(XOOZX0XOOZXOXWX@XY 5*0~1 ,,-xu ( # /# ZXO OZX X @X 2OXW# /%X ZXO OZX X @X 2XXOXW# /&X ZXO OZX X @X 2XXOXW#  /" X ZXO OZX X  @X 2 X XOXW#  /"(XZXOOZX X @X2(X(XOXW#  /"0XZXOOZX X @X20X0XOXW*0 X  XOZOXWX Y  5XJ_9!_9 0X  XO XXOZ XO XXOZX O XOZXOZWX 8XOZWX @XOZW#?ZZ  ( W ( #-C6?4#? Z#UUUUUU?ZY+ ( [Z X OZWX XOZWX XOZW8#?Z XO XO XOZZXZX( Z ( W( #-C6?4#?Z#UUUUUU?ZY + ( [  Z X XO ZWX  XOZWX  XOZW 0X ( ZXOWX X2XJ_9u( ZXOZOXWX X2+@ 0X  X( ZXOZOXWX X2( PX(*0 #?[#/ZXJXTX2ZXY`XZ`ZX Y`XY`X" Z ("( <"(XZXJ 6HX PX((YZXJ PX6( ZXJ 6 X PX(ZXJ PX6( ZXJ 6 YO XXOZYO XXOZX(YO XOZXW6XYO XOZXO XXOZXO XXOZXW6X XO XXOZ(XO XXOZXXO XOZXW X XO XO6XOZ XO6XOZYYWZXJ  X XO XO6OZ XO6XOZYYWZXJ  X XO XO6XOZ XO6OZYYWX `X`X?1 <X4X3 X2ZXJ  X XO4OZ XOXWZXJ  X XO3OZ XOXWZXJ  X XO2OZ XOXWX 2 ZXY`XY`X <ZXJXJXJ)zJ20XJ21yu ( J1&ZXJZXTXTX X+ ZXJXTX?f/4ZXXJZXJ3ZXTZXJX X2 /6ZXXJ1ZXJ/ZXTZXJX X 2 /&ZXXJ-ZXTZXJX X 2@ZX Y`XZ(> ZXY`XZXY`X/ZXY`X.ZXY`X-b)(/8XO(.jOe(-jO(/Z)XTX2 ZX((Y`XZ(5 XT5#W5X0XOW<  Y J 5X ZXT5X5XJ XT5XJ@Z5XJXT5X5XJ XT5$X ZXT5(X Z/XT5,X Z.XT50X Z-XT54X Z)XT XJ  5 XJ XJ){J/0 J  XZ)XJ2 XTXJ2 X XYB (Y`X''(<Y J XJXJZXJ XO*`Z"X XJ ZX'XZXJY?@X, X!X@X X+X&&@X%& X0X (XX Y   XO*ZW X Y5 YOYOZ,OXOZX!OOZXW YOYOZOXOZX+OOZXW %OXOZOOZX&OYOZXW@X@X@X @X YBQJ,XJ93XJZXJ XO*`Z"XZXJY?@X  X X@X  XX%%@X&% X+0X(XX!Y,!!,XO*ZW!X!Y5YOYOZ OXOZXO OZXWY OXOZOOZXOYOZXW&OXOZ+OOZX%OYOZXW@X@X@X@XYBMXX?W1 Y`X+ZZXY`X  (<^  JXJ  94 XJ$$9 JXJ$JXJ ZXJ ZXJ/  ; ;ZXJ,XJ J( ZXJ,XJ-(,zu .(  ZXJ,XJ-,{u /(  ZXJZXJ  ZXJ ZXJZ XZ XZ(ZX@Z'X ZZX@ZX($XJ$$: XJ  : X YB < YZXJ J  ZX ZZ X'XX( XJ,XJ,;ZXJ J  ZX@ZX ZZ X'XX(X  X ?n /'ZX Z/XO#Z OXWX  X 2Y`X Z(<, "  X  J XO1    Y JXO#ZX@XO1ZXWX X 2 J X  XOXOZXOXOZXOOZXW XY XXOXOZ XXOXOZX XOOZXW X@XXOXOZ@XXOXOZX@XOOZXW    JXO#ZOXWX X 2`X X  @X YBZXY`X( < Y J ZX ZX  XJ XJXJ@Z XZXJ( XJ,XJ,+ZXJ JZX@Z XXJ@Z X(X  X ?y/) Y   XO#Z OYW X Y5ZXY`X ZX  Y`X.-)( <Y  XJ  ZX J XJXJ@ZX Z XZXJ(J,XJ,+ZXJ XJ@ZX@Z X XJZ X(X X2/m      JXO OXWX X  2    X  JXO OXWX X  (2 X  @X Y5 Z/ZXZXOZWX Z2<  "  J XO0    JXO0ZOXWXX  2 J X   X( `X  @X  X Y5 /ZXJ(X 2 <ZXJ X#WZXJ X#WZXJ X#WZXJ X#WZXJ X#WZXJ X#WZXJ X#WZXJ (X#WX ?E*0(*0 {(*0 {(*0 {(*0 {(*0 ( (;*0( }*0( (<(}*0 {(*0{*0 {(*0 {(*0{(*0E]{( O}XO}XO}p]q]*0!{( OXOXO*0({(*0{W X{W@X{WX{W(X{WHX{WX{W0X{WPX{W{(*0_{( O} XO}@XO}XO}(XO}HXO}XO}0XO}PXO}p_q_* 0 v1 ( , (  ({{{{{{{{{({(*A / 081 ( , (  (({(*A / 0;1 ( , (  (({(*A / 0;1 ( , (  (({(*A /0{(*0{(*0{(*0{(*0{(*0G{( {OZ#ZXOZ#ZXOZ#Z(*0G{( {OZ#ZXOZ#ZXOZ#Z(*0{(*0{(*0{(*0E]{( O}XO}XO}p]q]*0{(*0E]{( O}XO}XO}p]q]*0L]{(O}XO}XO}p]q]*0L]{(O}XO}XO}p]q]*0{{(*0 ( (H*0 ( (i*0( }*0 {(*0{*0 {(*0{(I(*0{(*0{W X{W@X{WX{W(X{WHX{WX{W0X{WPX{W{(*0{, {(}*0 {(*0 {(*0E]{( O}XO}XO}p]q]*0_{( O} XO}@XO}XO}(XO}HXO}XO}0XO}PXO}p_q_*0&{, {((j(.}*0){, {((j(/}*0+{, {((j(1}*0'{, {((j(0}*0 {(2*0I]{(3O}XO}XO}p]q]*0V^{(4O}XO}XO}XO}p^q^*0{(5*0 {(*0 ( (n*0 ( (*0( }*0 {(*0{*0 ( (* 0(( (*A - 0A(( {, {((<(} (*A-3 - 0F(( {, {((<((} (*A28 -0(*0+{, {((<((}*0&{, {((<(}*0{(I(I(*0{(I(*0 {(*0 {(*0{(*0J]{(O}XO}XO}p]q]*0{(*0 {(*0{(*0 {(*0 {(*0 {(*0 {(*0 {(*0 ( (* 0(( (*A - 0A(( {, {((<(} (*A-3 - 0F(( {, {((<((} (*A28 -0(*0+{, {((<((}*0&{, {((<(}*0{(I(I(*0{(I(*0{(*0I]{(O}XO}XO}p]q]*0 ( (* 0(( (*A , 0A(( {, {((<(} (*A-3 , 0F(( {, {((<((} (*A28 ,0(*0+{, {((<((}*0&{, {((<(}*0{(I(I(*0{(I(*0 {(*0 ( (*0( }*0( (}*0 {(*0{*0 {, {((}*0 {(*0 {(*0&#8/T! 6#5 {( *0 {(*0&#8/T! @4#7 {( *0 {(*0{( *0 {(*0{( *0 {(*0{( *0 {(*0{( *0 {(*0{( *0 {(*0{( *0 {(!*0 {("* 0(( (*A - 0A(( {, {((<(} (*A-3 - 0F(( {, {((<((} (*A28 -0(*0+{, {((<((}*0&{, {((<(}*0{(I(I(*0{(I(*0{(#*0I]{($O}XO}XO}p]q]*0{(%*0I]{(&O}XO}XO}p]q]*0#8/T! 6#5 {( #8/T! @4#7 {( {( {( {( {( {( {( *0 ( (* 0(( (*A - 0A(( {, {((<(} (*A-3 - 0F(( {, {((<((} (*A28 -0(*0+{, {((<((}*0&{, {((<(}*0{('*0I]{((O}XO}XO}p]q]*0{()*0I]{(*O}XO}XO}p]q]*0{(+*0I]{(,O}XO}XO}p]q]*0 {(-*0 {(.*0 {(/*0{(I(I(*0{(I(*0 ( (*0 {(0*0#5 {(1*0 {(0*0#7 {(1*0 {(0*0{(1*0 {(0*0{(1*0 {(0*0{(1*0 {(0*0{(1*0 {(0*0{(1*0 {(0*0{(1*0 {(2*0 {(3* 0(( (*A - 0A(( {, {((<(} (*A-3 - 0F(( {, {((<((} (*A28 -0(*0+{, {((<((}*0&{, {((<(}*0{(I(I(*0{(I(*0{(4*0I]{(5O}XO}XO}p]q]*0#5 {( #7 {( {(1{(1{(1{(1{(1{(1*0 ( (*0( (}*0( (}{(*0 {(*0{*0{(*0( (}*0 {(*0{*0{(*0I]{(O}XO}XO}p]q]*0%e{(OXOXO*0 {(*%mVj^u;}ƣmjPYYx]ujV5m YYx]ujX^3ҹx]  x|3ɺ4`\tu Ah|3^=Ut=ËD$;r=Xw+PYà PËD$} PYËD$ PËD$;r=Xw+PYà P ËD$} PYËD$ P jhejjYY3@ËeMj; xuhth Ptt$t$jYj YátVW $3;ϋsu?tу;ru,hn\ƿ;YstЃ;r3_^UVWj,3F95UYuu P} E5UUuR p]t)l];tСl];p]l]s(0;ƋstЃ;r4<;ƋstЃ;r}_^t juUY]jjt$ jjj U E VuWuEuEPEBuuX tMxE EPjYY_^U E VuEWEPuEPEBuu tMxE EPj9YY_^j jYYjø+pt{x ||i{{"Ur"̋T$L$u<:u. t&:au% t:Au t:au uҋ3Ðt:u ttf:u t:au t̋L$t$tNu$$~Ѓ3ƒtAt2t$tt͍AL$+ÍAL$+ÍAL$+ÍAL$+UWVu M};v;|ur)$|_Ǻr $^$_$_^^^#ъFGFGr$|_I#ъFGr$|_#ъr$|_Is_`_X_P_H_@_8_0_DDDDDDDDDDDDDD$|_____E^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $a$`IǺr +$`$a,`P`x`F#шGr$aIF#шGFGr$aF#шGFGFGV$aI```````aDDDDDDDDD D DDDD$a(a0a@aTaE^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_=săPQL$-=s+ȋą@P̋T$*Zzr b$BB 02CVB$dBu B;L$ t D$ B$Iu@ B!D$BItVWt$z(v_^+̋T$*Zzr b$BdBu B@ B+UE VV01N pUF|UVUv 5tUt 5tUjxU%Y u %M ,`]I$U|+#|X!|ju UfI롅u,9U~i U9Uuy;h%VuDhjjYYt,V5(VtY$NO Y3ujdY3@e^] US]Vu W}u =U&tu"d]t WVSЅt WVSBu3NWVS4%E u u7WPStu&WVS u!E } td]tWVSЉE E _^[] Ut u=Uut$hYYÃHSS%Yu`\D\ ``@ `\$;rUVWD$P@f|$FD$H8h/D$;|9=D\}Nd\SW%Yt8D\ ``@ $;r9=D\|=D\3ۅ~jD$tTMtLu P<t<ˋÃ `\4D$EFF hP#YYt.FD$CE;|3ۋ `\ۍ4>uoFu jXyHP8t?W<t4%>uN@ uNF hP#YYtF N@NCr5D\43_^][HVW`\>t1t G PD$;r6*&Y`]|_^jh(uu uuF3}we=@\uGu ];,\w3jY!}S,YEMJ}tujWr# u:Vj5<\Hu%9=\XtV(#Yvu jYËjh8M3ۉ]jnY]j_};=m}Vx];tB@ tP.YtE|(x] PDx]4Yx]G럃M EjYYSVt$ F Ȁ3ۀu:ft4FW>+~'WPv"0 ;uF yF N _Ff^[Vt$VYt^F @tv~0Y^3^jhH'3}}jEY}3u;5mx];t\@ tVPVYY3BUx]H t/9UuPfYtE9}utPKYu E}F3uܡx]4VqYYÃM}EtEjYj h`R39uu VY$uYuuYEM ETuYjYVW3U<u8h0FYYt F$|3@_^Ã$3SDVW>t~t WW&Y|ܾ_t ~uPӃ|^[UE4Ÿ ]UVu4>t3@dWjYu"/ 3Ej B>Yu&hWpYYuWj YY‰>WYj t3Y@_^]UEV4Ÿ>uPhYujY6^]UVEPXu3uT3$3P3EPLE3E35xu xN@^hhX=x3EE W3;tMu uYYM3@ËeEHt4E`EMhPQ\uhP3/YYP/Y HN+IN~ WPS2)E 3t `\Ã@ t jjS1 FM3GWEPS( E 9} _tN E% F ^[]A @tyt$Ix  QPYYu UVMEM >t} ^]G @SVt!uD$ L$ C>t|$ ^[UTx3ESE3EEEԋE 3Ʉ5VWMG}}  |xx3jY;E$w3MEĉẺE܉EEEà t;t-tHHtMMM}MtMk*u!EE@EQM]EEˍDAЉE0e'*uEE@E MEˍDAЉEIt.ht ltwMMM <6u4uGGM} <3u2uGGe} -uMFuVYiHHt^HHE'EIf8t@@u+EpuEEI8t@u+ELEMEE+EQE0EEEEMEE E@t fMfMEE Et@t@@@@u3@t|s ؃ڀMu؋u3}} Ee9E~E ueuEM t$ERPWSA,09]؋~MЈN̍E+FEEut΀90uu MM0@E}]@t&tE-tE+ t E Eu+u+u uuEVj u}EMYtuWVj0E }tA}~;E]EM3fPEP++CYCY~'}PEM}YuuMEYEtuEVj f }t uG eY} _^M3ME[`|rpqgqqqqr W9pt 3$W=$WE]܉};uj9Mt QDY3ɉMEt tuSXU؉KXu9S\UC\u'EЋ5;}@sTL@މM}us\jY}]39MtQ#YuYEt tuM؉KXuEԉC\3U x3EMSVE3W3; t@r;#U;u =UhPRU\uhPC!YYP?@-ˋ_>-u-C}~H 38Mh<MQ} YYtEF A80t.FHy-Ad| jd^A | j ^A^]U,x3ESEVEPEPEp0s/u] EPFP3}-3ɅQ.juEVM3M(^[USVFH}Wt;E u3Ƀ>-M0`>-]u-CF3G w0C؃} ~S]_^[]ËL$AtD$T$SVWD$Pjhd5d%D$ Xp t.;t$$t(4v L$H |uhD@Td _^[3d yuQ R 9QuSQ SQMKCk Y[Vt$v'!Ytru3 8u^3@hUfF uMSW<^^fN _3[@^3^Ã|$t"Vt$ F tVf f&fY^tPl ËD$@T @SV`5tuIhj YYt-V5(tFT F$NjRYSp^[jh3uuPtu F$tPYF,tPYF4tP|YF=YtU;Yt7VPYY8u5UUh]3Y]_^[5UUUQS] 39UWt ME98"u3Ʌ@ѱ"-tG@Zt tG@ɋ] t2u t utge8 t u@H8}t ME93C3@B8\t8"u&u}t H9"u339MMt t\GJutH}u t= t8t.tZtG@GZt@@ht'G] !Et _[UQQSVW39=t]uY.%LXhHWVW\`];lj5Ut8uލEPWu3ɋ;uEP u%EP >Wu EHYUY=U3_^[QQPXSUVW=33;j]u-׋;t PX`xu ţPXPXu};u׋;tyf9tf9uf9u=SSS+S@PVSSD$4׋;t2U;YD$t#SSUPt$$VSSׅut$Y\$\$VP;t;t3D;t8t @8u@8u+@UX;Yu3 UVW V_^][YYÃ=pUu =|Ur3@jX39D$jhP<\t*@\uhqYu5<\33@Ã=@\uiS39$\U-|~EV5(\W= h@h6hj6vj5<\ՃC;$\|_^5(\j5<\][5<\3@ t$3@jhTXu7=pUt$hthPTXu lTXeu uЉE$EE3@Ëe}ujp3MEj hu=@\u.;5,\w&jYeV. YEM3Eu#uF=@\tVj5<\HËuj)YÃ|$w"t$uYu9D$tt$Yu35\Xt$YYáXXtt$ЅYt3@3̋T$ L$tO3D$Wr1كt +шuʃtt uD$_ËD$h@j5<\H(\uËL$% \%$\0\3 ,\4\@á$\ (\ T$+P r ;r3UMAVu W+y iDMIMS1UVUU] utJ?vj?ZK;KuB sL!\D u#M!JL! uM!Y] S[MMZU ZRSMJ?vj?Z]]+u]j?u K^;vMJ;։Mv;t^M q;qu; s!tDLu!M!1K!LuM!qM qINM qINu ]}u;M ыYN^qNqN;Nu`LM Ls%}uʻM DD )}uJM YJꍄ ED0E \ 8\5h@H SQ֋ 8\ \ P \@ 8\ \@HC \HyCu ` \xuiSjp ֡ \pj5<\|$\(\ȡ \+ȍLQHQPE $\; \vm(\0\E \=8\[_^á$\ 4\W3;u4DPP5(\W5<\;u3_Ã4\(\$\ (\VhAj5<\4H;ljFu3Cjh hW;ljF uvW5<\|ЃN>~$\F^_UQQMASVqW3C}i0Dj?EZ@@Jujhy hWup;UwC+ GAH@PǀIuˋUEO HAJ HAdD3GFCENCu x!P_^[U MASVuW} +Q iDMOI;|9M]UE;;MI?Mvj?YM_;_uC sML!\D u&M!ML! uM!YO_YOyM+M}}M O?L1vj?_]][Y]YKYKY;YuWLM Ls}uϻM DD }uOM YO U MD2LU FBD2<38/] )uNK\3uN?] Kvj?^EuN?vj?^O;OuB st!\Du#M!NL! uM!Y] OwqwOquuuN?vj?^M yK{YKYK;KuWLM Ls}uοM 9DD }uNM yN ED3@_^[UM$\(\SMVWI <}} M 3E0\؉u;K;#M# u ;]]r;]u$K;#M# u ;؉]r;0\CUt|D#M# u6#UeHD1#u ֋uu#UE9# tUiDMLD3#um#Mj _^{u ];]r;]u& {u ;؉]r;u؅ۉ]tSYKC8$3zG}MT +MN?M~j?^;J;Ju\ }&M|8Ӊ]#\D\Du3M]! ,OM|8!]u ]M!K]}JzyJzyM yJzQJQJ;Ju^LM L}#} u ;οM |D)} u N {MN 7Mt LMuэN L2uɍy>u; \uM; 8\u% \MB_^[Vt$WF t4VVvA }Ft PsfYf _^j hUMuF @t f EwVYeV}YEM׋uVYU x3EW39}E}}u3nES]V4`\D0 tjWWu6@9}E E}M+M };Ms'UEA u E @E@E}|ԋ+jEPWP40dtEE;|E+E 3;Er `E3E;9}tWj^9uuA 06WMQuu 0dt E}E`EuY,D0@t E 8u38+E^[M3M_j h_];D\sx<`\Ã4D0tXSYeD0tuu S E  MME!]SY j h(];D\<`\Ã4D0tmSAYeD0t1SYPu `Ee}tJM7 MME]SOY @ VL$H 3; tF-rr$$w~@ ^p H^ÁrwO@^A@^US39`XVWumh;5hWօ`Xt|h|WhhWdXփ=pUhXuhLWօpXt h4W֣lXlXt<ЅtMQj MQjPpXtEu=|Ur M )35MdXtЋ؅thXtSЋuu uS`X_^[W|$n$L$Wtt=u~Ѓ3ƒtAt#ttt͍y yyyL$ ttfu~Ѓ3‹tt4t'ttljD$_fD$G_fD$_ÈD$_̋L$ WVSًt$|$u 't+t/uuatt7uD$[^_tuutu[^D$_Ét~Ѓ3‹t܄t,tt uĉ3҉3t 3uwD$[^_VC20XC00USVWU] E@EEEECs {ta v|tEVUkT]^] t3x<{SkVS vjDC T{ v4롸UkjS]]_^[]UL$)APAP]jhp}3;uu Yu ;u WPYo=@\.]jSY]WYE;;5,\wLVWPx t}8VEYE;t*GHE;rPWuWAEWPb9]uK;u3Fu u VS5<\HE;t#GHE;rPWu蘾WuMO9]u";u3Fu VWS5<\EE;u`9\XtXVYE3ۋu }jY3w;u3FVWS5<\;u9\Xt VYu3 jh=@\u:jYeuVYEt v uuM$}uuj5<\ËujYVt$VYu? ^Wt$jt$Pu`3t PY΃ `\ƍD _^j h];D\sx<`\Ã4D0tXSjYeD0tuu S5 E} { MME!]SYM K vhUhYL$At I AI AAAAaËD$;D\r3Ëȃ `\D@UM V3;u3LE9pufEf=w,3@3U RVp(u QjMQVp;t9u tt*^] @d;Ltd t$t$P} VD$ u(L$D$ 3؋D$d$ȋd$Gȋ\$T$ D$ ud$ȋD$r;T$ wr;D$v N+D$T$3+D$T$ ؃ʋӋًȋ^_@d;Lt x(~jt$P Ë@HL$HUQS] Vu~W~$t 3Gs9~(~ WSV FHX#DžtqVHDJte jE] X e ]WvMjQPEPhv t$;uEM3e A|ZC ~_^[]@d;Lt t$PYYËD$j YjY+ʃL$҅t 3Ã<u@|3@ËD$VWj Y|$ PjY+3BR0 Nxv |!3}MEP^Y3Y@^eEPoYY3jY+N vMɁ ]@u M UY uM _^[ht$ t$ ht$ t$ Ux3EE3PPPPu EPEPuEPM3M$bUx3EE3PPPPu EPEPAuEPtM3M$UWVu M};v;|ur)$Ǻr $$$ ܨ#ъFGFGr$I#ъFGr$#ъr$Iph`XPH@DDDDDDDDDDDDDD$ĩE^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $($تIǺr +$,$(<`F#шGr$(IF#шGFGr$(F#шGFGFGV$(Iܪ DDDDDDDDD D DDDD$(8@PdE^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_UUJ S] VuW~0~]3ۊtAj0Z@MuU |95| 0H89t>1uBW轱@PWVT_^[]UQU 3fBSVWu%#ωE B%t;t<(!3;u;uEXfXM<] ME ΉHuP Ɂ։PtM fH_^[U,x3EVEWEPEP&YYEPjj ufu}FE։EԉFEPWM3M ~ 4_^jXY3tjXttt tt UVʾ #Wt!tt;u  #t ;u  _^]t 3t@tttt t˺#Vt#t;t ;u  ˁt u  ^t UQS}]؋E #؋E#E KE m [ËD$%Pt$YYVt$Fth DYu;tuYE;uo>[FYFYF 3E܃}f E[fLF@3E=} ZL0@3E=} [0@5Y}u;5Yt V Y}M E-j 胵YÃ=t]ujYt]3Vt$WV?Yt<tuj(j;YYtVYPu `3Vv`\Y dt W`Y3_^j h ;];D\sh<`\Ã4D0tHSYeD0t S,YE MME!]SY Vt$F ttvff 3YFF^UQQE VuEEWVE;Yu T )uMQuP;ljEu`t P6YNj`\ D EU_^ËL$; D\VWsX<`\4@t78t2=Uu3+tItIuPjPjPj 3 _^ËD$;D\sȃ `\@tL J ËD$SVW`\3<~u9j >~Yu#F hPhYYu j 舲Y3Fj yYD8 P3@_^[ËD$ȃ `\D P UQE HMw IHATVWyHDw_^tejEUX eE3@jqqMQPEPj,uE#Ej8h &39Xu8SS3FVh hSt5X`xu X9]~MEI8t@;u+EX;3}]]9] uXE SSuu39]$Pu u;E6誧eĉEԃM3@Ëex3ۉ]ԃM}u9]u6PYE;`EVuuuju SSVuu u};E t-9];}uuVuu uE?ܦeĉEЃM3@Ëe3ۉ]ЃM}u9]u?PYE;t@EWuVuu ut!SS9]uSSuuWuSu 9]t uY9]t uY[]3]9]uXE9] uXE uYEău3!;E SSMQuPu E;tSSuPu uu;]讥e}VSW 3@Ëeu33M;u#uY;t1uSW EuWuuu uE;u3&uuEPWu u@u9]t#WYuuuuu u9]t uYƍe貰ËT$Vt$ 23;r;s3@T$ ^Vt$W|$V76 tFPj0 tFFPw0 tFFPw0 _^ËD$V0Wx04? H _pH^ËD$PHVW ΉH _P^Ux3ES]3҉EE ;VWEN@SSvOE}쥥SeS_EPSSOEeeEEPSEMu39Su/{KE ;st׉{SEYstMfE3M_^fC [UXx3ESVE3W}uuEEEEE؉E܉EEE} t t t uGG s$b1| 9j:ujBÃ+t"HHtuOjXE룃ejX3@1E|9~:uj+t5-t00hCWE~cIe@jOj 1| 9H:K0`3@E}s E0FEGPYu:uFQ3@}EEu$MG0t}s E0FMGPJYu݀+H-?PEYj1OM| 9Ã+HHjEG0t1|9~DOu}E 8PjX9Ev}|ENEE}U1|9 j XO0t}몃} t&Ã+OMtHHu&MjXjXj XO xlueuE3ˍtAЁPGPYuQuGPYuuO MEN>tEPuEPE3Ƀ 9M}E9MuE9Mu+E=P.=|>uPEPeUċ]ƋuʋE΃ /E3۸3EE3333ۋM EԉYqfA EfM3M_^[žy߿7WI1U0x3ES]EEVȾ#fWEEEEEEEEEEEE?EtC-C fҋ} u u 9}f;ux;fu}t@uh Fftu }u.h ;u#}uh CPCeYYlh CPC‹iMfe NkM EEjPEPfU} f}?rEPEPF5 YYE}f3t C0~j_u?feEEPMYu}ށ~ EPNYuOɍCE~PMu}ХEPEPEPEP'EP|EMe0EMuEHH5K|A 89u0H;s;s@f*,CdEM3M_^[RÀ80uH;s;s0f#c3C C@Vt$vپvѾv ɾvv蹾v豾6誾v 袾v$蚾v(蒾v,芾v0肾v4zvrv8jvr }𥥥MuVuUYY39M u_^M3M[eUWVSu } t2'8t,A<ɀ A,A<ɀ A8t[^_VW脰xd;=Ltt$ (~jPW OHAtFF-t+uF30| 90t AF݃-_^űD$L$ ȋL$ u D$S؋D$d$؋D$[UWVSM tMu} AZ I& t' t#8r8w8r8w8u u38t rً[^_̍B[Í$d$3D$ST$t 8tτtQu WV ؋ ~333ƃu%t%uu^_[3ËB8t6t8t't8tt8tt^_B[ÍB^_[ÍB^_[ÍB^_[%h%jhh誙uuV YeViEEPu VEVuխM E螙uYjhxLuuV諅YeV Euu V蓜EVuxM EAu躅YË8csmt3袭jhјeM U EËeMUQQEEE3E %3EEEUVWVh?EEf%f=YYubEQQ$3YY~'~uEWQQ$j J EHW\$E$jjg uQQ$/V]W E_^]̃=Yw\$D$%=u<$f$ffd$F~D$f(f(f(fs4f~fTffʩuL=|}f=2 fL$D$f.{$T$ ԃT$T$$ D$~D$ff(f= |!=2 fT\fL$D$ffVfTf\$D$U VWVh? EEf%f=YYumQQ$gYY~0~eu&EW]E\$E$j[ vEWH\$E]E\$E$jj$DzVW EYY+EEPQQ$0E] }فM= E~7W\$$ \$E]E$QQE$jj=~0PQQ$5] EW\$E]E\$=} W\$E]E1=}BPQQ$] EW\$E]E\$E$jj $PQQ$V]W E_^̋\$+sd;5t V訧t0C P$ tC =02CVu C$ tS CPV赧jC<ӋZzr D$bbjt$ƱYYPVt$8csmuxux uCYtPYt VY3^hY35Yjhړ莨xltePl3@ËeMFUSQE EEUuMmBVW_^]MUuQ ]Y[ Vt$3Ft3^UQQEEM] fEEU3ҁ} u 9Uu3@]Á} u 9Uuj*M#f;ujfuE u9UtjX]3]UQQEDz 33fEubE u9MtTEz3@3e E tM eJEte;tMEQQQ$ #EQQQ$U E]EUM3AMAMS3ۉA MVCWt E XEtEHEtEHEtEHEtEHEu E3Hj1HE3H_1HE3H1HE3H#1HE3H#1HtMI tMI tMI tM y tE X  #t4=t=t ;u(E E E ˉE #t =t ;u"E E EEM31E X EH ωH EEXE X`EH` ϋ}H`EXPEPSjuE@t&@t&@t&@t&Xt&ߋt1ItIt Iu*N $!tItIu!#ʁ #ʁ@P_^[]UESV3ۋCut]tSnYtEtjTYEj2EY #=t[=t*;M At]EtM Au]EJM Au]E M At]EE3tW} DEPQQ$8M]E } Sz33EfE;}+]tum]tMmHutE]E_tjYeuEtE t j Y3^[ËD$t~-"!!ÊD$ tjt3@ètjtjXU 3 Ÿ;M td@|3Et^EEEEEEEVuEE EE$hu(uEEPD uV:YE^Ëżhu(juE U=u(uE \$\$E $uj3$]hu!E YY]UQQ=E E]u)uE\$E\$E $uj$跸hu!EYYUx3Eu $EPu u$d$@EPEPu E uPD$PBu&=u+t'u E\$\$E$u P!$P$u EYYL$|3M'x]Ux3Eu($E PuQ u4D$@E\$0D$@E PEPu E(uPD$PtuX=u,t(u(E \$E\$E$u PR$P$u(0E YYL$|3MXw]Q|$D$YQ|$D$YUQ}E M#M #E E m EQQL$ t -\$ t-\$t -\$t ؛ t\$YYU$x3EEE;VtsjY+t]HtNt:Ht+tH5EEELEME1EMEEEt5Ht&HtHQHEfEƋEEEE u]E]PE]YXE;-t_tJt5Ht&-=tHEEE@EE@EE8EE0EE u]E]P]Y茴"ED-t6Ht*HtHt HusED(EEu#ETE\EEuE ]EE]P]Yu !EM3M^*tj hH܆eef(E3@ËeMEUSWVX5 PZ+t QU%Y%YEtt 3@YY3^_[UQQSVV5KEYY؋EQf%f=Q$uUYY~-~u#ESQQ$j rVSEYYdESH\$E$j j?]EY]YDzVSEYY" uES\$E$j j^[j hXeE3@EE3=Ëe3M臅3QQD$ \$D$YY&Ծ~κ  .@Pbrл&6BNXhvڼ 4P`nƽҽ&8J\n~dsetSize() out of space in LOCAL arrayHh6H %s: %s %d: ODE INTERNAL ERROR %dODE Message\Visual Studio Projects\ODE\ODE\Src\geom.cppBad argument(s) (%s:%d)assertion "o2->_class->num == dSphereClass" failed in %s:%dassertion "o1->_class->num == dSphereClass" failed in %s:%dassertion "skip >= (int)sizeof(dContactGeom)" failed in %s:%dassertion "o2->_class->num == dBoxClass" failed in %s:%dassertion "o2->_class->num == dPlaneClass" failed in %s:%dassertion "o1->_class->num == dBoxClass" failed in %s:%dassertion "o1->_class->num == dCCylinderClass" failed in %s:%ddCollideCC(): too many iterationsassertion "o2->_class->num == dCCylinderClass" failed in %s:%dE@D`@`P0FY ]Qargument not a sphere (%s:%d)argument not a box (%s:%d)argument not a plane (%s:%d)argument not a ccylinder (%s:%d)bad geom class (%s:%d)bad class number (%s:%d)^p]_@^`_0a`joint is not a ball (%s:%d)\Visual Studio Projects\ODE\ODE\Src\joint.cppbad joint argument (%s:%d)bad result argument (%s:%d)joint is not a hinge (%s:%d)joint is not a Hinge (%s:%d)joint is not a slider (%s:%d)joint is not a hinge2 (%s:%d)not yet implementedjoint is not fixed (%s:%d)this should never get called\Visual Studio Projects\ODE\ODE\Src\lcp.cppassertion "A && n > 0 && i1 >= 0 && i2 >= 0 && i1 < n && i2 < n && nskip >= n && i1 < i2" failed in %s:%dassertion "n>0 && i1 >=0 && i2 >= 0 && i1 < n && i2 < n && nskip >= n && i1 <= i2" failed in %s:%dassertion "j < nC" failed in %s:%dassertion "k < nC" failed in %s:%dLCP internal error, s <= 0 (s=%.4e)assertion "lo[k] <= 0 && hi[k] >= 0" failed in %s:%dcenter of mass inconsistent with mass parameters (%s:%d)inertia must be positive definite (%s:%d)\Visual Studio Projects\ODE\ODE\Src\mass.cppmass must be > 0 (%s:%d)bad direction number (%s:%d)\Visual Studio Projects\ODE\ODE\Src\matrix.cppassertion "p[i] >= 0 && p[i] < n1" failed in %s:%dnum_bytes too largeunattached or disabled joint taggedattached enabled joint not taggedenabled body not taggeddisabled body taggedassertion "stacksize <= world->nj" failed in %s:%d\Visual Studio Projects\ODE\ODE\Src\ode.cppassertion "stacksize <= world->nb" failed in %s:%dassertion "w && j" failed in %s:%dassertion "w && vtable" failed in %s:%djoint can not be attached to just one body (%s:%d)joint and bodies must be in same world (%s:%d)can't have body1==body2 (%s:%d)warning: destroying world containing grouped jointsstepsize must be > 0 (%s:%d)bad world argument (%s:%d)vector has zero size (%s:%d)\Visual Studio Projects\ODE\ODE\Src\odemath.cpp\Visual Studio Projects\ODE\ODE\Src\rotation.cpp\Visual Studio Projects\ODE\ODE\Src\space.cppobject is already in a space (%s:%d)object is not in a space (%s:%d)must be a hash space (%s:%d)must have minlevel <= maxlevel (%s:%d)assertion "i >= 0 && i < (tested_rowsize*n)" failed in %s:%d\Visual Studio Projects\ODE\ODE\Src\step.cppassertion "p>0 && r>0 && A && B && C" failed in %s:%dassertion "p>0 && A && B && C" failed in %s:%dassertion "q>0 && A && B && C" failed in %s:%dassertion "info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m" failed in %s:%dassertion "joint[j2]->node[1].body || jb2==0" failed in %s:%dassertion "joint[j1]->node[1].body || jb1==0" failed in %s:%d& .>A buffer overrun has been detected which has corrupted the program's internal state. The program cannot safely continue execution and must now be terminated. Buffer overrun detected!A security error of unknown cause has been detected which has corrupted the program's internal state. The program cannot safely continue execution and must now be terminated. Unknown security failure detected!kl6n{nnnnEEE50P (8PX700WP `h````ppxxxx(null)(null)syruntime 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 This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. R6009 - not enough space for environment R6008 - not enough space for arguments R6002 - floating point not loaded Runtime Error! Program: e+000?~PAGAIsProcessorFeaturePresentKERNEL32gInitializeCriticalSectionAndSpinCountkernel32.dllىv)GetProcessWindowStationGetUserObjectInformationAGetLastActivePopupGetActiveWindowMessageBoxAuser32.dll ((((( H h(((( H H h(((( H   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~O=׻ۻԹع1#QNAN1#INF1#IND1#SNANHH:mm:ssdddd, MMMM dd, yyyyMM/dd/yyPMAMDecemberNovemberOctoberSeptemberAugustJulyJuneAprilMarchFebruaryJanuaryDecNovOctSepAugJulJunMayAprMarFebJanSaturdayFridayThursdayWednesdayTuesdayMondaySundaySatFriThuWedTueMonSun^bSunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDec KT??330COS_nextafter_logb_yn_y1_y0frexpfmod_hypot_cabsldexpmodffabsfloorceiltancossinsqrtatan2atanacosasintanhcoshsinhlog10logpowexp IqI`B `BYnYnexp2exp10log2IMBSJB v1.0.3705` :HP> EI> QM> ^O ?! ^Pd2 jQP?G sR?T |Sh@k |XHDv |]E |b8F |ghP |lQ |qY |v(] {x] |^ ~H^ _, _N `j `{ (e e hf g 8a xa a 8b* hB jr p *q *Hr ;(s Ks[Ht0jt\yxxxxyyXz{8|.x~I~zX(((x(2x@<X<tFxTbo{X84Qqx   x6K`v 8 Xح<X&t4!X?#XN)ȱN,(4/xZ1d2xq5س-|78B|9x[|;شpZ=>H?xA(C(DXFHINxy\8)nX)oH )p%8qCJs_\v8}oz}zX%FxR[e8u $h1CShs({X !1AZkX{Th )X: K]Xp----9x(H.HHDH ]W8qW(es H#%')H +-1/?0(Z18m2X283X6889=?8AXBxD,Eh7 GC HOI[ LiM~PShVH#Y#[/]?`X_fh hf vf8 9vg Nhd_j uj8 j m n ohqrt  vyH+ |L j. . (. ; E h- E P`c Z`&p `. i`7 `>c @`G 3`O `cL`j `ra`w ` 0` Q` 8` ]` `L`P`t ` P` p` `) 0`-5  `) д`[5 p` `p г`@ p`B5 y`K Pz`X  ``5 `) `d p`d `K  `X P`zK `X `K p` X `K `6X ` K `KX ``d `vd `d `5 `) `@d `Xd `K `X c`n : : : xW: WD; W ; W ; XX; W; X*; -8; -@; -H; -P; .FX; H.: (.: x.D; . ; .k; .s; .{; x/; /; /; /; h0; 1; 1; 2;! x2<) 2P< 3b< (3n<1 X3<1 3<1 3< 4< x4< 4< 4< 4 = 85= X52= 5E=; 6T=; x6c=D 6FX; V:T V: WD; 8W ;Z XWo=a 6FX; 6: 6D; 7 ;{ 87w= X7= 8; x7{; 8; 7; X8k; x8s; 9= 9= := X:= (8= := := ;= ;= ;> ;FX; E: E: ED; F ; (F> XF> ;FX; <: (<D; H< ; h<DX; H=: <: <: =D; >> => >+> >6> >A> ?I> h?Q> ?Z> ?c> @k> (@s> H@~> >> X>> ?> ?> h@FX; HA: @: !@: "AD; "B> "A> #B> %XB> &B> (B> +(CFX; +D: +C: -HC: .xDD; .D> .D> /HE> 1E> 2hE> 4EFX; 4I: 4HI: 6H: 7(JD; 7J> 7HJ> 8J> :J> ;K> =K> @KA> @8KI> CL>* CxF? KF? KF*? LF5? L8G@? MXGM? MxGZ? NGg? NGt? OG? OG? PH? P8H? QXH? QxH? RH? RH? SH? SLFX; SM: S8M: UL: VND; VxN> V8N> WN> YN> \8O@ \XO @ _O@ _O@ b8P&@ bXP0@ bxP>@ bP> bP> cPFX; e(T: eS: ghS: hTD; hT> hT> ihU> k8U> lUA> nUI> qV>* qQ? y(Q? yXQ*? zxQ5? zQ@? {QM? {QZ? |Rg? |(Rt? }HR? }hR? ~R? ~R? R? R? S? (SL@ HSY@ VFX;   $ ) 1 3 5 O Q 5 S O Q 5 S ~  5  O 3 5  O 3 5  ~ Q  ~ Q  ~ Q           " (  5 8  > A G N T Y ^ f       3          >  _ b e ^ f _ b e ^ f _ b e ^ f _ b e ^ f _ b e ^ f _ b e ^ f _ b e ^ f _ b e ^ f                       1 3           W ] b j W ] b j       b j             VW ] w{  ] W ] W    W    ] W ] W W    W    W  W  W W W W  W W  ] W ] W    W  W W   ]  ] W   ] W ] W W    W    W    W  W  W  W W W  W W   ] W ] W  W    W VW W W W  W W W W W   ] W ] W  ] W ] ~ 5 14 7~  3 bdgjl r 5 1 4 7     jAjZ1 ko5 ~  3 bdg r~ Q      <1 3    1 5 1 5 ~ 5 O 3 5 ~ 5 ~ 5 1  5 O  3 5  O  1 5  ~ jO   ~ 5  PP b3 3  3 3    3  3    3    3 3 3 3 3 3 3 3 3 3 %(+3 %(+3 %(+3 %(+ 3 %(+ b bbbbbbb QW   bb   b bbbbb1 1 5 jA ux{ux{ux{ux{A  AbA ,,  ,,        ~ Q  ~ Q  jF~ Q  jF~ Q  j~ Q  j~ Q  A3 W    ";/;    ;;;;  <<< 2<A<Y<\<_<Y<\<_<Y<\<_<|<<<Y<\<_<|<<<Y<\<_<|<<<<<Y<\<_<Y<\<_<      |<<<|<<<3     ;        1 3         > > > >    V    > >       > >    > >         >>>>>>? ? > >             > >      >>>>>>? ?:6 !:< Q: a:B c i: &G &^ >c &p t y@ y@ y@ > >t y@ y@ @ : : .Cb c3#Cc3c33#Ccc333##3Cc#Cc3333#3#CC3c3c333##3CC3c333#Cc3##3Cc3 3 # 3# C c    3    3# 3# C 3C c    3  3  # C c   3 3 3  @ `     ! !@!`!!!!!" "@"`"""""# #@#`#####$ $@$`$$$$$% %@%`%%%%%& &@&`&&&& &    P  - ' P><9;?" !!" # $%4&8'@(P)x*+.,-(./012`3 45X6478,9j:c;T<#=$>5?%@A*B`C D3E/FGH IJ0K(LM4N1O PQR=STU`VW|X6YmZ@[ \ 4foz" ,8<NXaiz*6EZo+Qbt8Jfny )5=SZar{z`ik c; g; ? ?  ? ? > > > > > > j@ w@  ? ? > > > > > > CDBA     !!##%%''))++--     |@4p4TpTHPDL !X"#$%$& '0((),*+,-./012$3T45p6789: ; <<=(>?@ABCDE\FGHI\JKLhMN<OPQRS TUVXW8XY$Z[\]p^L_X`|abcd(e|f\ghi0jklLmtnopq8rst uPvwxyzX{|}H~<@   ('&+&8&HGdArrayBase$ArrayType$0xed986b79_iobuf$ArrayType$0xe7df2480$ArrayType$0x6047384f$ArrayType$0x042bfd4b$ArrayType$0x16b5e9c4$ArrayType$0x14f3579d$ArrayType$0x9a50a794dContactGeom$ArrayType$0xfff53803$ArrayType$0x5d7903b1$ArrayType$0x0faed885dGeomClassdxGeomClass$ArrayType$0x40ef4e42$ArrayType$0xf4835a38dxGeomdxBodydxPosR$ArrayType$0x59f47f03$ArrayType$0x11bc4118$ArrayType$0x238a239adxSphere$ArrayType$0x6e8d0b04$ArrayType$0xf00e268a$ArrayType$0x08a77059$ArrayType$0x412d2475$ArrayType$0xb0b4aec4$ArrayType$0x2541e171$ArrayType$0x6bc21d81$ArrayType$0xf541300f$ArrayType$0x0e6cb2b2dArraydArraydInfBytesdxJointInfo2dxWorlddxJointLimitMotordxJointBallInfo1$ArrayType$0x76545072$ArrayType$0xec5a014edxJointHingedxJointSliderdxJointContactdxJointHinge2dxJointAMotor$ArrayType$0xa437c731$ArrayType$0x8a643b80$ArrayType$0x24838b46dxJointFixeddxJointNullVtable$ArrayType$0x446232f0$ArrayType$0x1efd57e5$ArrayType$0xf914dfeedLCP$ArrayType$0x58361534$ArrayType$0x731b46f7$ArrayType$0x0ae1ce00$ArrayType$0x6a0077b6dMass$ArrayType$0x12389576$ArrayType$0x68823c48$ArrayType$0x177783f3$ArrayType$0x38d7ac82$ArrayType$0x6f4f6133dObStackArenadxJointNode$ArrayType$0x3d98ba07$ArrayType$0xe8d77dfc$ArrayType$0x200ef7f4dxJointGroup$ArrayType$0x13faff41$ArrayType$0xf1cc4cbddxSimpleSpacedxSpacedxHashSpace$ArrayType$0x3a9112db$ArrayType$0x1e0cd3c1NodedxAABB$ArrayType$0xbf6e0f80$ArrayType$0x4c75f539$ArrayType$0x45a058c7$ArrayType$0x99654b2a$ArrayType$0x7ae17755$ArrayType$0x79c151b8Vector3ODEManagedVector4Matrix3WorldBodySpaceGeomJointGroupJointJointAMotorJointBallJointFixedJointHingeJointHinge2JointSlidermscorlibMicrosoft.VisualCSecurityActionSystem.Security.PermissionsSecurityPermissionAttributeAssemblyAttributesGoHereSMSystem.Runtime.CompilerServicesDebuggableAttributeSystem.DiagnosticsAssemblyAttributesGoHereCallConvCdeclCallConvThiscallIsConstModifierValueTypeSystemDebugInfoInPDBAttributeNoSignSpecifiedModifierDecoratedNameAttributeMiscellaneousBitsAttributeIsCXXReferenceModifierMathIsLongModifierObjectGCSuppressUnmanagedCodeSecurityAttributeSystem.SecuritydArrayBase._setSizenewsizesizeofTdArrayBase.newsizedArrayBase.deleteptr?A0xa51b0081.printMessagenummsg1msg2apdDotabn?A0x452938a3.dSolveL1_1LBlskip1?A0x452938a3.dSolveL1_2dFactorLDLTAdnskipdSolveL1dSolveL1TdMULTIPLY0_331CdMULTIPLY1_331dMULTIPLY0_333?A0xd80468a9.dCollideSpheresp1r1p2r2c?A0xd80468a9.lineClosestApproachpauapbubalphabetadBoxBoxR1side1R2side2normaldepthcodemaxccontactskip?A0xd80468a9.initCollisionArraysdCreateGeomClassdGeomGetClassgdGeomSetDatadatadGeomGetDatadGeomSetBodydGeomGetBodydGeomSetPositionxyzdGeomSetRotationRdGeomGetPositiondGeomGetRotationdCreateGeomclassnumdGeomDestroydCollideSSo1o2flagsdCollideSBdCollideSPdCollideBBdCollideBPdCollideCSdCollideCCdCollideCP?A0xd80468a9.dSphereColliderFn?A0xd80468a9.dSphereAABBgeomaabb?A0xd80468a9.dBoxColliderFn?A0xd80468a9.dBoxAABB?A0xd80468a9.dCCylinderColliderFn?A0xd80468a9.dCCylinderAABBdPlaneColliderFn?A0xd80468a9.dPlaneAABBdCreateSpherespaceradiusdCreateBoxlxlylzdCreateCCylinderlengthdCreatePlanedGeomSphereGetRadiusdGeomBoxGetLengthsresultdGeomPlaneGetParamsdGeomCCylinderGetParams?A0x58603bfe.setBalljointinfoanchor1anchor2?A0x58603bfe.setBall2axiserp1?A0x58603bfe.setAnchorsj?A0x58603bfe.setAxesaxis1axis2?A0x58603bfe.getHingeAnglebody1body2q_initialdxJointLimitMotor.setvaluedxJointLimitMotor.getdxJointLimitMotor.testRotationalLimitangledxJointLimitMotor.addLimotrowax1rotational?A0x58603bfe.ballInit?A0x58603bfe.ballGetInfo1?A0x58603bfe.ballGetInfo2dJointSetBallAnchordJointGetBallAnchor?A0x58603bfe.hingeInit?A0x58603bfe.hingeGetInfo1?A0x58603bfe.hingeGetInfo2?A0x58603bfe.hingeComputeInitialRelativeRotationdJointSetHingeAnchordJointSetHingeAxisdJointGetHingeAnchordJointGetHingeAxisdJointSetHingeParamparameterdJointGetHingeParamdJointGetHingeAngledJointGetHingeAngleRate?A0x58603bfe.sliderInitdJointGetSliderPositiondJointGetSliderPositionRate?A0x58603bfe.sliderGetInfo1?A0x58603bfe.sliderGetInfo2dJointSetSliderAxisdJointGetSliderAxisdJointSetSliderParamdJointGetSliderParam?A0x58603bfe.contactInit?A0x58603bfe.contactGetInfo1?A0x58603bfe.contactGetInfo2?A0x58603bfe.measureHinge2Angle?A0x58603bfe.hinge2Init?A0x58603bfe.hinge2GetInfo1?A0x58603bfe.hinge2GetInfo2?A0x58603bfe.makeHinge2V1andV2dJointSetHinge2AnchordJointSetHinge2Axis1dJointSetHinge2Axis2dJointGetHinge2AnchordJointGetHinge2Axis1dJointGetHinge2Axis2dJointGetHinge2Angle1dJointGetHinge2Angle1RatedJointGetHinge2Angle2Rate?A0x58603bfe.amotorInit?A0x58603bfe.amotorComputeGlobalAxesax?A0x58603bfe.amotorComputeEulerAngles?A0x58603bfe.amotorSetEulerReferenceVectors?A0x58603bfe.amotorGetInfo1?A0x58603bfe.amotorGetInfo2dJointSetAMotorNumAxesdJointSetAMotorAxisanumreldJointSetAMotorAngledJointSetAMotorParamdJointSetAMotorModemodedJointGetAMotorNumAxesdJointGetAMotorAxisdJointGetAMotorAxisReldJointGetAMotorAngledJointGetAMotorAngleRatedJointGetAMotorParamdJointGetAMotorMode?A0x58603bfe.fixedInit?A0x58603bfe.fixedGetInfo1?A0x58603bfe.fixedGetInfo2dJointSetFixed?A0x58603bfe.nullGetInfo1?A0x58603bfe.nullGetInfo2?A0xfd3124e6.swapRowsAndColsi1i2do_fast_row_swaps?A0xfd3124e6.swapProblemwlohipstatefindexdLCP.__ctor_n_nub_Adata_x_b_w_lo_hi_L_d_Dell_ell_tmp_state_findex_p_CArowsdLCP.transfer_i_to_CidLCP.transfer_i_from_N_to_CdLCP.transfer_i_from_C_to_NdLCP.pN_equals_ANC_times_qCqdLCP.pN_plusequals_ANisigndLCP.solve1dironly_transferdLCP.unpermutedSolveLCPnubdMULTIPLY2_333?A0x50c2799c.checkMassmdMassSetZerodMassSetParametersthemasscgxcgycgzI11I22I33I12I13I23dMassSetSpheredensitydMassSetCappedCylinderdirectiondMassSetBoxdSetZerodSetValuedFactorCholeskydSolveCholeskydInvertPDMatrixAinvdIsPositiveDefinitedVectorScaledSolveLDLTdLDLTAddTLdLDLTRemoven1n2rdRemoveRowColdAllocdReallocoldsizedFreedAllocDontReportdObStack.__ctordObStack.__dtordObStack.allocnum_bytesdObStack.freeAlldObStack.rewinddObStack.nextdBase.delete?A0xe5028ea3.removeJointReferencesFromAttachedBodies?A0xe5028ea3.processIslandsworldstepsizedBodyCreatedBodyDestroydBodySetDatadBodyGetDatadBodySetPositiondBodySetRotationdBodySetLinearVeldBodySetAngularVeldBodyGetPositiondBodyGetRotationdBodyGetLinearVeldBodyGetAngularVeldBodySetMassmassdBodyAddForcefxfyfzdBodyAddTorquedBodyAddRelForcedBodyAddRelTorquedBodyAddForceAtPospxpypzdBodyAddRelForceAtPosdBodyAddRelForceAtRelPosdBodyGetRelPointPosdBodyGetRelPointVel?A0xe5028ea3.dJointInit?A0xe5028ea3.createJointgroupvtabledJointCreateBalldJointCreateHingedJointCreateSliderdJointCreateHinge2dJointCreateFixeddJointCreateAMotordJointDestroydJointGroupCreatemax_sizedJointGroupDestroydxJointGroup.__dtordJointGroupEmptydJointAttachdAreConnectedb1b2dWorldCreatedWorldDestroydWorldSetGravitydWorldGetGravitydWorldSetERPerpdWorldGetERPdWorldSetCFMcfmdWorldGetCFMdWorldStepdNormalize3dNormalize4dPlaneSpacedRSetIdentitydQMultiply0qaqbqcdQMultiply1dQMultiply2dQMultiply3dQtoRdRtoQdWtoDQdq?A0x8a1ab737.collideAABBsbounds1bounds2g1g2callbackdSimpleSpaceCreatedxSimpleSpace.destroydxSimpleSpace.add__unnamed000dxSimpleSpace.removedxSimpleSpace.collidedHashSpaceCreatedxHashSpace.destroydHashSpaceSetLevelsminlevelmaxleveldxHashSpace.adddxHashSpace.removedxHashSpace.collidedSpaceDestroydSpaceAdddSpaceRemovedSpaceCollidedMULTIPLYADD0_331?A0x8201046a.Multiply2_p8rAskip?A0x8201046a.MultiplyAdd2_p8r?A0x8201046a.Multiply0_p81?A0x8201046a.MultiplyAdd0_p81?A0x8201046a.MultiplyAdd1_8q1?A0x8201046a.moveAndRotateBodyhdInternalStepIsland_x2bodynb_jointnjdInternalStepIslanddDebugfprintfvfprintffflushdMessagememmove__CxxCallUnwindDtormallocreallocfree_copysignfrexpfloorldexplongjmpstrlennewdelete__DllMainCRTStartup@12??_C@_0CG@NMCBFDMP@setSize?$CI?$CJ?5out?5of?5space?5in?5LOCAL?5@??_C@_08OGHPEGLJ@?6?$CFs?5?$CFd?3?5?$AA@??_C@_05CDHFJGNI@?6?$CFs?3?5?$AA@??_C@_01EEMJAFIK@?6?$AA@??_C@_0BG@IJGHIEJA@ODE?5INTERNAL?5ERROR?5?$CFd?$AA@??_C@_0M@NEHELGBE@ODE?5Message?$AA@?A0xa51b0081.debug_function?A0xa51b0081.error_function?A0xa51b0081.message_function??_C@_0CN@PBAKODFH@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0BH@BEBBKLIN@bad?5geom?5class?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BI@BPGDKPFJ@Bad?5argument?$CIs?$CJ?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BJ@FALOOJBO@bad?5class?5number?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0DO@OHGIHFAL@assertion?5?$CCskip?5?$DO?$DN?5?$CIint?$CJsizeof?$CId@??_C@_0DM@MNHLGIJM@assertion?5?$CCo1?9?$DO_class?9?$DOnum?5?$DN?$DN?5dS@??_C@_0DM@ILKJFNPI@assertion?5?$CCo2?9?$DO_class?9?$DOnum?5?$DN?$DN?5dS@??_C@_0DJ@IFAIIHCC@assertion?5?$CCo2?9?$DO_class?9?$DOnum?5?$DN?$DN?5dB@??_C@_0DL@EBPFAGEL@assertion?5?$CCo2?9?$DO_class?9?$DOnum?5?$DN?$DN?5dP@??_C@_0DJ@LKMDPJLH@assertion?5?$CCo1?9?$DO_class?9?$DOnum?5?$DN?$DN?5dB@??_C@_0DP@MBAEIBDK@assertion?5?$CCo1?9?$DO_class?9?$DOnum?5?$DN?$DN?5dC@??_C@_0DP@EEDGJDMO@assertion?5?$CCo2?9?$DO_class?9?$DOnum?5?$DN?$DN?5dC@??_C@_0CC@JHDPAAM@dCollideCC?$CI?$CJ?3?5too?5many?5iteration@??_C@_0BO@PDIKDMEF@argument?5not?5a?5sphere?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BL@CODJECFE@argument?5not?5a?5box?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BN@MNCPPEFJ@argument?5not?5a?5plane?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0CB@DHAOLAGD@argument?5not?5a?5ccylinder?5?$CI?$CFs?3?$CFd?$CJ@?A0xd80468a9.classesdGeomGroupClassdBoxClassdPlaneClassdSphereClassdCCylinderClass?A0xd80468a9.collidersdGeomTransformClass__unep@?dCollideSS@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dCollideSB@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dCollideSP@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dCollideBB@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dCollideBP@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dCollideCS@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dCollideCC@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dCollideCP@@$$FYAHPBUdxGeom@@0HPAUdContactGeom@@H@Z__unep@?dSphereColliderFn@?A0xd80468a9@@$$FYAP6AHPAUdxGeom@@0HPAUdContactGeom@@H@ZH@Z__unep@?dSphereAABB@?A0xd80468a9@@$$FYAXPAUdxGeom@@QAN@Z__unep@?dBoxColliderFn@?A0xd80468a9@@$$FYAP6AHPAUdxGeom@@0HPAUdContactGeom@@H@ZH@Z__unep@?dBoxAABB@?A0xd80468a9@@$$FYAXPAUdxGeom@@QAN@Z__unep@?dCCylinderColliderFn@?A0xd80468a9@@$$FYAP6AHPAUdxGeom@@0HPAUdContactGeom@@H@ZH@Z__unep@?dCCylinderAABB@?A0xd80468a9@@$$FYAXPAUdxGeom@@QAN@Z__unep@?dPlaneColliderFn@@$$FYAP6AHPAUdxGeom@@0HPAUdContactGeom@@H@ZH@Z__unep@?dPlaneAABB@?A0xd80468a9@@$$FYAXPAUdxGeom@@QAN@Z??_C@_0CO@CEMOKGO@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0BL@DBHCCIG@bad?5joint?5argument?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BM@KDPHHNBN@joint?5is?5not?5a?5ball?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BM@PDIDNBGN@bad?5result?5argument?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BN@OJILMJPO@joint?5is?5not?5a?5hinge?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BN@CEOPLBCG@joint?5is?5not?5a?5Hinge?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BO@EGEGAPEA@joint?5is?5not?5a?5slider?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BO@MMCEILJE@joint?5is?5not?5a?5hinge2?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BE@PEJLKNFI@not?5yet?5implemented?$AA@??_C@_0BL@CKGODMKE@joint?5is?5not?5fixed?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BN@LMEGJHPH@this?5should?5never?5get?5called?$AA@__dnull_vtable__dfixed_vtable__dslider_vtable__dhinge2_vtable__damotor_vtable__dhinge_vtable__dball_vtable__dcontact_vtable??_C@_0CM@CKHDECJP@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0GK@HALHKGLK@assertion?5?$CCA?5?$CG?$CG?5n?5?$DO?50?5?$CG?$CG?5i1?5?$DO?$DN?50@??_C@_0GD@CJEOIJML@assertion?5?$CCn?$DO0?5?$CG?$CG?5i1?5?$DO?$DN0?5?$CG?$CG?5i2?5?$DO@??_C@_0CD@HGGFIPOJ@assertion?5?$CCk?5?$DM?5nC?$CC?5failed?5in?5?$CFs?3@??_C@_0CD@PHEAOKMO@assertion?5?$CCj?5?$DM?5nC?$CC?5failed?5in?5?$CFs?3@??_C@_0CE@PEHMBDPO@LCP?5internal?5error?0?5s?5?$DM?$DN?50?5?$CIs?$DN?$CF?4@??_C@_0DF@FBJAIME@assertion?5?$CClo?$FLk?$FN?5?$DM?$DN?50?5?$CG?$CG?5hi?$FLk?$FN?5?$DO@??_C@_0CN@HJMMPCGC@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0BJ@HCAIPDDC@mass?5must?5be?5?$DO?50?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0CK@EFOPHPIM@inertia?5must?5be?5positive?5definit@??_C@_0DJ@HKCPNAGH@center?5of?5mass?5inconsistent?5with@??_C@_0BN@OJHAICJD@bad?5direction?5number?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0CP@PKEPKPFM@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0DD@JPNAKHMA@assertion?5?$CCp?$FLi?$FN?5?$DO?$DN?50?5?$CG?$CG?5p?$FLi?$FN?5?$DM?5n@?A0x4aa97bf2.freefn?A0x4aa97bf2.reallocfn?A0x4aa97bf2.allocfn?A0x80f160b2.seed??_C@_0BE@BGLBIMBE@num_bytes?5too?5large?$AA@??_C@_0CM@DCEAOINK@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0DD@PBLDMIJF@assertion?5?$CCstacksize?5?$DM?$DN?5world?9?$DOn@??_C@_0DD@PIBCNFBA@assertion?5?$CCstacksize?5?$DM?$DN?5world?9?$DOn@??_C@_0BF@MGEAPDPL@disabled?5body?5tagged?$AA@??_C@_0BI@EIELNPOI@enabled?5body?5not?5tagged?$AA@??_C@_0CC@NOPANLHG@attached?5enabled?5joint?5not?5tagge@??_C@_0CE@PNKICPIA@unattached?5or?5disabled?5joint?5tag@??_C@_0CD@KOBLPCIK@assertion?5?$CCw?5?$CG?$CG?5j?$CC?5failed?5in?5?$CFs?3@??_C@_0CI@PGLEOAHI@assertion?5?$CCw?5?$CG?$CG?5vtable?$CC?5failed?5i@??_C@_0CA@BLMGPAHF@can?8t?5have?5body1?$DN?$DNbody2?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0CP@BDKIFOI@joint?5and?5bodies?5must?5be?5in?5same@??_C@_0DD@OGAOMIOK@joint?5can?5not?5be?5attached?5to?5jus@??_C@_0DE@ELGPNAC@warning?3?5destroying?5world?5contai@??_C@_0BL@FFHHHIFE@bad?5world?5argument?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0BN@CIJGGBIJ@stepsize?5must?5be?5?$DO?50?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0DA@EEOKICBE@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0BN@CEAPOPDD@vector?5has?5zero?5size?5?$CI?$CFs?3?$CFd?$CJ?$AA@dInfinityValue??_C@_0DB@OLIFKNIJ@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0CO@NADGGGKH@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0CF@GDHOLMC@object?5is?5already?5in?5a?5space?5?$CI?$CFs@??_C@_0CB@OPAKLOIA@object?5is?5not?5in?5a?5space?5?$CI?$CFs?3?$CFd?$CJ@??_C@_0CH@GEDGPMKM@must?5have?5minlevel?5?$DM?$DN?5maxlevel?5?$CI@??_C@_0BN@MDBCOOCL@must?5be?5a?5hash?5space?5?$CI?$CFs?3?$CFd?$CJ?$AA@??_C@_0DN@LFNNJAHB@assertion?5?$CCi?5?$DO?$DN?50?5?$CG?$CG?5i?5?$DM?5?$CItested@?A0x8a1ab737.prime??_7dxHashSpace@@6B@??_7dxSimpleSpace@@6B@??_C@_0CN@KLAPIPJE@?2Visual?5Studio?5Projects?2ODE?2ODE?2@??_C@_0DG@KBEGCMII@assertion?5?$CCp?$DO0?5?$CG?$CG?5r?$DO0?5?$CG?$CG?5A?5?$CG?$CG?5B?5@??_C@_0CP@MFABKDHD@assertion?5?$CCp?$DO0?5?$CG?$CG?5A?5?$CG?$CG?5B?5?$CG?$CG?5C?$CC?5f@??_C@_0CP@FAHBHHOG@assertion?5?$CCq?$DO0?5?$CG?$CG?5A?5?$CG?$CG?5B?5?$CG?$CG?5C?$CC?5f@??_C@_0GN@MGEOOHI@assertion?5?$CCinfo?$FLi?$FN?4m?5?$DO?$DN?50?5?$CG?$CG?5inf@??_C@_0DO@BKBCCODH@assertion?5?$CCjoint?$FLj1?$FN?9?$DOnode?$FL1?$FN?4bo@??_C@_0DO@FNBCMLNB@assertion?5?$CCjoint?$FLj2?$FN?9?$DOnode?$FL1?$FN?4bo@?A0xb3b54937.jump_buffer?A0xb3b54937.tol?A0x42094a32.num?A0x42094a32.event_iob.ctorWm11m12m13m21m22m23m31m32m33FinalizeIdSetGravityGetGravitygravityStepstepSizeset_CFMget_CFMset_ERPget_ERP__dtor_idERPCFMSetDataGetDataSetPositionGetPositionpositionSetRotationIdentitySetRotationrotationGetRotationSetMasscenterOfGravityinertiaSetMassSphereSetMassBoxsideXsideYsideZSetMassCappedCylindercylinderRadiuscylinderLengthAddForcefXfYfZAddRelForceAddForceAtPospXpYpZAddRelForceAtPosAddRelForceAtRelPosApplyLinearVelocityDragdragCoefApplyAngularVelocityDragAddTorqueAddRelTorqueSetLinearVelocityGetLinearVelocitySetAngularVelocityGetAngularVelocityGetRelPointPosGetRelPointVelConnectedToCollideGetBodySetBodyCreateSphereCreateBoxCreatePlaneCreateCCylinderDestroySphereGetRadiusBoxGetLengthsPlaneGetParamsCCylinderGetParamsGetClassmaxSizeCreateEmptyjointGroupSetNumAxesGetNumAxesSetAxisGetAxisSetAngleGetAngleSetModeGetModeGetAxisRelGetAngleRateAttachSetParamGetParamSetAnchorGetAnchorSetFixedSetAllMovParamsLoStopHiStopVelocityMaxForceFudgeFactorBounceStopERPStopCFMget_LoStopset_LoStopget_HiStopset_HiStopget_Velocityset_Velocityget_MaxForceset_MaxForceget_FudgeFactorset_FudgeFactorget_Bounceset_Bounceget_StopERPset_StopERPget_StopCFMset_StopCFMget_Angleget_AngleRateAngleRateAngleSetAxis1GetAxis1SetAxis2GetAxis2GetAngle1GetAngle1RateGetAngle2Rateget_Positionget_PositionRatePositionRatePositionSqrtAbsAtan2SinCosSuppressFinalizeodeode.dll(}LF%_z\V4N“[Fr 01!/?_ :G{;NUDM  ! !      ! - ! - -   !  !    !         !  !    ,  !  !  !  !   (  !  !  !  !  !  !   ,    !< L  L  L  LP  PL  L  L !   ! L L L  !L !L,  LL,  L  LD  LD  LD  LD   L  L               PP    ! !   ! !  ! !   ! !                                                                      0                                      3  ! !              ! !  ! !    ! !   ! !    ! !                               !     !     !     !   !  !      !    !            ! !   ! !  ! !  ! !      P P  P  P  P  P !   ! P P ! P  P    4 4  4  4   ! !4 PP  PP              !     !    !  !     LL LL D   ! !@  ! !@L  ! !@ LL   ! !H  D  ! !HL  ! !H LL  D  DL D LL           P   ! !P ! !   ! -  ! -  ! - -    !                   ! -                          $  ! - -48DX\`hlpt|       A (08,<HL` !\dhl ! p(        t   (   9 P   | |  t|         t  9 !P  D  LLD L  9  9  9  9  9  x    L  44   9 9   t       9 9       ! -A ! -  ! -A ! -  ! -A -    ! -A       !   !   !   !          (  !    !    ! 1! !   !    !  !  L  L  : !  !  !  !  !  !  !  !  !  !  !  !  !  !   0k   !  !  !  !  ! , !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  ! 00000000T  , 000000  ,   0/ !  !  !  !  ! ,  !  ! 0   d0aF                     ,   xxxxxxx  , 0  @ LTL<L <   00  0000 0 0 00          00000    0  00 0C.         0000000000 00#   0000000   000  0000000 000 0000000000 00 0"  000  0      ! ! % ! ! ! ! ! ! ! !A  ! ! ! ! ! ! ! ! ! ! ! ! ! !   R ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !  ! ! ! !N7                                    $    !  !  !             ! 5&               !                    ! !     $$P 0PP$PP  P $ $ P0P0000 P0000   4 $PP     LL  LL   L  LL LL LLLL  L  z5LXXXXXTX X TX TX X  X  XXX ! !HP                         0P PPP P P P000000{7     ! !P           $  $           ! tt !   ! || t0t x0xTSkipVerification<PermissionSet class="System.Security.PermissionSet" version="1"> <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="SkipVerification"/> </PermissionSet> @\`dhlptx|<@DHLPTX\`dhlptx|  $(,TrX\&Ծ~κ  .@Pbrл&6BNXhvڼ 4P`nƽҽ&8J\n~dMessageBoxAUSER32.dllEnterCriticalSection-LeaveCriticalSectionExitProcessGetProcAddressgGetModuleHandleA1TerminateProcess/GetCurrentProcess2GetCurrentThreadId9TlsSetValueGetCommandLineAGetVersionExASetHandleCountGetStdHandlePGetFileTypeGetStartupInfoAvDeleteCriticalSectionHeapAlloc~QueryPerformanceCounterGetTickCount0GetCurrentProcessIdGetSystemTimeAsFileTimeeGetModuleFileNameAZGetLastErrorvWriteFileRtlUnwind7TlsFreeSetLastError8TlsGetValue6TlsAllocHeapFreeFreeEnvironmentStringsA?GetEnvironmentStringsFreeEnvironmentStringsWiWideCharToMultiByteAGetEnvironmentStringsWHeapDestroyHeapCreateXVirtualFreeInitializeCriticalSectionUVirtualAllocHeapReAllocFlushFileBuffers.LoadLibraryAHeapSizeSetFilePointerGetACP|GetOEMCPGetCPInfo,CloseHandle SetStdHandle LCMapStringAQMultiByteToWideChar!LCMapStringW]GetLocaleInfoAGetStringTypeAGetStringTypeW[VirtualProtectGetSystemInfo]VirtualQueryKERNEL32.dllY_CorDllMainmscoree.dllSetUnhandledExceptionFilterIsBadCodePtrRaiseExceptionnkXm(] gY !"#$%&'()*+,-xxxy({0|p~ppP0pX@p 4P?@ABCDEFHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijnopqrstuvwxyz{|}~ =???0   ` 0   ]]N@us\\\[   X `xPy@z0,               ! 5A CPR S WY l m pr   )     x .5 @ CDCC`y!@~ڣ @ڣ AϢ[@~QQ^ _j21~                      | x p d \ T  L D < 0 (         .@XXXXXXXXXDpPSTPDT@@@@ @P@$@@ @4@N@ p+ŝi@]%O@qוC)@D@<զIx@oGAkU'9p|Bݎ~QCv)/&D(DJzEeǑF e uuvHMXB䧓9;5SM]=];Z] T7aZ%]g']݀nLɛ R`%u?q= ףp= ף?Zd;On?,eX?#GGŧ?@il7?3=BzՔ?aw̫?/L[Mľ?S;uD?g9Eϔ?$#⼺;1az?aUY~S|_?/D?$?9'*?}d|FU>c{#Tw=:zc%C1B>??`0021p8899R:;2R?? 0"1122r3r456r7>?000R1229<=r? 134r566778:>?,R0R11"2r22r3324r445B5r5"9":R::92::;2<== b3P88888999'909A9]9n99999999:":K:R:_:e:n:u::::::::;";);6;;;C;L;`;i;n;u;z;;;;<<<<<<<<<<<=h>>>>>>>>> ????? ?$?(?,?v?|??????` 00 0$0(0I0s0000000000111 1$12222222333<3W3_3e33333 4e44444445F5M5^555556<6J6666666#787z777777 888-8899/9~99::!:K:W:]:::::::G;g;{;;;;;;;;;;<<"<)Q>]>d>>>>+?3???p0000~2*3D4444b5777788 888C8|8888888829;9A99999 :4:C::::::::;;1;@;R;;;;<<==*>>???????@0E0000011"1111111112 2212=2G2^222P3W3}333333334)4u4{4444455&585C55k66666666H7O7]7g777777838o8~88888888889 939?9I9Q9[9a9r999999999999 ::!:T:f:l:::I;O;V;c;j;p;x;~;;;====>>>(>3>E>X>c>i>n>t>>>>>>>>>>>>>?? ??!?-?K?\?b?s??tq3w334>6I6Q66 7=777=8R8888S9a9s9990:\::::::::::::::; ;;/;?;W;h;;>>?p?v????00(0D0O000001.1<1J11 24222o3q47777x8888888889 9$9(9,9094989<9999999 :$:+:0:4:8:Y:::::::::::";(;,;0;4;<>>> ?/?h???????? 0 00000000091E1]1t11111111 22*2I2i2222222 333393H3O3V3_3|33333333444&434<4E4Q444444444*5;55555556667(7H7j7777:8T8b8888999$9M9|99!:;:v:: ;D;Q;;$<{<{=_>>>*???b2f2j2n2r2v2z2~222222:3T3e33666667'727D7O7a7l7~777777778999(909;9D9n99:":D:Q::G;e;;;;$<<<<=t======>0>hh0q00J1P3V3]33644425z55616:6B666K7788 9999%9-99S::<7>=>Y>f>n>>>>>>>-?7?`*0001|11:22H3[3n333344"414D4i4445 55,5<5L5n55555556+666666#778444 4$4(4,40444444455??0?@?P?\?h?X\1`1p1|111125555566 606666p<<<<<<<<< >>> >p>>>>>>L0P0\0`000000 0,08000000000000000011 111 10141222222222355556666667 777$7,747<7D7L7T7\7d7l7p7t7x7|777990:@:D:L:<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=== ===== =$=(=,=0=D=H=L=P=T=X=\=`=d=h=t= >$>Hp111111111112 222$2,242<2D2L2T2\2d2l2t2|222222ode-0.14/contrib/DotNetManaged/Space.cpp0000644000000000000000000000112712635011627016560 0ustar rootroot#include "StdAfx.h" #include #include "Space.h" #include "TEST.h" namespace ODEManaged { //Constructor Space::Space(void) { _id = dSimpleSpaceCreate(); } Space::Space(int minlevel, int maxlevel) { _id = dHashSpaceCreate(); dHashSpaceSetLevels(this->_id, minlevel, maxlevel); } //Destructor Space::~Space(void) { dSpaceDestroy(this->_id); } //Methods //Id dSpaceID Space::Id() { return _id; } //Collide void Space::Collide(void *data, dNearCallback *callback) { dSpaceCollide(this->_id, data, callback); } } ode-0.14/contrib/DotNetManaged/Space.h0000644000000000000000000000053212635011627016224 0ustar rootroot#pragma once #include "CommonMgd.h" namespace ODEManaged { __gc public class Space { public: //Constructor Space(void); Space(int minlevel, int maxlevel); //Destructor ~Space(void); //Methods dSpaceID Id(void); void Collide(void *data, dNearCallback *callback); private: dSpaceID _id; }; } ode-0.14/contrib/DotNetManaged/Stdafx.cpp0000644000000000000000000000031112635011627016750 0ustar rootroot// stdafx.cpp : source file that includes just the standard includes // ODEManaged.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" ode-0.14/contrib/DotNetManaged/Stdafx.h0000644000000000000000000000030712635011627016422 0ustar rootroot// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, // but are changed infrequently #pragma once #using ode-0.14/contrib/DotNetManaged/TEST.h0000644000000000000000000000021212635011627015743 0ustar rootroot #pragma once #include "CommonMgd.h" namespace ODEManaged { void RnearCallback(void *data, dGeomID o1, dGeomID o2) { } } ode-0.14/contrib/DotNetManaged/World.cpp0000644000000000000000000000174612635011627016623 0ustar rootroot#include "StdAfx.h" #include #include "World.h" namespace ODEManaged { //Constructor World::World(void) { /*dWorldID _temp = dWorldCreate(); _id = _temp;*/ _id = dWorldCreate(); } //Destructor World::~World(void) { dWorldDestroy(this->_id); } //Methods //Id dWorldID World::Id() { return _id; } //SetGravity void World::SetGravity(double x, double y, double z) { dWorldSetGravity(this->_id, x, y, z); } //Overloaded GetGravity Vector3 World::GetGravity(void) { Vector3 retVal; dVector3 temp; dWorldGetGravity(this->_id, temp); retVal.x = temp[0]; retVal.y = temp[1]; retVal.z = temp[2]; return retVal; } void World::GetGravity(double gravity __gc[]) { dVector3 temp; dWorldGetGravity(this->_id, temp); gravity[0] = temp[0]; gravity[1] = temp[1]; gravity[2] = temp[2]; } //Step void World::Step(double stepSize) { dWorldStep(this->_id, stepSize); } } ode-0.14/contrib/DotNetManaged/World.h0000644000000000000000000000152512635011627016263 0ustar rootroot#pragma once #include "CommonMgd.h" namespace ODEManaged { __gc public class World { public: //Constructor World(void); //Destructor ~World(void); // Methods dWorldID Id(void); void SetGravity(double x, double y, double z); //Overloaded GetGravity Vector3 GetGravity(void); void GetGravity(double gravity __gc[]); void Step(double stepSize); //Properties //Constraint Force Mixing __property void set_CFM(double cfm) { dWorldSetCFM(this->_id,cfm); } __property double get_CFM(void) { return dWorldGetCFM(this->_id); } //Error Reduction Parameter __property void set_ERP(double erp) { dWorldSetERP(this->_id,erp); } __property double get_ERP(void) { return dWorldGetERP(this->_id); } private: dWorldID _id; }; } ode-0.14/contrib/GeomTransformGroup/0000775000000000000000000000000012635012023016137 5ustar rootrootode-0.14/contrib/GeomTransformGroup/GeomTransformGroup.cpp0000644000000000000000000001663012635011627022460 0ustar rootroot /* ************************************************************************ */ /* grouped and transformed geometry functions author: Tim Schmidt tisch@uni-paderborn.de */ #include #include #include #include #include #include #include #include #include #include "objects.h" #include "array.h" #include "geom_internal.h" // given a pointer `p' to a dContactGeom, return the dContactGeom at // p + skip bytes. #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) // ############################################################################ int dGeomTransformGroupClass = -1; // ############################################################################ struct dxGeomTransformGroup { dArray parts; // all the geoms that make up the group dVector3 relativePosition; dMatrix3 relativeRotation; }; // ############################################################################ void dGeomTransformGroupSetRelativePosition (dxGeom *g, dReal x, dReal y, dReal z) { dAASSERT (g); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); transformGroup->relativePosition[0] = x; transformGroup->relativePosition[1] = y; transformGroup->relativePosition[2] = z; } // ############################################################################ void dGeomTransformGroupSetRelativeRotation (dxGeom *g, const dMatrix3 R) { dAASSERT (g); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); memcpy (transformGroup->relativeRotation,R,sizeof(dMatrix3)); } // ############################################################################ const dReal * dGeomTransformGroupGetRelativePosition (dxGeom *g) { dAASSERT (g); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); return transformGroup->relativePosition; } // ############################################################################ const dReal * dGeomTransformGroupGetRelativeRotation (dxGeom *g) { dAASSERT (g); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); return transformGroup->relativeRotation; } // ############################################################################ static void computeFinalTransformation (const dxGeom *tg, const dxGeom *part) { dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(tg); dMULTIPLY0_331 (part->pos,tg->R,transformGroup->relativePosition); part->pos[0] += tg->pos[0]; part->pos[1] += tg->pos[1]; part->pos[2] += tg->pos[2]; dMULTIPLY0_333 (part->R,tg->R,transformGroup->relativeRotation); } // ############################################################################ int dCollideTransformGroup (const dxGeom *o1, const dxGeom *o2, int flags, dContactGeom *contact, int skip) { dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(o1); if (transformGroup->parts.size() == 0) { return 0; } int numleft = flags & NUMC_MASK; if (numleft == 0) numleft = 1; flags &= ~NUMC_MASK; int num=0, i=0; while (i < transformGroup->parts.size() && numleft > 0) { dUASSERT (transformGroup->parts[i]->spaceid==0, "GeomTransformGroup encapsulated object must not be in a space"); dUASSERT (transformGroup->parts[i]->body==0, "GeomTransformGroup encapsulated object must not be attached to a body"); if (!o1->space_aabb) { computeFinalTransformation (o1, transformGroup->parts[i]); } dxBody *bodyBackup = transformGroup->parts[i]->body; transformGroup->parts[i]->body = o1->body; int n = dCollide (transformGroup->parts[i],const_cast(o2), flags | numleft,contact,skip); transformGroup->parts[i]->body = bodyBackup; contact = CONTACT (contact,skip*n); numleft -= n; num += n; i++; } return num; } // ############################################################################ static dColliderFn * dGeomTransformGroupColliderFn (int num) { return (dColliderFn *) &dCollideTransformGroup; } // ############################################################################ static void dGeomTransformGroupAABB (dxGeom *geom, dReal aabb[6]) { dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(geom); aabb[0] = dInfinity; aabb[1] = -dInfinity; aabb[2] = dInfinity; aabb[3] = -dInfinity; aabb[4] = dInfinity; aabb[5] = -dInfinity; int i,j; for (i=0; i < transformGroup->parts.size(); i++) { computeFinalTransformation (geom, transformGroup->parts[i]); dReal aabb2[6]; transformGroup->parts[i]->_class->aabb (transformGroup->parts[i],aabb2); for (j=0; j<6; j += 2) if (aabb2[j] < aabb[j]) aabb[j] = aabb2[j]; for (j=1; j<6; j += 2) if (aabb2[j] > aabb[j]) aabb[j] = aabb2[j]; } } // ############################################################################ static void dGeomTransformGroupDtor (dxGeom *geom) { dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(geom); transformGroup->parts.~dArray(); } // ############################################################################ dxGeom *dCreateGeomTransformGroup (dSpaceID space) { if (dGeomTransformGroupClass == -1) { dGeomClass c; c.bytes = sizeof (dxGeomTransformGroup); c.collider = &dGeomTransformGroupColliderFn; c.aabb = &dGeomTransformGroupAABB; c.aabb_test = 0; c.dtor = dGeomTransformGroupDtor; dGeomTransformGroupClass = dCreateGeomClass (&c); } dxGeom *g = dCreateGeom (dGeomTransformGroupClass); if (space) { dSpaceAdd (space,g); } dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); transformGroup->parts.constructor(); dSetZero (transformGroup->relativePosition,4); dRSetIdentity (transformGroup->relativeRotation); return g; } // ############################################################################ void dGeomTransformGroupAddGeom (dxGeom *g, dxGeom *obj) { dUASSERT (g && g->_class->num == dGeomTransformGroupClass, "argument not a geom TransformGroup"); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); transformGroup->parts.push (obj); } // ############################################################################ void dGeomTransformGroupRemoveGeom (dxGeom *g, dxGeom *obj) { dUASSERT (g && g->_class->num == dGeomTransformGroupClass, "argument not a geom TransformGroup"); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); for (int i=0; i < transformGroup->parts.size(); i++) { if (transformGroup->parts[i] == obj) { transformGroup->parts.remove (i); return; } } } // ############################################################################ dxGeom * dGeomTransformGroupGetGeom (dxGeom *g, int i) { dUASSERT (g && g->_class->num == dGeomTransformGroupClass, "argument not a geom TransformGroup"); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); dAASSERT (i >= 0 && i < transformGroup->parts.size()); return transformGroup->parts[i]; } // ############################################################################ int dGeomTransformGroupGetNumGeoms (dxGeom *g) { dUASSERT (g && g->_class->num == dGeomTransformGroupClass, "argument not a geom TransformGroup"); dxGeomTransformGroup *transformGroup = (dxGeomTransformGroup*) CLASSDATA(g); return transformGroup->parts.size(); } ode-0.14/contrib/GeomTransformGroup/GeomTransformGroup.h0000644000000000000000000000154012635011627022117 0ustar rootroot /* ************************************************************************ */ /* grouped and transformed geometry functions author: Tim Schmidt tisch@uni-paderborn.de */ #ifdef __cplusplus extern "C" { #endif extern int dGeomTransformGroupClass; void dGeomTransformGroupSetRelativePosition (dGeomID g, dReal x, dReal y, dReal z); void dGeomTransformGroupSetRelativeRotation (dGeomID g, const dMatrix3 R); const dReal * dGeomTransformGroupGetRelativePosition (dxGeom *g); const dReal * dGeomTransformGroupGetRelativeRotation (dxGeom *g); dGeomID dCreateGeomTransformGroup (dSpaceID space); void dGeomTransformGroupAddGeom (dGeomID tg, dGeomID obj); void dGeomTransformGroupRemoveGeom (dGeomID tg, dGeomID obj); dGeomID dGeomTransformGroupGetGeom (dGeomID tg, int i); int dGeomTransformGroupGetNumGeoms (dGeomID tg); #ifdef __cplusplus } #endif ode-0.14/contrib/GeomTransformGroup/README.txt0000644000000000000000000001373612635011627017656 0ustar rootrootREADME for GeomTransformGroup by Tim Schmidt. --------------------------------------------- This is a patch to add the dGeomTransformGroup object to the list of geometry objects. It should work with the cvs version of the ode library from 07/24/2002. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ comment by russ smith: this code is easy to use with the rest of ODE. simply copy GeomTransformGroup.cpp to ode/src and copy GeomTransformGroup.h to include/ode. then add GeomTransformGroup.cpp to the ODE_SRC variable in the makefile. rebuild, and you're done! of course i could have done all this for you, but i prefer to keep GeomTransformGroup separated from the rest of ODE for now while other issues with the collision system are resolved. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Description: The dGeomTransformGroup is an adaption of the TransformGroup known from Java3D (and maybe other libraries with a similar scene graph representation). It can be used to build an arbitrarily structured tree of objects that are each positioned relative to the particular parent node. If you have a plane for example, there is one root node associated with the plane's body and another three transformgroups placed 'under' this node. One with the fuselage (cappedcylinder) under it and two with the underlying wings (flat boxes). And if you want to add engines, simply put them 'next to' the wings under another two transformgroups. bodyTG ---> associated with dBody | +--fuselageTG | | | +--fuselageCylinder | +--leftwingTG | | | +--wingBox | | | +--leftengineTG | | | +--leftengineCylinder | +--rightwingTG | +--wingBox | +--rightengineTG | +--rightengineCylinder This is a method to easily compose objects without the necessity of always calculating global coordinates. But apart from this there is something else that makes dGeomTransformGroups very valuable. Maybe you remember that some users reported the problem of acquiring the correct bodies to be attached by a contactjoint in the nearCallback when using dGeomGroups and dGeomTransforms at the same time. This results from the fact that dGeomGroups are not associated with bodies while all other geometries are. So, as you can see in the nearCallback of the the test_buggy demo you have to attach the contactjoint with the bodies that you get from the geometries that are stored in the contact struct (-> dGeomGetBody(contacts[i].geom.g1)). Normally you would do this by asking o1 and o2 directly with dGeomGetBody(o1) and dGeomGetBody(o2) respectively. As a first approach you can overcome that problem by testing o1 and o2 if they are groups or not to find out how to get the corresponding bodies. However this will fail if you want grouped transforms that are constructed out of dGeomTransforms encapsulated in a dGeomGroup. According to the test you use contacts[i].geom.g1 to get the right body. Unfortunately g1 is encapsulated in a transform and therefore not attached to any body. In this case the dGeomTransform 'in the middle' would have been the right object to be asked for the body. You may now conclude that it is a good idea to unwrap the group encapsulated geoms at the beginning of the nearcallback and use dGeomGetBody(o1) consistently. But keep in mind that this also means not to invoke dCollide(..) on groups at all and therefore not to expoit the capability of dGeomGroups to speed up collision detection by the creation of bounding boxes around the encapsulated geometry. Everything becomes even worse if you create a dGeomTransform that contains a dGeomGroup of geoms. The function that cares about the collision of transforms with other objects uses the position and rotation of the respective encapsulated object to compute its final position and orientation. Unfortunately dGeomGroups do not have a position and rotation, so the result will not be what you have expected. Here the dGeomTransformGroups comes into operation, because it combines the advantages and capabilities of the dGeomGroup and the dGeomTransform. And as an effect of synergy it is now even possible to set the position of a group of geoms with one single command. Even nested encapsulations of dGeomTransformGroups in dGeomTransformGroups should be possible (to be honest, I have not tried that so far ;-) ). ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ API: dGeomID dCreateGeomTransformGroup (dSpaceID space); - create a GeomTransformGroup void dGeomTransformGroupAddGeom (dGeomID tg, dGeomID obj); - Comparable to dGeomTransformSetGeom or dGeomGroupAdd - add objects to this group void dGeomTransformGroupRemoveGeom (dGeomID tg, dGeomID obj); - remove objects from this group void dGeomTransformGroupSetRelativePosition (dGeomID g, dReal x, dReal y, dReal z); void dGeomTransformGroupSetRelativeRotation (dGeomID g, const dMatrix3 R); - Comparable to setting the position and rotation of all the dGeomTransform encapsulated geometry. The difference is that it is global with respect to this group and therefore affects all geoms in this group. - The relative position and rotation are attributes of the transformgroup, so the position and rotation of the individual geoms are not changed const dReal * dGeomTransformGroupGetRelativePosition (dGeomID g); const dReal * dGeomTransformGroupGetRelativeRotation (dGeomID g); - get the relative position and rotation dGeomID dGeomTransformGroupGetGeom (dGeomID tg, int i); - Comparable to dGeomGroupGetGeom - get a specific geom of the group int dGeomTransformGroupGetNumGeoms (dGeomID tg); - Comparable to dGeomGroupGetNumGeoms - get the number of geoms in the group ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Tim Schmidt student of computer science University of Paderborn, Germany tisch@uni-paderborn.de ode-0.14/contrib/InteractiveCollisions/0000775000000000000000000000000012635012023016653 5ustar rootrootode-0.14/contrib/InteractiveCollisions/AUTHORS0000644000000000000000000000006212635011627017730 0ustar rootrootDaniel K. O. ode-0.14/contrib/InteractiveCollisions/COPYING0000644000000000000000000010451312635011627017721 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ode-0.14/contrib/InteractiveCollisions/ChangeLog0000644000000000000000000000003212635011627020427 0ustar rootroot2011-11-13 First version. ode-0.14/contrib/InteractiveCollisions/INSTALL0000644000000000000000000003633212635011627017722 0ustar rootrootInstallation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. ode-0.14/contrib/InteractiveCollisions/Makefile.am0000644000000000000000000000005512635011627020716 0ustar rootrootSUBDIRS = deps src EXTRA_DIST = bootstrap ode-0.14/contrib/InteractiveCollisions/NEWS0000644000000000000000000000010712635011627017357 0ustar rootroot2011-11-13 Basic functionality implemented (Sphere, Box, Capsule) ode-0.14/contrib/InteractiveCollisions/README0000644000000000000000000000041612635011627017543 0ustar rootrootThis is a simple tool to test pairs of ODE geoms. It uses AntTweakBar for the GUI. Dependencies are currently GLFW, but other backends (SDL, GLUT, etc) can be easily implemented, that part of the code is only used to open a windows and get mouse and keyboard events. ode-0.14/contrib/InteractiveCollisions/bootstrap0000755000000000000000000000023412635011627020624 0ustar rootroot#!/bin/sh libtoolize aclocal autoconf autoheader automake -a (echo "Running ./bootstrap in dependencies/AntTweakBar" && cd deps/AntTweakBar && ./bootstrap) ode-0.14/contrib/InteractiveCollisions/configure.ac0000644000000000000000000000230012635011627021143 0ustar rootroot# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.68]) AC_INIT([interactive-collision], [0.1], [danielosmari@users.sourceforge.net]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE LT_INIT # Checks for programs. AC_PROG_CC AC_PROG_CXX PKG_PROG_PKG_CONFIG AC_LANG(C++) # Checks for libraries. PKG_CHECK_MODULES(ODE, ode) PKG_CHECK_MODULES(OPENGL, gl glu) PKG_CHECK_MODULES(GLFW, libglfw, [have_glfw=true], [have_glfw=false]) AM_CONDITIONAL([GLFW], [test x$have_glfw = xtrue]) if test x$have_glfw = xtrue then AC_DEFINE([USE_GLFW], [1], [define if GLFW is available]) fi # TODO: when I get around implementing other backends... # PKG_CHECK_MODULES(SDL, sdl, AC_DEFINE(HAVE_SDL)) # PKG_CHECK_MODULES(GLUT, glut, AC_DEFINE(HAVE_GLUT)) # Checks for header files. AC_CHECK_HEADERS # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_CHECK_FUNCS([atexit]) AC_CHECK_FUNCS([sqrt]) AC_HEADER_STDBOOL AC_CONFIG_SUBDIRS([deps/AntTweakBar]) AC_CONFIG_FILES([Makefile deps/Makefile src/Makefile]) AC_OUTPUT ode-0.14/contrib/InteractiveCollisions/deps/0000775000000000000000000000000012635012023017606 5ustar rootrootode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/0000775000000000000000000000000012635012023021751 5ustar rootrootode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/AntTweakBar_Doc.url0000644000000000000000000000014712635011627025436 0ustar rootroot[InternetShortcut] URL=http://www.antisphere.com/Wiki/tools:anttweakbar Modified=C043A0DCA0FFC801E7 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/ChangeLog.txt0000644000000000000000000002273712635011627024363 0ustar rootroot--- AntTweakBar library release notes --- * Version 1.14 (2011/03/26) - Added 64 bit version of the library. - Added multiple windows support (Inspired by comments and code from Evan F. and Ivo H.) - Better MacOSX support (Thanks to Alexis DH., Fabrice N., Diederick H., Alec J.). - Improved readability of overlapped transparent bars. Content of overlapped regions is clipped and not drawn. This behavior can be disabled using the bar parameter "overlap". - Added support for Direct3D11. - Added support for SDL 1.3 integration in addition to SDL 1.2. ABI modification: TwEventSDL takes SDL version as an additional parameter. - Added support for SFML 1.6 integration. - Added support for GLFW 2.7 integration in addition to GLFW 2.6. This may imply changing the calling convention of event callbacks. Can be done by defining GLFW_CDECL before including AntTweakBar.h if needed. - Added function TwKeyTest that checks if a key event would be processed by AntTweakBar but without processing it. Needed to fix bad handling report of WM_KEYUP and WM_KEYDOWN in TwEventWin (Thanks to Ryan DB. for reporting it). - Added check sign for vars of type boolean. - Added new bar parameter "buttonalign" to center or left-align buttons (Suggested by Michael R.). - Allowed values column width to be adjusted to fit its content. This is done by setting the bar parameter valueswidth=fit (Requested by Koshmaar and Michael R.). The user can also click in the left or right area near the value width slider to fit column content. - Added new helper function TwDefineEnumFromString to ease the defining of an enum through a string of comma-separated enum values (Thanks to Bruno L. for the suggestion and code). - Fixed compilation issues with gcc4 (missing includes, warnings). - Fixes for the fedora package maintained by Sean Middleditch. - Fixed rotation widget display and interaction issues when the library is compiled with gcc -O3 (Thanks to Ares L. for reporting this). - Fixed SDL key event SDLK_RETURN handling after a bar is minimized (Thanks to Sean M. for reporting this). - Fixed issue with SDL_ShowCursor (Thanks to Hugues M. for reporting it). - Fixed DirectX10 resource issue. - Store and restore GL_TEXTURE_COORD_ARRAY state (Thanks to Jerry J. for reporting this). - Fixed mouse click repetition issue with passive event loop (Thanks to Bruno L. for reporting it). - Fixed issue with mouse button event when glut windows doesn't have focus (Thanks to Scott J. for the fix). - Reset enum content each time the var parameter "enum" is set using TwDefine or TwSetParam (Following Carsten W. and Sulaiman remarks). - Fixed memory corruption when more than one std_string are defined in a custom struct (Thanks to Sulaiman for reporting it). - Fixed mouse position issue with Direct3D9 fullscreen mode in TwSimpleDX9 (Thanks to Paolo S. for pointing this out). - Fixed ignored double-click in TwEvenWin (Thanks to H. Seungho for this). * Version 1.13 (2009/04/19) - Now compiles on Mac OSX (Many thanks to Evan F. for rewritting the OS specific code, and to Tyler S. and Konstantin L. for their feedback). - Added functions TwGetBarCount, TwGetBarByIndex, TwGetBarByName, TwRefreshBar. - Fixed bug related to var of type TW_TYPE_STDSTRING on Windows: Microsoft implementation of std::string does not have the same size in Debug and Release mode (hidden member added for debugging), which caused a crash when mixing the Release version of AntTweakBar with a program compiled in Debug mode (Thanks to Minh D. for reporting it). - Added function TwGetParam and TwSetParam to allow access to the parameters defining the behavior of bars and variables. - Changed the bar/var parameters without value (like "show"/"hide") to parameters with value ("visible=true or false") to be compatible with the new TwGetParam and TwSetParam functions (the old syntax is still kept for backward compatibility). - Arrow keys and Return key can now be used to navigate and tweak values. - Bars can now be moved partly outside of the window. They can still be constrained to be fully contained in the window by setting the parameter "contained=true". - Added another way to move a bar by pressing mouse middle button in the bar. * Version 1.12 (2008/09/27) - Added new var types TW_TYPE_QUAT* and TW_TYPE_DIR* allowing for the interactive tweaking of rotations (through quaternions) and 3D vectors (directions). - Better management of transparent tweak bars. New bar parameters added: alpha=n text=dark/light. - Default color scheme changed (now transparent by default). To reactivate the previous scheme, call TwDefine("GLOBAL colorscheme=0") before creating bars. - Added paramters to manage the bar behavior: resizable, movable, iconifiable, fontresizable, alwaystop, alwaysbottom, visible, iconified (following Jeppe F. B. feedback). - Added functions TwSetBottomBar and TwGetBottomBar. - The library can now be recompiled without requiring to install GLUT, GLFW and SDL. - New var parameters arrow, arrowcolor, axisx, axusy, axisz and showval added for quaternion and direction types. - Msvc specific keyword removed from PrefTimer (thanks to Tim J. for pointing this out). - Fixed bug related to popup behavior when the help bar is visible. - GL_TEXTURE_RECTANGLE_ARB/EXT state is now saved and restored by TwDraw (thanks to Cyril C. for suggesting this). - glBlendFunc and glBlendEquationEXT are now saved and restored by TwDraw (thanks to Sebastion B. for reporting the problem). - Fixed bug related cursor visibility state with SDL (Thanks to Jeppe F. B. for reporting it). * Version 1.11 (2007/12/10) - Now DirectX10 is also supported in addition to OpenGL and DirectX9. Initialization of AntTweakBar with DX10: TwInit(TW_DIRECT3D10, d3d10Device). - A new example that uses DirectX10 has been added: see TwSimpleDX10 in the examples directory. - Recap for string variables added to the doc. See http://www.antisphere.com/Wiki/tools:anttweakbar:varstring - An example that illustrates the use of the different types of string variables has been added. See TwString in the examples directory. - Added some code for multi-thread safety (thanks to Daniel 'DrUiD' B. for the tip). - Cleanup of the Help bar. Now only variables having help are displayed in the Help bar. - Function TwHandleErrors documented. - Separators don't require a name anymore. - Var parameter 'order' becomes 'colororder', and its values become 'rgba' and 'argb' (order=ogl and order=dx still exist but are deprecated). - A small icon added for variables of type bool. - Function TwCopyCDStringToLibrary added. - The keyword 'GLOBAL' has been added for TwDefine commands that don't apply to a specific tweak bar (suggested by Koshmaar). - TwEventWin32 becomes TwEventWin (a #define has been added to keep compatibility with previous applications). - TwWindowSize(0,0) now releases graphics resources allocated by AntTweakBar (may be useful for Direct3D applications, before resizing for instance). - A wrong assert removed from TwMgr.cpp (thanks to Chris W. for reporting it). - Some slight cosmetic changes (again). * Version 1.10 (2007/08/31) - Variable values can now also be entered and edited via keyboard input (implementation based on modifications made by Laury M., thank you Laury). - Variables of type string are now handled: 3 types of string added TW_TYPE_CSSTRING, TW_TYPE_CDSTRING and TW_STDSTRING. - Text selection and copy/paste added. - Position of bar icons is modifiable (cf. TwBar paramters iconPos, iconAlign and iconMargin). - Separators can be added in a bar (TwAddSeparator). - OpenGL: states related to 3D textures and multitexturing are now saved and restored by TwDraw (thanks to Dylan D. for pointing this out). - Selected element of a listbox now highlighted. - ReadOnly and ReadWrite behavior of buttons revisited. - Documentation improved (examples for TwType, new functions documented,...). - Some slight cosmetic changes. * Version 1.05 (2007/03/01) - Listbox and rotoslider buttons added. - Icon resources (AntTweakBar.rc) no more required for static linkage (thanks to Joe C. for pointing this out). - Fixed a rotoslider precision problem when mouse button is released. * Version 1.04 (2006/12/16) - OpenGL: Vertex buffer object state and Vertex/fragment program and object states are now reset and restored by TwDraw (thanks to Dylan D. and Siva K. for pointing this out). - Fixed problem that occurs when an initialized variable of type float/double is displayed. * Version 1.03 (2006/10/28) - Medium font antialiased. - Now also compiles on 64 bits x86 platform (thanks to Herling G. for this). - Slight changes to avoid visual 8 secure crt warnings. - Corrected behaviour if min/max values are not defined. - Modif to avoid looping to max value when reaching zero with unsigned types. - Min/max/step parameters for type TW_TYPE_CHAR now read ascii codes (not characters). - Added FPU precision control (because DirectX changes it). - Fixed problem that occurs when the lib is initialized/uninitialized more than once (thanks Lukasz P. for reporting it). - Distribution follows Savannah's recommendations. * Version 1.02 (2006/09/27) - Library sources released. * Version 1.01 (2006/09/14) - First official release. ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/License.txt0000644000000000000000000000162512635011627024107 0ustar rootroot--- AntTweakBar license --- Copyright (C) 2005-2011 Philippe Decaudin This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. http://www.antisphere.com ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/Makefile.am0000644000000000000000000000006312635011627024013 0ustar rootrootAUTOMAKE_OPTIONS = foreign SUBDIRS = include src ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/Readme.txt0000644000000000000000000000104412635011627023715 0ustar rootroot--- AntTweakBar development library --- AntTweakBar is a small and easy-to-use C/C++ library that allows programmers to quickly add a light and intuitive GUI into OpenGL and DirectX based graphic programs to interactively tweak parameters. This package includes the development version of the AntTweakBar library for Windows, GNU/Linux and OSX, and some program examples (sources + binaries). For installation and documentation please refer to: http://www.antisphere.com/Wiki/tools:anttweakbar Philippe Decaudin - http://www.antisphere.com ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/bootstrap0000755000000000000000000000006312635011627023722 0ustar rootroot#!/bin/sh libtoolize aclocal autoconf automake -a ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/configure.ac0000644000000000000000000000157212635011627024253 0ustar rootroot# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.68]) AC_INIT([AntTweakBar], [1.14]) AC_CONFIG_SRCDIR([include/AntTweakBar.h]) AM_INIT_AUTOMAKE(foreign) LT_INIT # Checks for programs. AC_PROG_CXX AC_PROG_AWK AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET PKG_PROG_PKG_CONFIG # Checks for libraries. PKG_CHECK_MODULES(OPENGL, gl glu) # Checks for header files. AC_CHECK_HEADERS([malloc.h memory.h stddef.h sys/time.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STDBOOL AC_C_INLINE AC_TYPE_INT64_T AC_TYPE_SIZE_T AC_CHECK_TYPES([ptrdiff_t]) # Checks for library functions. AC_CHECK_FUNCS([gettimeofday memset sqrt strstr]) AC_CONFIG_FILES([Makefile include/Makefile src/Makefile]) AC_OUTPUT ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/include/0000775000000000000000000000000012635012023023374 5ustar rootrootode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/include/AntTweakBar.h0000644000000000000000000003517512635011627025732 0ustar rootroot// ---------------------------------------------------------------------------- // // @file AntTweakBar.h // // @brief AntTweakBar is a light and intuitive graphical user interface // that can be readily integrated into OpenGL and DirectX // applications in order to interactively tweak parameters. // // @author Philippe Decaudin - http://www.antisphere.com // // @doc http://www.antisphere.com/Wiki/tools:anttweakbar // // @license This file is part of the AntTweakBar library. // AntTweakBar is a free software released under the zlib license. // For conditions of distribution and use, see License.txt // // ---------------------------------------------------------------------------- #if !defined TW_INCLUDED #define TW_INCLUDED #include #define TW_VERSION 114 // Version Mmm : M=Major mm=minor (e.g., 102 is version 1.02) #ifdef __cplusplus # if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable: 4995 4530) # include # pragma warning(pop) # else # include # endif extern "C" { #endif // __cplusplus // ---------------------------------------------------------------------------- // OS specific definitions // ---------------------------------------------------------------------------- #if defined(_WIN32) || defined(_WIN64) # define TW_CALL __stdcall # define TW_CDECL_CALL __cdecl # define TW_EXPORT_API __declspec(dllexport) # define TW_IMPORT_API __declspec(dllimport) #else # define TW_CALL # define TW_CDECL_CALL # define TW_EXPORT_API # define TW_IMPORT_API #endif #if defined TW_EXPORTS # define TW_API TW_EXPORT_API #elif defined TW_STATIC # define TW_API # if defined(_MSC_VER) && !defined(TW_NO_LIB_PRAGMA) # ifdef _WIN64 # pragma comment(lib, "AntTweakBarStatic64") # else # pragma comment(lib, "AntTweakBarStatic") # endif # endif #else # define TW_API TW_IMPORT_API # if defined(_MSC_VER) && !defined(TW_NO_LIB_PRAGMA) # ifdef _WIN64 # pragma comment(lib, "AntTweakBar64") # else # pragma comment(lib, "AntTweakBar") # endif # endif #endif // ---------------------------------------------------------------------------- // Bar functions and definitions // ---------------------------------------------------------------------------- typedef struct CTwBar TwBar; // structure CTwBar is not exposed. TW_API TwBar * TW_CALL TwNewBar(const char *barName); TW_API int TW_CALL TwDeleteBar(TwBar *bar); TW_API int TW_CALL TwDeleteAllBars(); TW_API int TW_CALL TwSetTopBar(const TwBar *bar); TW_API TwBar * TW_CALL TwGetTopBar(); TW_API int TW_CALL TwSetBottomBar(const TwBar *bar); TW_API TwBar * TW_CALL TwGetBottomBar(); TW_API const char * TW_CALL TwGetBarName(TwBar *bar); TW_API int TW_CALL TwGetBarCount(); TW_API TwBar * TW_CALL TwGetBarByIndex(int barIndex); TW_API TwBar * TW_CALL TwGetBarByName(const char *barName); TW_API int TW_CALL TwRefreshBar(TwBar *bar); // ---------------------------------------------------------------------------- // Var functions and definitions // ---------------------------------------------------------------------------- typedef enum ETwType { TW_TYPE_UNDEF = 0, #ifdef __cplusplus TW_TYPE_BOOLCPP = 1, #endif // __cplusplus TW_TYPE_BOOL8 = 2, TW_TYPE_BOOL16, TW_TYPE_BOOL32, TW_TYPE_CHAR, TW_TYPE_INT8, TW_TYPE_UINT8, TW_TYPE_INT16, TW_TYPE_UINT16, TW_TYPE_INT32, TW_TYPE_UINT32, TW_TYPE_FLOAT, TW_TYPE_DOUBLE, TW_TYPE_COLOR32, // 32 bits color. Order is RGBA if API is OpenGL or Direct3D10, and inversed if API is Direct3D9 (can be modified by defining 'colorOrder=...', see doc) TW_TYPE_COLOR3F, // 3 floats color. Order is RGB. TW_TYPE_COLOR4F, // 4 floats color. Order is RGBA. TW_TYPE_CDSTRING, // Null-terminated C Dynamic String (pointer to an array of char dynamically allocated with malloc/realloc/strdup) #ifdef __cplusplus TW_TYPE_STDSTRING = (0x2fff0000+sizeof(std::string)), // C++ STL string (std::string) #endif // __cplusplus TW_TYPE_QUAT4F = TW_TYPE_CDSTRING+2, // 4 floats encoding a quaternion {qx,qy,qz,qs} TW_TYPE_QUAT4D, // 4 doubles encoding a quaternion {qx,qy,qz,qs} TW_TYPE_DIR3F, // direction vector represented by 3 floats TW_TYPE_DIR3D // direction vector represented by 3 doubles } TwType; #define TW_TYPE_CSSTRING(n) ((TwType)(0x30000000+((n)&0xfffffff))) // Null-terminated C Static String of size n (defined as char[n], with n<2^28) typedef void (TW_CALL * TwSetVarCallback)(const void *value, void *clientData); typedef void (TW_CALL * TwGetVarCallback)(void *value, void *clientData); typedef void (TW_CALL * TwButtonCallback)(void *clientData); TW_API int TW_CALL TwAddVarRW(TwBar *bar, const char *name, TwType type, void *var, const char *def); TW_API int TW_CALL TwAddVarRO(TwBar *bar, const char *name, TwType type, const void *var, const char *def); TW_API int TW_CALL TwAddVarCB(TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def); TW_API int TW_CALL TwAddButton(TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def); TW_API int TW_CALL TwAddSeparator(TwBar *bar, const char *name, const char *def); TW_API int TW_CALL TwRemoveVar(TwBar *bar, const char *name); TW_API int TW_CALL TwRemoveAllVars(TwBar *bar); typedef struct CTwEnumVal { int Value; const char * Label; } TwEnumVal; typedef struct CTwStructMember { const char * Name; TwType Type; size_t Offset; const char * DefString; } TwStructMember; typedef void (TW_CALL * TwSummaryCallback)(char *summaryString, size_t summaryMaxLength, const void *value, void *clientData); TW_API int TW_CALL TwDefine(const char *def); TW_API TwType TW_CALL TwDefineEnum(const char *name, const TwEnumVal *enumValues, unsigned int nbValues); TW_API TwType TW_CALL TwDefineEnumFromString(const char *name, const char *enumString); TW_API TwType TW_CALL TwDefineStruct(const char *name, const TwStructMember *structMembers, unsigned int nbMembers, size_t structSize, TwSummaryCallback summaryCallback, void *summaryClientData); typedef void (TW_CALL * TwCopyCDStringToClient)(char **destinationClientStringPtr, const char *sourceString); TW_API void TW_CALL TwCopyCDStringToClientFunc(TwCopyCDStringToClient copyCDStringFunc); TW_API void TW_CALL TwCopyCDStringToLibrary(char **destinationLibraryStringPtr, const char *sourceClientString); #ifdef __cplusplus typedef void (TW_CALL * TwCopyStdStringToClient)(std::string& destinationClientString, const std::string& sourceString); TW_API void TW_CALL TwCopyStdStringToClientFunc(TwCopyStdStringToClient copyStdStringToClientFunc); TW_API void TW_CALL TwCopyStdStringToLibrary(std::string& destinationLibraryString, const std::string& sourceClientString); #endif // __cplusplus typedef enum ETwParamValueType { TW_PARAM_INT32, TW_PARAM_FLOAT, TW_PARAM_DOUBLE, TW_PARAM_CSTRING // Null-terminated array of char (ie, c-string) } TwParamValueType; TW_API int TW_CALL TwGetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues); TW_API int TW_CALL TwSetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues); // ---------------------------------------------------------------------------- // Management functions and definitions // ---------------------------------------------------------------------------- typedef enum ETwGraphAPI { TW_OPENGL = 1, TW_DIRECT3D9 = 2, TW_DIRECT3D10 = 3, TW_DIRECT3D11 = 4 } TwGraphAPI; TW_API int TW_CALL TwInit(TwGraphAPI graphAPI, void *device); TW_API int TW_CALL TwTerminate(); TW_API int TW_CALL TwDraw(); TW_API int TW_CALL TwWindowSize(int width, int height); TW_API int TW_CALL TwSetCurrentWindow(int windowID); // multi-windows support TW_API int TW_CALL TwGetCurrentWindow(); TW_API int TW_CALL TwWindowExists(int windowID); typedef enum ETwKeyModifier { TW_KMOD_NONE = 0x0000, // same codes as SDL keysym.mod TW_KMOD_SHIFT = 0x0003, TW_KMOD_CTRL = 0x00c0, TW_KMOD_ALT = 0x0100, TW_KMOD_META = 0x0c00 } TwKeyModifier; typedef enum EKeySpecial { TW_KEY_BACKSPACE = '\b', TW_KEY_TAB = '\t', TW_KEY_CLEAR = 0x0c, TW_KEY_RETURN = '\r', TW_KEY_PAUSE = 0x13, TW_KEY_ESCAPE = 0x1b, TW_KEY_SPACE = ' ', TW_KEY_DELETE = 0x7f, TW_KEY_UP = 273, // same codes and order as SDL 1.2 keysym.sym TW_KEY_DOWN, TW_KEY_RIGHT, TW_KEY_LEFT, TW_KEY_INSERT, TW_KEY_HOME, TW_KEY_END, TW_KEY_PAGE_UP, TW_KEY_PAGE_DOWN, TW_KEY_F1, TW_KEY_F2, TW_KEY_F3, TW_KEY_F4, TW_KEY_F5, TW_KEY_F6, TW_KEY_F7, TW_KEY_F8, TW_KEY_F9, TW_KEY_F10, TW_KEY_F11, TW_KEY_F12, TW_KEY_F13, TW_KEY_F14, TW_KEY_F15, TW_KEY_LAST } TwKeySpecial; TW_API int TW_CALL TwKeyPressed(int key, int modifiers); TW_API int TW_CALL TwKeyTest(int key, int modifiers); typedef enum ETwMouseAction { TW_MOUSE_RELEASED, TW_MOUSE_PRESSED } TwMouseAction; typedef enum ETwMouseButtonID { TW_MOUSE_LEFT = 1, // same code as SDL_BUTTON_LEFT TW_MOUSE_MIDDLE = 2, // same code as SDL_BUTTON_MIDDLE TW_MOUSE_RIGHT = 3 // same code as SDL_BUTTON_RIGHT } TwMouseButtonID; TW_API int TW_CALL TwMouseButton(TwMouseAction action, TwMouseButtonID button); TW_API int TW_CALL TwMouseMotion(int mouseX, int mouseY); TW_API int TW_CALL TwMouseWheel(int pos); TW_API const char * TW_CALL TwGetLastError(); typedef void (TW_CALL * TwErrorHandler)(const char *errorMessage); TW_API void TW_CALL TwHandleErrors(TwErrorHandler errorHandler); // ---------------------------------------------------------------------------- // Helper functions to translate events from some common window management // frameworks to AntTweakBar. // They call TwKeyPressed, TwMouse* and TwWindowSize for you (implemented in // files TwEventWin.c TwEventSDL*.c TwEventGLFW.c TwEventGLUT.c) // ---------------------------------------------------------------------------- // For Windows message proc #ifndef _W64 // Microsoft specific (detection of 64 bits portability issues) # define _W64 #endif // _W64 #ifdef _WIN64 TW_API int TW_CALL TwEventWin(void *wnd, unsigned int msg, unsigned __int64 _W64 wParam, __int64 _W64 lParam); #else TW_API int TW_CALL TwEventWin(void *wnd, unsigned int msg, unsigned int _W64 wParam, int _W64 lParam); #endif #define TwEventWin32 TwEventWin // For compatibility with AntTweakBar versions prior to 1.11 // For libSDL event loop TW_API int TW_CALL TwEventSDL(const void *sdlEvent, unsigned char sdlMajorVersion, unsigned char sdlMinorVersion); // For GLFW event callbacks // Define GLFW_CDECL before including AntTweakBar.h if your version of GLFW uses cdecl calling convensions #ifdef GLFW_CDECL TW_API int TW_CDECL_CALL TwEventMouseButtonGLFWcdecl(int glfwButton, int glfwAction); TW_API int TW_CDECL_CALL TwEventKeyGLFWcdecl(int glfwKey, int glfwAction); TW_API int TW_CDECL_CALL TwEventCharGLFWcdecl(int glfwChar, int glfwAction); TW_API int TW_CDECL_CALL TwEventMousePosGLFWcdecl(int mouseX, int mouseY); TW_API int TW_CDECL_CALL TwEventMouseWheelGLFWcdecl(int wheelPos); # define TwEventMouseButtonGLFW TwEventMouseButtonGLFWcdecl # define TwEventKeyGLFW TwEventKeyGLFWcdecl # define TwEventCharGLFW TwEventCharGLFWcdecl # define TwEventMousePosGLFW TwEventMousePosGLFWcdecl # define TwEventMouseWheelGLFW TwEventMouseWheelGLFWcdecl #else TW_API int TW_CALL TwEventMouseButtonGLFW(int glfwButton, int glfwAction); TW_API int TW_CALL TwEventKeyGLFW(int glfwKey, int glfwAction); TW_API int TW_CALL TwEventCharGLFW(int glfwChar, int glfwAction); # define TwEventMousePosGLFW TwMouseMotion # define TwEventMouseWheelGLFW TwMouseWheel #endif // For GLUT event callbacks (Windows calling convention for GLUT callbacks is cdecl) #if defined(_WIN32) || defined(_WIN64) # define TW_GLUT_CALL TW_CDECL_CALL #else # define TW_GLUT_CALL #endif TW_API int TW_GLUT_CALL TwEventMouseButtonGLUT(int glutButton, int glutState, int mouseX, int mouseY); TW_API int TW_GLUT_CALL TwEventMouseMotionGLUT(int mouseX, int mouseY); TW_API int TW_GLUT_CALL TwEventKeyboardGLUT(unsigned char glutKey, int mouseX, int mouseY); TW_API int TW_GLUT_CALL TwEventSpecialGLUT(int glutKey, int mouseX, int mouseY); TW_API int TW_CALL TwGLUTModifiersFunc(int (TW_CALL *glutGetModifiersFunc)(void)); typedef void (TW_GLUT_CALL *GLUTmousebuttonfun)(int glutButton, int glutState, int mouseX, int mouseY); typedef void (TW_GLUT_CALL *GLUTmousemotionfun)(int mouseX, int mouseY); typedef void (TW_GLUT_CALL *GLUTkeyboardfun)(unsigned char glutKey, int mouseX, int mouseY); typedef void (TW_GLUT_CALL *GLUTspecialfun)(int glutKey, int mouseX, int mouseY); // For SFML event loop TW_API int TW_CALL TwEventSFML(const void *sfmlEvent, unsigned char sfmlMajorVersion, unsigned char sfmlMinorVersion); // ---------------------------------------------------------------------------- // Make sure the types have the right sizes // ---------------------------------------------------------------------------- #define TW_COMPILE_TIME_ASSERT(name, x) typedef int TW_DUMMY_ ## name[(x) * 2 - 1] TW_COMPILE_TIME_ASSERT(TW_CHAR, sizeof(char) == 1); TW_COMPILE_TIME_ASSERT(TW_SHORT, sizeof(short) == 2); TW_COMPILE_TIME_ASSERT(TW_INT, sizeof(int) == 4); TW_COMPILE_TIME_ASSERT(TW_FLOAT, sizeof(float) == 4); TW_COMPILE_TIME_ASSERT(TW_DOUBLE, sizeof(double) == 8); // Check pointer size on Windows #if !defined(_WIN64) && defined(_WIN32) // If the following assert failed, the platform is not 32-bit and _WIN64 is not defined. // When targetting 64-bit Windows platform, _WIN64 must be defined. TW_COMPILE_TIME_ASSERT(TW_PTR32, sizeof(void*) == 4); #elif defined(_WIN64) // If the following assert failed, _WIN64 is defined but the targeted platform is not 64-bit. TW_COMPILE_TIME_ASSERT(TW_PTR64, sizeof(void*) == 8); #endif // --------------------------------------------------------------------------- #ifdef __cplusplus } // extern "C" #endif // __cplusplus #endif // !defined TW_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/include/Makefile.am0000644000000000000000000000004012635011627025431 0ustar rootrootnoinst_HEADERS = AntTweakBar.h ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/0000775000000000000000000000000012635012023022540 5ustar rootrootode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/AntPerfTimer.h0000644000000000000000000000372412635011627025266 0ustar rootroot// --------------------------------------------------------------------------- // // @file AntPerfTimer.h // @brief A performance (precision) timer for benchs // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: No cpp file is needed, everything is defined in this header // // --------------------------------------------------------------------------- #if !defined ANT_PERF_TIMER_INCLUDED #define ANT_PERF_TIMER_INCLUDED #ifndef __cplusplus # error This is a C++ header #endif // __cplusplus #if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64) #include #include struct PerfTimer { inline PerfTimer() { if( !QueryPerformanceFrequency(&Freq) ) MessageBox(NULL, _T("Precision timer not supported"), _T("Problem"), MB_ICONEXCLAMATION); Reset(); } inline void Reset() { QueryPerformanceCounter(&Start); } inline double GetTime() { if( QueryPerformanceCounter(&End) ) return ((double)End.QuadPart - (double)Start.QuadPart)/((double)Freq.QuadPart); else return 0; } protected: LARGE_INTEGER Start, End, Freq; }; #else // !_WIN (-> LINUX) #include #include struct PerfTimer { inline PerfTimer() { Reset(); } inline void Reset() { gettimeofday(&Start, &TZ); } inline double GetTime() { gettimeofday(&End,&TZ); double t1 = (double)Start.tv_sec + (double)Start.tv_usec/(1000*1000); double t2 = (double)End.tv_sec + (double)End.tv_usec/(1000*1000); return t2-t1; } protected: struct timeval Start, End; struct timezone TZ; }; #endif // _WIN #endif // ANT_PERF_TIMER_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/LoadOGL.cpp0000644000000000000000000003345112635011627024502 0ustar rootroot// --------------------------------------------------------------------------- // // @file LoadOGL.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "LoadOGL.h" // --------------------------------------------------------------------------- #define ANT_NB_OGL_FUNC_MAX 1024 struct COGLFuncRec { const char * m_Name; GL::PFNOpenGL * m_FuncPtr; COGLFuncRec() : m_Name(NULL), m_FuncPtr(NULL) {} }; COGLFuncRec g_OGLFuncRec[ANT_NB_OGL_FUNC_MAX]; int g_NbOGLFunc = 0; #if defined(ANT_WINDOWS) HMODULE g_OGLModule = NULL; #endif // --------------------------------------------------------------------------- ANT_GL_IMPL(glAccum) ANT_GL_IMPL(glAlphaFunc) ANT_GL_IMPL(glAreTexturesResident) ANT_GL_IMPL(glArrayElement) ANT_GL_IMPL(glBegin) ANT_GL_IMPL(glBindTexture) ANT_GL_IMPL(glBitmap) ANT_GL_IMPL(glBlendFunc) ANT_GL_IMPL(glCallList) ANT_GL_IMPL(glCallLists) ANT_GL_IMPL(glClear) ANT_GL_IMPL(glClearAccum) ANT_GL_IMPL(glClearColor) ANT_GL_IMPL(glClearDepth) ANT_GL_IMPL(glClearIndex) ANT_GL_IMPL(glClearStencil) ANT_GL_IMPL(glClipPlane) ANT_GL_IMPL(glColor3b) ANT_GL_IMPL(glColor3bv) ANT_GL_IMPL(glColor3d) ANT_GL_IMPL(glColor3dv) ANT_GL_IMPL(glColor3f) ANT_GL_IMPL(glColor3fv) ANT_GL_IMPL(glColor3i) ANT_GL_IMPL(glColor3iv) ANT_GL_IMPL(glColor3s) ANT_GL_IMPL(glColor3sv) ANT_GL_IMPL(glColor3ub) ANT_GL_IMPL(glColor3ubv) ANT_GL_IMPL(glColor3ui) ANT_GL_IMPL(glColor3uiv) ANT_GL_IMPL(glColor3us) ANT_GL_IMPL(glColor3usv) ANT_GL_IMPL(glColor4b) ANT_GL_IMPL(glColor4bv) ANT_GL_IMPL(glColor4d) ANT_GL_IMPL(glColor4dv) ANT_GL_IMPL(glColor4f) ANT_GL_IMPL(glColor4fv) ANT_GL_IMPL(glColor4i) ANT_GL_IMPL(glColor4iv) ANT_GL_IMPL(glColor4s) ANT_GL_IMPL(glColor4sv) ANT_GL_IMPL(glColor4ub) ANT_GL_IMPL(glColor4ubv) ANT_GL_IMPL(glColor4ui) ANT_GL_IMPL(glColor4uiv) ANT_GL_IMPL(glColor4us) ANT_GL_IMPL(glColor4usv) ANT_GL_IMPL(glColorMask) ANT_GL_IMPL(glColorMaterial) ANT_GL_IMPL(glColorPointer) ANT_GL_IMPL(glCopyPixels) ANT_GL_IMPL(glCopyTexImage1D) ANT_GL_IMPL(glCopyTexImage2D) ANT_GL_IMPL(glCopyTexSubImage1D) ANT_GL_IMPL(glCopyTexSubImage2D) ANT_GL_IMPL(glCullFace) ANT_GL_IMPL(glDeleteLists) ANT_GL_IMPL(glDeleteTextures) ANT_GL_IMPL(glDepthFunc) ANT_GL_IMPL(glDepthMask) ANT_GL_IMPL(glDepthRange) ANT_GL_IMPL(glDisable) ANT_GL_IMPL(glDisableClientState) ANT_GL_IMPL(glDrawArrays) ANT_GL_IMPL(glDrawBuffer) ANT_GL_IMPL(glDrawElements) ANT_GL_IMPL(glDrawPixels) ANT_GL_IMPL(glEdgeFlag) ANT_GL_IMPL(glEdgeFlagPointer) ANT_GL_IMPL(glEdgeFlagv) ANT_GL_IMPL(glEnable) ANT_GL_IMPL(glEnableClientState) ANT_GL_IMPL(glEnd) ANT_GL_IMPL(glEndList) ANT_GL_IMPL(glEvalCoord1d) ANT_GL_IMPL(glEvalCoord1dv) ANT_GL_IMPL(glEvalCoord1f) ANT_GL_IMPL(glEvalCoord1fv) ANT_GL_IMPL(glEvalCoord2d) ANT_GL_IMPL(glEvalCoord2dv) ANT_GL_IMPL(glEvalCoord2f) ANT_GL_IMPL(glEvalCoord2fv) ANT_GL_IMPL(glEvalMesh1) ANT_GL_IMPL(glEvalMesh2) ANT_GL_IMPL(glEvalPoint1) ANT_GL_IMPL(glEvalPoint2) ANT_GL_IMPL(glFeedbackBuffer) ANT_GL_IMPL(glFinish) ANT_GL_IMPL(glFlush) ANT_GL_IMPL(glFogf) ANT_GL_IMPL(glFogfv) ANT_GL_IMPL(glFogi) ANT_GL_IMPL(glFogiv) ANT_GL_IMPL(glFrontFace) ANT_GL_IMPL(glFrustum) ANT_GL_IMPL(glGenLists) ANT_GL_IMPL(glGenTextures) ANT_GL_IMPL(glGetBooleanv) ANT_GL_IMPL(glGetClipPlane) ANT_GL_IMPL(glGetDoublev) ANT_GL_IMPL(glGetError) ANT_GL_IMPL(glGetFloatv) ANT_GL_IMPL(glGetIntegerv) ANT_GL_IMPL(glGetLightfv) ANT_GL_IMPL(glGetLightiv) ANT_GL_IMPL(glGetMapdv) ANT_GL_IMPL(glGetMapfv) ANT_GL_IMPL(glGetMapiv) ANT_GL_IMPL(glGetMaterialfv) ANT_GL_IMPL(glGetMaterialiv) ANT_GL_IMPL(glGetPixelMapfv) ANT_GL_IMPL(glGetPixelMapuiv) ANT_GL_IMPL(glGetPixelMapusv) ANT_GL_IMPL(glGetPointerv) ANT_GL_IMPL(glGetPolygonStipple) ANT_GL_IMPL(glGetString) ANT_GL_IMPL(glGetTexEnvfv) ANT_GL_IMPL(glGetTexEnviv) ANT_GL_IMPL(glGetTexGendv) ANT_GL_IMPL(glGetTexGenfv) ANT_GL_IMPL(glGetTexGeniv) ANT_GL_IMPL(glGetTexImage) ANT_GL_IMPL(glGetTexLevelParameterfv) ANT_GL_IMPL(glGetTexLevelParameteriv) ANT_GL_IMPL(glGetTexParameterfv) ANT_GL_IMPL(glGetTexParameteriv) ANT_GL_IMPL(glHint) ANT_GL_IMPL(glIndexMask) ANT_GL_IMPL(glIndexPointer) ANT_GL_IMPL(glIndexd) ANT_GL_IMPL(glIndexdv) ANT_GL_IMPL(glIndexf) ANT_GL_IMPL(glIndexfv) ANT_GL_IMPL(glIndexi) ANT_GL_IMPL(glIndexiv) ANT_GL_IMPL(glIndexs) ANT_GL_IMPL(glIndexsv) ANT_GL_IMPL(glIndexub) ANT_GL_IMPL(glIndexubv) ANT_GL_IMPL(glInitNames) ANT_GL_IMPL(glInterleavedArrays) ANT_GL_IMPL(glIsEnabled) ANT_GL_IMPL(glIsList) ANT_GL_IMPL(glIsTexture) ANT_GL_IMPL(glLightModelf) ANT_GL_IMPL(glLightModelfv) ANT_GL_IMPL(glLightModeli) ANT_GL_IMPL(glLightModeliv) ANT_GL_IMPL(glLightf) ANT_GL_IMPL(glLightfv) ANT_GL_IMPL(glLighti) ANT_GL_IMPL(glLightiv) ANT_GL_IMPL(glLineStipple) ANT_GL_IMPL(glLineWidth) ANT_GL_IMPL(glListBase) ANT_GL_IMPL(glLoadIdentity) ANT_GL_IMPL(glLoadMatrixd) ANT_GL_IMPL(glLoadMatrixf) ANT_GL_IMPL(glLoadName) ANT_GL_IMPL(glLogicOp) ANT_GL_IMPL(glMap1d) ANT_GL_IMPL(glMap1f) ANT_GL_IMPL(glMap2d) ANT_GL_IMPL(glMap2f) ANT_GL_IMPL(glMapGrid1d) ANT_GL_IMPL(glMapGrid1f) ANT_GL_IMPL(glMapGrid2d) ANT_GL_IMPL(glMapGrid2f) ANT_GL_IMPL(glMaterialf) ANT_GL_IMPL(glMaterialfv) ANT_GL_IMPL(glMateriali) ANT_GL_IMPL(glMaterialiv) ANT_GL_IMPL(glMatrixMode) ANT_GL_IMPL(glMultMatrixd) ANT_GL_IMPL(glMultMatrixf) ANT_GL_IMPL(glNewList) ANT_GL_IMPL(glNormal3b) ANT_GL_IMPL(glNormal3bv) ANT_GL_IMPL(glNormal3d) ANT_GL_IMPL(glNormal3dv) ANT_GL_IMPL(glNormal3f) ANT_GL_IMPL(glNormal3fv) ANT_GL_IMPL(glNormal3i) ANT_GL_IMPL(glNormal3iv) ANT_GL_IMPL(glNormal3s) ANT_GL_IMPL(glNormal3sv) ANT_GL_IMPL(glNormalPointer) ANT_GL_IMPL(glOrtho) ANT_GL_IMPL(glPassThrough) ANT_GL_IMPL(glPixelMapfv) ANT_GL_IMPL(glPixelMapuiv) ANT_GL_IMPL(glPixelMapusv) ANT_GL_IMPL(glPixelStoref) ANT_GL_IMPL(glPixelStorei) ANT_GL_IMPL(glPixelTransferf) ANT_GL_IMPL(glPixelTransferi) ANT_GL_IMPL(glPixelZoom) ANT_GL_IMPL(glPointSize) ANT_GL_IMPL(glPolygonMode) ANT_GL_IMPL(glPolygonOffset) ANT_GL_IMPL(glPolygonStipple) ANT_GL_IMPL(glPopAttrib) ANT_GL_IMPL(glPopClientAttrib) ANT_GL_IMPL(glPopMatrix) ANT_GL_IMPL(glPopName) ANT_GL_IMPL(glPrioritizeTextures) ANT_GL_IMPL(glPushAttrib) ANT_GL_IMPL(glPushClientAttrib) ANT_GL_IMPL(glPushMatrix) ANT_GL_IMPL(glPushName) ANT_GL_IMPL(glRasterPos2d) ANT_GL_IMPL(glRasterPos2dv) ANT_GL_IMPL(glRasterPos2f) ANT_GL_IMPL(glRasterPos2fv) ANT_GL_IMPL(glRasterPos2i) ANT_GL_IMPL(glRasterPos2iv) ANT_GL_IMPL(glRasterPos2s) ANT_GL_IMPL(glRasterPos2sv) ANT_GL_IMPL(glRasterPos3d) ANT_GL_IMPL(glRasterPos3dv) ANT_GL_IMPL(glRasterPos3f) ANT_GL_IMPL(glRasterPos3fv) ANT_GL_IMPL(glRasterPos3i) ANT_GL_IMPL(glRasterPos3iv) ANT_GL_IMPL(glRasterPos3s) ANT_GL_IMPL(glRasterPos3sv) ANT_GL_IMPL(glRasterPos4d) ANT_GL_IMPL(glRasterPos4dv) ANT_GL_IMPL(glRasterPos4f) ANT_GL_IMPL(glRasterPos4fv) ANT_GL_IMPL(glRasterPos4i) ANT_GL_IMPL(glRasterPos4iv) ANT_GL_IMPL(glRasterPos4s) ANT_GL_IMPL(glRasterPos4sv) ANT_GL_IMPL(glReadBuffer) ANT_GL_IMPL(glReadPixels) ANT_GL_IMPL(glRectd) ANT_GL_IMPL(glRectdv) ANT_GL_IMPL(glRectf) ANT_GL_IMPL(glRectfv) ANT_GL_IMPL(glRecti) ANT_GL_IMPL(glRectiv) ANT_GL_IMPL(glRects) ANT_GL_IMPL(glRectsv) ANT_GL_IMPL(glRenderMode) ANT_GL_IMPL(glRotated) ANT_GL_IMPL(glRotatef) ANT_GL_IMPL(glScaled) ANT_GL_IMPL(glScalef) ANT_GL_IMPL(glScissor) ANT_GL_IMPL(glSelectBuffer) ANT_GL_IMPL(glShadeModel) ANT_GL_IMPL(glStencilFunc) ANT_GL_IMPL(glStencilMask) ANT_GL_IMPL(glStencilOp) ANT_GL_IMPL(glTexCoord1d) ANT_GL_IMPL(glTexCoord1dv) ANT_GL_IMPL(glTexCoord1f) ANT_GL_IMPL(glTexCoord1fv) ANT_GL_IMPL(glTexCoord1i) ANT_GL_IMPL(glTexCoord1iv) ANT_GL_IMPL(glTexCoord1s) ANT_GL_IMPL(glTexCoord1sv) ANT_GL_IMPL(glTexCoord2d) ANT_GL_IMPL(glTexCoord2dv) ANT_GL_IMPL(glTexCoord2f) ANT_GL_IMPL(glTexCoord2fv) ANT_GL_IMPL(glTexCoord2i) ANT_GL_IMPL(glTexCoord2iv) ANT_GL_IMPL(glTexCoord2s) ANT_GL_IMPL(glTexCoord2sv) ANT_GL_IMPL(glTexCoord3d) ANT_GL_IMPL(glTexCoord3dv) ANT_GL_IMPL(glTexCoord3f) ANT_GL_IMPL(glTexCoord3fv) ANT_GL_IMPL(glTexCoord3i) ANT_GL_IMPL(glTexCoord3iv) ANT_GL_IMPL(glTexCoord3s) ANT_GL_IMPL(glTexCoord3sv) ANT_GL_IMPL(glTexCoord4d) ANT_GL_IMPL(glTexCoord4dv) ANT_GL_IMPL(glTexCoord4f) ANT_GL_IMPL(glTexCoord4fv) ANT_GL_IMPL(glTexCoord4i) ANT_GL_IMPL(glTexCoord4iv) ANT_GL_IMPL(glTexCoord4s) ANT_GL_IMPL(glTexCoord4sv) ANT_GL_IMPL(glTexCoordPointer) ANT_GL_IMPL(glTexEnvf) ANT_GL_IMPL(glTexEnvfv) ANT_GL_IMPL(glTexEnvi) ANT_GL_IMPL(glTexEnviv) ANT_GL_IMPL(glTexGend) ANT_GL_IMPL(glTexGendv) ANT_GL_IMPL(glTexGenf) ANT_GL_IMPL(glTexGenfv) ANT_GL_IMPL(glTexGeni) ANT_GL_IMPL(glTexGeniv) ANT_GL_IMPL(glTexImage1D) ANT_GL_IMPL(glTexImage2D) ANT_GL_IMPL(glTexParameterf) ANT_GL_IMPL(glTexParameterfv) ANT_GL_IMPL(glTexParameteri) ANT_GL_IMPL(glTexParameteriv) ANT_GL_IMPL(glTexSubImage1D) ANT_GL_IMPL(glTexSubImage2D) ANT_GL_IMPL(glTranslated) ANT_GL_IMPL(glTranslatef) ANT_GL_IMPL(glVertex2d) ANT_GL_IMPL(glVertex2dv) ANT_GL_IMPL(glVertex2f) ANT_GL_IMPL(glVertex2fv) ANT_GL_IMPL(glVertex2i) ANT_GL_IMPL(glVertex2iv) ANT_GL_IMPL(glVertex2s) ANT_GL_IMPL(glVertex2sv) ANT_GL_IMPL(glVertex3d) ANT_GL_IMPL(glVertex3dv) ANT_GL_IMPL(glVertex3f) ANT_GL_IMPL(glVertex3fv) ANT_GL_IMPL(glVertex3i) ANT_GL_IMPL(glVertex3iv) ANT_GL_IMPL(glVertex3s) ANT_GL_IMPL(glVertex3sv) ANT_GL_IMPL(glVertex4d) ANT_GL_IMPL(glVertex4dv) ANT_GL_IMPL(glVertex4f) ANT_GL_IMPL(glVertex4fv) ANT_GL_IMPL(glVertex4i) ANT_GL_IMPL(glVertex4iv) ANT_GL_IMPL(glVertex4s) ANT_GL_IMPL(glVertex4sv) ANT_GL_IMPL(glVertexPointer) ANT_GL_IMPL(glViewport) #if defined(ANT_WINDOWS) ANT_GL_IMPL(wglGetProcAddress) #endif namespace GL { PFNGLGetProcAddress _glGetProcAddress = NULL; } // --------------------------------------------------------------------------- #if defined(ANT_WINDOWS) // --------------------------------------------------------------------------- int LoadOpenGL() { if( g_OGLModule!=NULL ) { return 1; // "OpenGL library already loaded" } g_OGLModule = LoadLibrary("OPENGL32.DLL"); if( g_OGLModule ) { // Info(VERB_LOW, "Load %d OpenGL functions", g_NbOGLFunc); int Res = 1; for(int i=0; i0); *(g_OGLFuncRec[i].m_FuncPtr) = reinterpret_cast(GetProcAddress(g_OGLModule, g_OGLFuncRec[i].m_Name)); if( *(g_OGLFuncRec[i].m_FuncPtr)==NULL ) Res = 0; // Error("cannot find OpenGL function"); } _glGetProcAddress = reinterpret_cast(_wglGetProcAddress); if( _glGetProcAddress==NULL ) Res = 0; return Res; } else { // InternDisplayLastErrorWIN("Cannot load opengl32 DLL", false); return 0; // cannot load DLL } } // --------------------------------------------------------------------------- int UnloadOpenGL() { if( g_OGLModule==NULL ) { return 1; // "OpenGL library not loaded" } // Info(VERB_LOW, "Unload %d OpenGL functions", g_NbOGLFunc); for(int i=0; i0); *(g_OGLFuncRec[i].m_FuncPtr) = NULL; } if( FreeLibrary(g_OGLModule) ) { // Info(VERB_LOW, "OpenGL library unloaded"); g_OGLModule = NULL; return 1; } else { // InternDisplayLastErrorWIN("Cannot unload opengl32 DLL", false); return 0; // cannot unload opengl32.dll } } // --------------------------------------------------------------------------- namespace GL { PFNOpenGL Record(const char *_FuncName, PFNOpenGL *_FuncPtr) { if( g_NbOGLFunc>=ANT_NB_OGL_FUNC_MAX ) { fprintf(stderr, "Too many OpenGL functions declared. Change ANT_NB_OGL_FUNC_MAX."); exit(-1); } g_OGLFuncRec[g_NbOGLFunc].m_Name = _FuncName; g_OGLFuncRec[g_NbOGLFunc].m_FuncPtr = _FuncPtr; ++g_NbOGLFunc; return NULL; } } // namespace GL // --------------------------------------------------------------------------- #endif // defined(ANT_WINDOWS) // --------------------------------------------------------------------------- #if defined(ANT_UNIX) int LoadOpenGL() { _glGetProcAddress = reinterpret_cast(glXGetProcAddressARB); return 1; // "OpenGL library is statically linked" } int UnloadOpenGL() { return 1; // "OpenGL library is statically linked" } #elif defined(ANT_OSX) #include static void *gl_dyld = NULL; void *NSGLGetProcAddressNew(const GLubyte *name) { void *proc=NULL; if (gl_dyld == NULL) { gl_dyld = dlopen("OpenGL",RTLD_LAZY); } if (gl_dyld) { NSString *sym = [[NSString alloc] initWithFormat: @"_%s",name]; proc = dlsym(gl_dyld,[sym UTF8String]); [sym release]; } return proc; } int LoadOpenGL() { _glGetProcAddress = reinterpret_cast(NSGLGetProcAddressNew); return 1; } int UnloadOpenGL() { if (gl_dyld) { dlclose(gl_dyld); gl_dyld = NULL; } return 1; } #endif // defined(ANT_UNIX) // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/LoadOGL.h0000644000000000000000000006061312635011627024147 0ustar rootroot// --------------------------------------------------------------------------- // // @file LoadOGL.h // @brief OpenGL declarations for dynamic loading // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_LOAD_OGL_INCLUDED #define ANT_LOAD_OGL_INCLUDED #define ANT_GL_DECL(_Ret, _Fct, _Params) \ extern "C" { typedef _Ret (APIENTRY* PFN##_Fct)_Params; } \ namespace GL { extern PFN##_Fct _##_Fct; } \ using GL::_##_Fct; #if defined(ANT_WINDOWS) # define ANT_GL_IMPL(_Fct) \ namespace GL { PFN##_Fct _##_Fct = (PFN##_Fct)Record(#_Fct, (PFNOpenGL*)(&_##_Fct)); } #elif defined(ANT_UNIX) || defined(ANT_OSX) # define ANT_GL_IMPL(_Fct) \ namespace GL { PFN##_Fct _##_Fct = _Fct; } # if !defined(APIENTRY) # define APIENTRY # endif #endif int LoadOpenGL(); int UnloadOpenGL(); namespace GL { extern "C" { typedef void (APIENTRY* PFNOpenGL)(); } PFNOpenGL Record(const char *_FuncName, PFNOpenGL *_FuncPtr); extern "C" { typedef PFNOpenGL (APIENTRY *PFNGLGetProcAddress)(const char *); } extern PFNGLGetProcAddress _glGetProcAddress; } using GL::_glGetProcAddress; ANT_GL_DECL(void, glAccum, (GLenum op, GLfloat value)) ANT_GL_DECL(void, glAlphaFunc, (GLenum func, GLclampf ref)) ANT_GL_DECL(GLboolean, glAreTexturesResident, (GLsizei n, const GLuint *textures, GLboolean *residences)) ANT_GL_DECL(void, glArrayElement, (GLint i)) ANT_GL_DECL(void, glBegin, (GLenum mode)) ANT_GL_DECL(void, glBindTexture, (GLenum target, GLuint texture)) ANT_GL_DECL(void, glBitmap, (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)) ANT_GL_DECL(void, glBlendFunc, (GLenum sfactor, GLenum dfactor)) ANT_GL_DECL(void, glCallList, (GLuint list)) ANT_GL_DECL(void, glCallLists, (GLsizei n, GLenum type, const GLvoid *lists)) ANT_GL_DECL(void, glClear, (GLbitfield mask)) ANT_GL_DECL(void, glClearAccum, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) ANT_GL_DECL(void, glClearColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) ANT_GL_DECL(void, glClearDepth, (GLclampd depth)) ANT_GL_DECL(void, glClearIndex, (GLfloat c)) ANT_GL_DECL(void, glClearStencil, (GLint s)) ANT_GL_DECL(void, glClipPlane, (GLenum plane, const GLdouble *equation)) ANT_GL_DECL(void, glColor3b, (GLbyte red, GLbyte green, GLbyte blue)) ANT_GL_DECL(void, glColor3bv, (const GLbyte *v)) ANT_GL_DECL(void, glColor3d, (GLdouble red, GLdouble green, GLdouble blue)) ANT_GL_DECL(void, glColor3dv, (const GLdouble *v)) ANT_GL_DECL(void, glColor3f, (GLfloat red, GLfloat green, GLfloat blue)) ANT_GL_DECL(void, glColor3fv, (const GLfloat *v)) ANT_GL_DECL(void, glColor3i, (GLint red, GLint green, GLint blue)) ANT_GL_DECL(void, glColor3iv, (const GLint *v)) ANT_GL_DECL(void, glColor3s, (GLshort red, GLshort green, GLshort blue)) ANT_GL_DECL(void, glColor3sv, (const GLshort *v)) ANT_GL_DECL(void, glColor3ub, (GLubyte red, GLubyte green, GLubyte blue)) ANT_GL_DECL(void, glColor3ubv, (const GLubyte *v)) ANT_GL_DECL(void, glColor3ui, (GLuint red, GLuint green, GLuint blue)) ANT_GL_DECL(void, glColor3uiv, (const GLuint *v)) ANT_GL_DECL(void, glColor3us, (GLushort red, GLushort green, GLushort blue)) ANT_GL_DECL(void, glColor3usv, (const GLushort *v)) ANT_GL_DECL(void, glColor4b, (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha)) ANT_GL_DECL(void, glColor4bv, (const GLbyte *v)) ANT_GL_DECL(void, glColor4d, (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)) ANT_GL_DECL(void, glColor4dv, (const GLdouble *v)) ANT_GL_DECL(void, glColor4f, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) ANT_GL_DECL(void, glColor4fv, (const GLfloat *v)) ANT_GL_DECL(void, glColor4i, (GLint red, GLint green, GLint blue, GLint alpha)) ANT_GL_DECL(void, glColor4iv, (const GLint *v)) ANT_GL_DECL(void, glColor4s, (GLshort red, GLshort green, GLshort blue, GLshort alpha)) ANT_GL_DECL(void, glColor4sv, (const GLshort *v)) ANT_GL_DECL(void, glColor4ub, (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)) ANT_GL_DECL(void, glColor4ubv, (const GLubyte *v)) ANT_GL_DECL(void, glColor4ui, (GLuint red, GLuint green, GLuint blue, GLuint alpha)) ANT_GL_DECL(void, glColor4uiv, (const GLuint *v)) ANT_GL_DECL(void, glColor4us, (GLushort red, GLushort green, GLushort blue, GLushort alpha)) ANT_GL_DECL(void, glColor4usv, (const GLushort *v)) ANT_GL_DECL(void, glColorMask, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) ANT_GL_DECL(void, glColorMaterial, (GLenum face, GLenum mode)) ANT_GL_DECL(void, glColorPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) ANT_GL_DECL(void, glCopyPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)) ANT_GL_DECL(void, glCopyTexImage1D, (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border)) ANT_GL_DECL(void, glCopyTexImage2D, (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)) ANT_GL_DECL(void, glCopyTexSubImage1D, (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)) ANT_GL_DECL(void, glCopyTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)) ANT_GL_DECL(void, glCullFace, (GLenum mode)) ANT_GL_DECL(void, glDeleteLists, (GLuint list, GLsizei range)) ANT_GL_DECL(void, glDeleteTextures, (GLsizei n, const GLuint *textures)) ANT_GL_DECL(void, glDepthFunc, (GLenum func)) ANT_GL_DECL(void, glDepthMask, (GLboolean flag)) ANT_GL_DECL(void, glDepthRange, (GLclampd zNear, GLclampd zFar)) ANT_GL_DECL(void, glDisable, (GLenum cap)) ANT_GL_DECL(void, glDisableClientState, (GLenum array)) ANT_GL_DECL(void, glDrawArrays, (GLenum mode, GLint first, GLsizei count)) ANT_GL_DECL(void, glDrawBuffer, (GLenum mode)) ANT_GL_DECL(void, glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)) ANT_GL_DECL(void, glDrawPixels, (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_DECL(void, glEdgeFlag, (GLboolean flag)) ANT_GL_DECL(void, glEdgeFlagPointer, (GLsizei stride, const void *pointer)) ANT_GL_DECL(void, glEdgeFlagv, (const GLboolean *flag)) ANT_GL_DECL(void, glEnable, (GLenum cap)) ANT_GL_DECL(void, glEnableClientState, (GLenum array)) ANT_GL_DECL(void, glEnd, (void)) ANT_GL_DECL(void, glEndList, (void)) ANT_GL_DECL(void, glEvalCoord1d, (GLdouble u)) ANT_GL_DECL(void, glEvalCoord1dv, (const GLdouble *u)) ANT_GL_DECL(void, glEvalCoord1f, (GLfloat u)) ANT_GL_DECL(void, glEvalCoord1fv, (const GLfloat *u)) ANT_GL_DECL(void, glEvalCoord2d, (GLdouble u, GLdouble v)) ANT_GL_DECL(void, glEvalCoord2dv, (const GLdouble *u)) ANT_GL_DECL(void, glEvalCoord2f, (GLfloat u, GLfloat v)) ANT_GL_DECL(void, glEvalCoord2fv, (const GLfloat *u)) ANT_GL_DECL(void, glEvalMesh1, (GLenum mode, GLint i1, GLint i2)) ANT_GL_DECL(void, glEvalMesh2, (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)) ANT_GL_DECL(void, glEvalPoint1, (GLint i)) ANT_GL_DECL(void, glEvalPoint2, (GLint i, GLint j)) ANT_GL_DECL(void, glFeedbackBuffer, (GLsizei size, GLenum type, GLfloat *buffer)) ANT_GL_DECL(void, glFinish, (void)) ANT_GL_DECL(void, glFlush, (void)) ANT_GL_DECL(void, glFogf, (GLenum pname, GLfloat param)) ANT_GL_DECL(void, glFogfv, (GLenum pname, const GLfloat *params)) ANT_GL_DECL(void, glFogi, (GLenum pname, GLint param)) ANT_GL_DECL(void, glFogiv, (GLenum pname, const GLint *params)) ANT_GL_DECL(void, glFrontFace, (GLenum mode)) ANT_GL_DECL(void, glFrustum, (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)) ANT_GL_DECL(GLuint, glGenLists, (GLsizei range)) ANT_GL_DECL(void, glGenTextures, (GLsizei n, GLuint *textures)) ANT_GL_DECL(void, glGetBooleanv, (GLenum pname, GLboolean *params)) ANT_GL_DECL(void, glGetClipPlane, (GLenum plane, GLdouble *equation)) ANT_GL_DECL(void, glGetDoublev, (GLenum pname, GLdouble *params)) ANT_GL_DECL(GLenum, glGetError, (void)) ANT_GL_DECL(void, glGetFloatv, (GLenum pname, GLfloat *params)) ANT_GL_DECL(void, glGetIntegerv, (GLenum pname, GLint *params)) ANT_GL_DECL(void, glGetLightfv, (GLenum light, GLenum pname, GLfloat *params)) ANT_GL_DECL(void, glGetLightiv, (GLenum light, GLenum pname, GLint *params)) ANT_GL_DECL(void, glGetMapdv, (GLenum target, GLenum query, GLdouble *v)) ANT_GL_DECL(void, glGetMapfv, (GLenum target, GLenum query, GLfloat *v)) ANT_GL_DECL(void, glGetMapiv, (GLenum target, GLenum query, GLint *v)) ANT_GL_DECL(void, glGetMaterialfv, (GLenum face, GLenum pname, GLfloat *params)) ANT_GL_DECL(void, glGetMaterialiv, (GLenum face, GLenum pname, GLint *params)) ANT_GL_DECL(void, glGetPixelMapfv, (GLenum map, GLfloat *values)) ANT_GL_DECL(void, glGetPixelMapuiv, (GLenum map, GLuint *values)) ANT_GL_DECL(void, glGetPixelMapusv, (GLenum map, GLushort *values)) ANT_GL_DECL(void, glGetPointerv, (GLenum pname, GLvoid* *params)) ANT_GL_DECL(void, glGetPolygonStipple, (GLubyte *mask)) ANT_GL_DECL(const GLubyte *, glGetString, (GLenum name)) ANT_GL_DECL(void, glGetTexEnvfv, (GLenum target, GLenum pname, GLfloat *params)) ANT_GL_DECL(void, glGetTexEnviv, (GLenum target, GLenum pname, GLint *params)) ANT_GL_DECL(void, glGetTexGendv, (GLenum coord, GLenum pname, GLdouble *params)) ANT_GL_DECL(void, glGetTexGenfv, (GLenum coord, GLenum pname, GLfloat *params)) ANT_GL_DECL(void, glGetTexGeniv, (GLenum coord, GLenum pname, GLint *params)) ANT_GL_DECL(void, glGetTexImage, (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels)) ANT_GL_DECL(void, glGetTexLevelParameterfv, (GLenum target, GLint level, GLenum pname, GLfloat *params)) ANT_GL_DECL(void, glGetTexLevelParameteriv, (GLenum target, GLint level, GLenum pname, GLint *params)) ANT_GL_DECL(void, glGetTexParameterfv, (GLenum target, GLenum pname, GLfloat *params)) ANT_GL_DECL(void, glGetTexParameteriv, (GLenum target, GLenum pname, GLint *params)) ANT_GL_DECL(void, glHint, (GLenum target, GLenum mode)) ANT_GL_DECL(void, glIndexMask, (GLuint mask)) ANT_GL_DECL(void, glIndexPointer, (GLenum type, GLsizei stride, const GLvoid *pointer)) ANT_GL_DECL(void, glIndexd, (GLdouble c)) ANT_GL_DECL(void, glIndexdv, (const GLdouble *c)) ANT_GL_DECL(void, glIndexf, (GLfloat c)) ANT_GL_DECL(void, glIndexfv, (const GLfloat *c)) ANT_GL_DECL(void, glIndexi, (GLint c)) ANT_GL_DECL(void, glIndexiv, (const GLint *c)) ANT_GL_DECL(void, glIndexs, (GLshort c)) ANT_GL_DECL(void, glIndexsv, (const GLshort *c)) ANT_GL_DECL(void, glIndexub, (GLubyte c)) ANT_GL_DECL(void, glIndexubv, (const GLubyte *c)) ANT_GL_DECL(void, glInitNames, (void)) ANT_GL_DECL(void, glInterleavedArrays, (GLenum format, GLsizei stride, const GLvoid *pointer)) ANT_GL_DECL(GLboolean, glIsEnabled, (GLenum cap)) ANT_GL_DECL(GLboolean, glIsList, (GLuint list)) ANT_GL_DECL(GLboolean, glIsTexture, (GLuint texture)) ANT_GL_DECL(void, glLightModelf, (GLenum pname, GLfloat param)) ANT_GL_DECL(void, glLightModelfv, (GLenum pname, const GLfloat *params)) ANT_GL_DECL(void, glLightModeli, (GLenum pname, GLint param)) ANT_GL_DECL(void, glLightModeliv, (GLenum pname, const GLint *params)) ANT_GL_DECL(void, glLightf, (GLenum light, GLenum pname, GLfloat param)) ANT_GL_DECL(void, glLightfv, (GLenum light, GLenum pname, const GLfloat *params)) ANT_GL_DECL(void, glLighti, (GLenum light, GLenum pname, GLint param)) ANT_GL_DECL(void, glLightiv, (GLenum light, GLenum pname, const GLint *params)) ANT_GL_DECL(void, glLineStipple, (GLint factor, GLushort pattern)) ANT_GL_DECL(void, glLineWidth, (GLfloat width)) ANT_GL_DECL(void, glListBase, (GLuint base)) ANT_GL_DECL(void, glLoadIdentity, (void)) ANT_GL_DECL(void, glLoadMatrixd, (const GLdouble *m)) ANT_GL_DECL(void, glLoadMatrixf, (const GLfloat *m)) ANT_GL_DECL(void, glLoadName, (GLuint name)) ANT_GL_DECL(void, glLogicOp, (GLenum opcode)) ANT_GL_DECL(void, glMap1d, (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points)) ANT_GL_DECL(void, glMap1f, (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points)) ANT_GL_DECL(void, glMap2d, (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points)) ANT_GL_DECL(void, glMap2f, (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points)) ANT_GL_DECL(void, glMapGrid1d, (GLint un, GLdouble u1, GLdouble u2)) ANT_GL_DECL(void, glMapGrid1f, (GLint un, GLfloat u1, GLfloat u2)) ANT_GL_DECL(void, glMapGrid2d, (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2)) ANT_GL_DECL(void, glMapGrid2f, (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2)) ANT_GL_DECL(void, glMaterialf, (GLenum face, GLenum pname, GLfloat param)) ANT_GL_DECL(void, glMaterialfv, (GLenum face, GLenum pname, const GLfloat *params)) ANT_GL_DECL(void, glMateriali, (GLenum face, GLenum pname, GLint param)) ANT_GL_DECL(void, glMaterialiv, (GLenum face, GLenum pname, const GLint *params)) ANT_GL_DECL(void, glMatrixMode, (GLenum mode)) ANT_GL_DECL(void, glMultMatrixd, (const GLdouble *m)) ANT_GL_DECL(void, glMultMatrixf, (const GLfloat *m)) ANT_GL_DECL(void, glNewList, (GLuint list, GLenum mode)) ANT_GL_DECL(void, glNormal3b, (GLbyte nx, GLbyte ny, GLbyte nz)) ANT_GL_DECL(void, glNormal3bv, (const GLbyte *v)) ANT_GL_DECL(void, glNormal3d, (GLdouble nx, GLdouble ny, GLdouble nz)) ANT_GL_DECL(void, glNormal3dv, (const GLdouble *v)) ANT_GL_DECL(void, glNormal3f, (GLfloat nx, GLfloat ny, GLfloat nz)) ANT_GL_DECL(void, glNormal3fv, (const GLfloat *v)) ANT_GL_DECL(void, glNormal3i, (GLint nx, GLint ny, GLint nz)) ANT_GL_DECL(void, glNormal3iv, (const GLint *v)) ANT_GL_DECL(void, glNormal3s, (GLshort nx, GLshort ny, GLshort nz)) ANT_GL_DECL(void, glNormal3sv, (const GLshort *v)) ANT_GL_DECL(void, glNormalPointer, (GLenum type, GLsizei stride, const GLvoid *pointer)) ANT_GL_DECL(void, glOrtho, (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar)) ANT_GL_DECL(void, glPassThrough, (GLfloat token)) ANT_GL_DECL(void, glPixelMapfv, (GLenum map, GLsizei mapsize, const GLfloat *values)) ANT_GL_DECL(void, glPixelMapuiv, (GLenum map, GLsizei mapsize, const GLuint *values)) ANT_GL_DECL(void, glPixelMapusv, (GLenum map, GLsizei mapsize, const GLushort *values)) ANT_GL_DECL(void, glPixelStoref, (GLenum pname, GLfloat param)) ANT_GL_DECL(void, glPixelStorei, (GLenum pname, GLint param)) ANT_GL_DECL(void, glPixelTransferf, (GLenum pname, GLfloat param)) ANT_GL_DECL(void, glPixelTransferi, (GLenum pname, GLint param)) ANT_GL_DECL(void, glPixelZoom, (GLfloat xfactor, GLfloat yfactor)) ANT_GL_DECL(void, glPointSize, (GLfloat size)) ANT_GL_DECL(void, glPolygonMode, (GLenum face, GLenum mode)) ANT_GL_DECL(void, glPolygonOffset, (GLfloat factor, GLfloat units)) ANT_GL_DECL(void, glPolygonStipple, (const GLubyte *mask)) ANT_GL_DECL(void, glPopAttrib, (void)) ANT_GL_DECL(void, glPopClientAttrib, (void)) ANT_GL_DECL(void, glPopMatrix, (void)) ANT_GL_DECL(void, glPopName, (void)) ANT_GL_DECL(void, glPrioritizeTextures, (GLsizei n, const GLuint *textures, const GLclampf *priorities)) ANT_GL_DECL(void, glPushAttrib, (GLbitfield mask)) ANT_GL_DECL(void, glPushClientAttrib, (GLbitfield mask)) ANT_GL_DECL(void, glPushMatrix, (void)) ANT_GL_DECL(void, glPushName, (GLuint name)) ANT_GL_DECL(void, glRasterPos2d, (GLdouble x, GLdouble y)) ANT_GL_DECL(void, glRasterPos2dv, (const GLdouble *v)) ANT_GL_DECL(void, glRasterPos2f, (GLfloat x, GLfloat y)) ANT_GL_DECL(void, glRasterPos2fv, (const GLfloat *v)) ANT_GL_DECL(void, glRasterPos2i, (GLint x, GLint y)) ANT_GL_DECL(void, glRasterPos2iv, (const GLint *v)) ANT_GL_DECL(void, glRasterPos2s, (GLshort x, GLshort y)) ANT_GL_DECL(void, glRasterPos2sv, (const GLshort *v)) ANT_GL_DECL(void, glRasterPos3d, (GLdouble x, GLdouble y, GLdouble z)) ANT_GL_DECL(void, glRasterPos3dv, (const GLdouble *v)) ANT_GL_DECL(void, glRasterPos3f, (GLfloat x, GLfloat y, GLfloat z)) ANT_GL_DECL(void, glRasterPos3fv, (const GLfloat *v)) ANT_GL_DECL(void, glRasterPos3i, (GLint x, GLint y, GLint z)) ANT_GL_DECL(void, glRasterPos3iv, (const GLint *v)) ANT_GL_DECL(void, glRasterPos3s, (GLshort x, GLshort y, GLshort z)) ANT_GL_DECL(void, glRasterPos3sv, (const GLshort *v)) ANT_GL_DECL(void, glRasterPos4d, (GLdouble x, GLdouble y, GLdouble z, GLdouble w)) ANT_GL_DECL(void, glRasterPos4dv, (const GLdouble *v)) ANT_GL_DECL(void, glRasterPos4f, (GLfloat x, GLfloat y, GLfloat z, GLfloat w)) ANT_GL_DECL(void, glRasterPos4fv, (const GLfloat *v)) ANT_GL_DECL(void, glRasterPos4i, (GLint x, GLint y, GLint z, GLint w)) ANT_GL_DECL(void, glRasterPos4iv, (const GLint *v)) ANT_GL_DECL(void, glRasterPos4s, (GLshort x, GLshort y, GLshort z, GLshort w)) ANT_GL_DECL(void, glRasterPos4sv, (const GLshort *v)) ANT_GL_DECL(void, glReadBuffer, (GLenum mode)) ANT_GL_DECL(void, glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)) ANT_GL_DECL(void, glRectd, (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)) ANT_GL_DECL(void, glRectdv, (const GLdouble *v1, const GLdouble *v2)) ANT_GL_DECL(void, glRectf, (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)) ANT_GL_DECL(void, glRectfv, (const GLfloat *v1, const GLfloat *v2)) ANT_GL_DECL(void, glRecti, (GLint x1, GLint y1, GLint x2, GLint y2)) ANT_GL_DECL(void, glRectiv, (const GLint *v1, const GLint *v2)) ANT_GL_DECL(void, glRects, (GLshort x1, GLshort y1, GLshort x2, GLshort y2)) ANT_GL_DECL(void, glRectsv, (const GLshort *v1, const GLshort *v2)) ANT_GL_DECL(GLint, glRenderMode, (GLenum mode)) ANT_GL_DECL(void, glRotated, (GLdouble angle, GLdouble x, GLdouble y, GLdouble z)) ANT_GL_DECL(void, glRotatef, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z)) ANT_GL_DECL(void, glScaled, (GLdouble x, GLdouble y, GLdouble z)) ANT_GL_DECL(void, glScalef, (GLfloat x, GLfloat y, GLfloat z)) ANT_GL_DECL(void, glScissor, (GLint x, GLint y, GLsizei width, GLsizei height)) ANT_GL_DECL(void, glSelectBuffer, (GLsizei size, GLuint *buffer)) ANT_GL_DECL(void, glShadeModel, (GLenum mode)) ANT_GL_DECL(void, glStencilFunc, (GLenum func, GLint ref, GLuint mask)) ANT_GL_DECL(void, glStencilMask, (GLuint mask)) ANT_GL_DECL(void, glStencilOp, (GLenum fail, GLenum zfail, GLenum zpass)) ANT_GL_DECL(void, glTexCoord1d, (GLdouble s)) ANT_GL_DECL(void, glTexCoord1dv, (const GLdouble *v)) ANT_GL_DECL(void, glTexCoord1f, (GLfloat s)) ANT_GL_DECL(void, glTexCoord1fv, (const GLfloat *v)) ANT_GL_DECL(void, glTexCoord1i, (GLint s)) ANT_GL_DECL(void, glTexCoord1iv, (const GLint *v)) ANT_GL_DECL(void, glTexCoord1s, (GLshort s)) ANT_GL_DECL(void, glTexCoord1sv, (const GLshort *v)) ANT_GL_DECL(void, glTexCoord2d, (GLdouble s, GLdouble t)) ANT_GL_DECL(void, glTexCoord2dv, (const GLdouble *v)) ANT_GL_DECL(void, glTexCoord2f, (GLfloat s, GLfloat t)) ANT_GL_DECL(void, glTexCoord2fv, (const GLfloat *v)) ANT_GL_DECL(void, glTexCoord2i, (GLint s, GLint t)) ANT_GL_DECL(void, glTexCoord2iv, (const GLint *v)) ANT_GL_DECL(void, glTexCoord2s, (GLshort s, GLshort t)) ANT_GL_DECL(void, glTexCoord2sv, (const GLshort *v)) ANT_GL_DECL(void, glTexCoord3d, (GLdouble s, GLdouble t, GLdouble r)) ANT_GL_DECL(void, glTexCoord3dv, (const GLdouble *v)) ANT_GL_DECL(void, glTexCoord3f, (GLfloat s, GLfloat t, GLfloat r)) ANT_GL_DECL(void, glTexCoord3fv, (const GLfloat *v)) ANT_GL_DECL(void, glTexCoord3i, (GLint s, GLint t, GLint r)) ANT_GL_DECL(void, glTexCoord3iv, (const GLint *v)) ANT_GL_DECL(void, glTexCoord3s, (GLshort s, GLshort t, GLshort r)) ANT_GL_DECL(void, glTexCoord3sv, (const GLshort *v)) ANT_GL_DECL(void, glTexCoord4d, (GLdouble s, GLdouble t, GLdouble r, GLdouble q)) ANT_GL_DECL(void, glTexCoord4dv, (const GLdouble *v)) ANT_GL_DECL(void, glTexCoord4f, (GLfloat s, GLfloat t, GLfloat r, GLfloat q)) ANT_GL_DECL(void, glTexCoord4fv, (const GLfloat *v)) ANT_GL_DECL(void, glTexCoord4i, (GLint s, GLint t, GLint r, GLint q)) ANT_GL_DECL(void, glTexCoord4iv, (const GLint *v)) ANT_GL_DECL(void, glTexCoord4s, (GLshort s, GLshort t, GLshort r, GLshort q)) ANT_GL_DECL(void, glTexCoord4sv, (const GLshort *v)) ANT_GL_DECL(void, glTexCoordPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) ANT_GL_DECL(void, glTexEnvf, (GLenum target, GLenum pname, GLfloat param)) ANT_GL_DECL(void, glTexEnvfv, (GLenum target, GLenum pname, const GLfloat *params)) ANT_GL_DECL(void, glTexEnvi, (GLenum target, GLenum pname, GLint param)) ANT_GL_DECL(void, glTexEnviv, (GLenum target, GLenum pname, const GLint *params)) ANT_GL_DECL(void, glTexGend, (GLenum coord, GLenum pname, GLdouble param)) ANT_GL_DECL(void, glTexGendv, (GLenum coord, GLenum pname, const GLdouble *params)) ANT_GL_DECL(void, glTexGenf, (GLenum coord, GLenum pname, GLfloat param)) ANT_GL_DECL(void, glTexGenfv, (GLenum coord, GLenum pname, const GLfloat *params)) ANT_GL_DECL(void, glTexGeni, (GLenum coord, GLenum pname, GLint param)) ANT_GL_DECL(void, glTexGeniv, (GLenum coord, GLenum pname, const GLint *params)) #if defined(ANT_OSX) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1070) // Mac OSX < 10.7 redefines these OpenGL calls: glTexImage1D, glTexImage2D ANT_GL_DECL(void, glTexImage1D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_DECL(void, glTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) #else ANT_GL_DECL(void, glTexImage1D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_DECL(void, glTexImage2D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) #endif ANT_GL_DECL(void, glTexParameterf, (GLenum target, GLenum pname, GLfloat param)) ANT_GL_DECL(void, glTexParameterfv, (GLenum target, GLenum pname, const GLfloat *params)) ANT_GL_DECL(void, glTexParameteri, (GLenum target, GLenum pname, GLint param)) ANT_GL_DECL(void, glTexParameteriv, (GLenum target, GLenum pname, const GLint *params)) ANT_GL_DECL(void, glTexSubImage1D, (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_DECL(void, glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_DECL(void, glTranslated, (GLdouble x, GLdouble y, GLdouble z)) ANT_GL_DECL(void, glTranslatef, (GLfloat x, GLfloat y, GLfloat z)) ANT_GL_DECL(void, glVertex2d, (GLdouble x, GLdouble y)) ANT_GL_DECL(void, glVertex2dv, (const GLdouble *v)) ANT_GL_DECL(void, glVertex2f, (GLfloat x, GLfloat y)) ANT_GL_DECL(void, glVertex2fv, (const GLfloat *v)) ANT_GL_DECL(void, glVertex2i, (GLint x, GLint y)) ANT_GL_DECL(void, glVertex2iv, (const GLint *v)) ANT_GL_DECL(void, glVertex2s, (GLshort x, GLshort y)) ANT_GL_DECL(void, glVertex2sv, (const GLshort *v)) ANT_GL_DECL(void, glVertex3d, (GLdouble x, GLdouble y, GLdouble z)) ANT_GL_DECL(void, glVertex3dv, (const GLdouble *v)) ANT_GL_DECL(void, glVertex3f, (GLfloat x, GLfloat y, GLfloat z)) ANT_GL_DECL(void, glVertex3fv, (const GLfloat *v)) ANT_GL_DECL(void, glVertex3i, (GLint x, GLint y, GLint z)) ANT_GL_DECL(void, glVertex3iv, (const GLint *v)) ANT_GL_DECL(void, glVertex3s, (GLshort x, GLshort y, GLshort z)) ANT_GL_DECL(void, glVertex3sv, (const GLshort *v)) ANT_GL_DECL(void, glVertex4d, (GLdouble x, GLdouble y, GLdouble z, GLdouble w)) ANT_GL_DECL(void, glVertex4dv, (const GLdouble *v)) ANT_GL_DECL(void, glVertex4f, (GLfloat x, GLfloat y, GLfloat z, GLfloat w)) ANT_GL_DECL(void, glVertex4fv, (const GLfloat *v)) ANT_GL_DECL(void, glVertex4i, (GLint x, GLint y, GLint z, GLint w)) ANT_GL_DECL(void, glVertex4iv, (const GLint *v)) ANT_GL_DECL(void, glVertex4s, (GLshort x, GLshort y, GLshort z, GLshort w)) ANT_GL_DECL(void, glVertex4sv, (const GLshort *v)) ANT_GL_DECL(void, glVertexPointer, (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) ANT_GL_DECL(void, glViewport, (GLint x, GLint y, GLsizei width, GLsizei height)) #ifdef ANT_WINDOWS ANT_GL_DECL(PROC, wglGetProcAddress, (LPCSTR)) #endif #endif // !defined ANT_LOAD_OGL_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/LoadOGLCore.cpp0000644000000000000000000003734312635011627025317 0ustar rootroot// --------------------------------------------------------------------------- // // @file LoadOGLCore.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "LoadOGLCore.h" // --------------------------------------------------------------------------- #define ANT_NB_OGL_CORE_FUNC_MAX 512 struct COGLCoreFuncRec { const char * m_Name; GLCore::PFNOpenGL * m_FuncPtr; COGLCoreFuncRec() : m_Name(NULL), m_FuncPtr(NULL) {} }; COGLCoreFuncRec g_OGLCoreFuncRec[ANT_NB_OGL_CORE_FUNC_MAX]; int g_NbOGLCoreFunc = 0; #if defined(ANT_WINDOWS) HMODULE g_OGLCoreModule = NULL; #endif // --------------------------------------------------------------------------- // GL 1.0 ANT_GL_CORE_IMPL(glCullFace) ANT_GL_CORE_IMPL(glFrontFace) ANT_GL_CORE_IMPL(glHint) ANT_GL_CORE_IMPL(glLineWidth) ANT_GL_CORE_IMPL(glPointSize) ANT_GL_CORE_IMPL(glPolygonMode) ANT_GL_CORE_IMPL(glScissor) ANT_GL_CORE_IMPL(glTexParameterf) ANT_GL_CORE_IMPL(glTexParameterfv) ANT_GL_CORE_IMPL(glTexParameteri) ANT_GL_CORE_IMPL(glTexParameteriv) ANT_GL_CORE_IMPL(glTexImage1D) ANT_GL_CORE_IMPL(glTexImage2D) ANT_GL_CORE_IMPL(glDrawBuffer) ANT_GL_CORE_IMPL(glClear) ANT_GL_CORE_IMPL(glClearColor) ANT_GL_CORE_IMPL(glClearStencil) ANT_GL_CORE_IMPL(glClearDepth) ANT_GL_CORE_IMPL(glStencilMask) ANT_GL_CORE_IMPL(glColorMask) ANT_GL_CORE_IMPL(glDepthMask) ANT_GL_CORE_IMPL(glDisable) ANT_GL_CORE_IMPL(glEnable) ANT_GL_CORE_IMPL(glFinish) ANT_GL_CORE_IMPL(glFlush) ANT_GL_CORE_IMPL(glBlendFunc) ANT_GL_CORE_IMPL(glLogicOp) ANT_GL_CORE_IMPL(glStencilFunc) ANT_GL_CORE_IMPL(glStencilOp) ANT_GL_CORE_IMPL(glDepthFunc) ANT_GL_CORE_IMPL(glPixelStoref) ANT_GL_CORE_IMPL(glPixelStorei) ANT_GL_CORE_IMPL(glReadBuffer) ANT_GL_CORE_IMPL(glReadPixels) ANT_GL_CORE_IMPL(glGetBooleanv) ANT_GL_CORE_IMPL(glGetDoublev) ANT_GL_CORE_IMPL(glGetError) ANT_GL_CORE_IMPL(glGetFloatv) ANT_GL_CORE_IMPL(glGetIntegerv) ANT_GL_CORE_IMPL(glGetString) ANT_GL_CORE_IMPL(glGetTexImage) ANT_GL_CORE_IMPL(glGetTexParameterfv) ANT_GL_CORE_IMPL(glGetTexParameteriv) ANT_GL_CORE_IMPL(glGetTexLevelParameterfv) ANT_GL_CORE_IMPL(glGetTexLevelParameteriv) ANT_GL_CORE_IMPL(glIsEnabled) ANT_GL_CORE_IMPL(glDepthRange) ANT_GL_CORE_IMPL(glViewport) // GL 1.1 ANT_GL_CORE_IMPL(glDrawArrays) ANT_GL_CORE_IMPL(glDrawElements) ANT_GL_CORE_IMPL(glGetPointerv) ANT_GL_CORE_IMPL(glPolygonOffset) ANT_GL_CORE_IMPL(glCopyTexImage1D) ANT_GL_CORE_IMPL(glCopyTexImage2D) ANT_GL_CORE_IMPL(glCopyTexSubImage1D) ANT_GL_CORE_IMPL(glCopyTexSubImage2D) ANT_GL_CORE_IMPL(glTexSubImage1D) ANT_GL_CORE_IMPL(glTexSubImage2D) ANT_GL_CORE_IMPL(glBindTexture) ANT_GL_CORE_IMPL(glDeleteTextures) ANT_GL_CORE_IMPL(glGenTextures) ANT_GL_CORE_IMPL(glIsTexture) // GL 1.2 ANT_GL_CORE_IMPL(glBlendColor) ANT_GL_CORE_IMPL(glBlendEquation) ANT_GL_CORE_IMPL(glDrawRangeElements) ANT_GL_CORE_IMPL(glTexImage3D) ANT_GL_CORE_IMPL(glTexSubImage3D) ANT_GL_CORE_IMPL(glCopyTexSubImage3D) // GL 1.3 ANT_GL_CORE_IMPL(glActiveTexture) ANT_GL_CORE_IMPL(glSampleCoverage) ANT_GL_CORE_IMPL(glCompressedTexImage3D) ANT_GL_CORE_IMPL(glCompressedTexImage2D) ANT_GL_CORE_IMPL(glCompressedTexImage1D) ANT_GL_CORE_IMPL(glCompressedTexSubImage3D) ANT_GL_CORE_IMPL(glCompressedTexSubImage2D) ANT_GL_CORE_IMPL(glCompressedTexSubImage1D) ANT_GL_CORE_IMPL(glGetCompressedTexImage) // GL 1.4 ANT_GL_CORE_IMPL(glBlendFuncSeparate) ANT_GL_CORE_IMPL(glMultiDrawArrays) ANT_GL_CORE_IMPL(glMultiDrawElements) ANT_GL_CORE_IMPL(glPointParameterf) ANT_GL_CORE_IMPL(glPointParameterfv) ANT_GL_CORE_IMPL(glPointParameteri) ANT_GL_CORE_IMPL(glPointParameteriv) // GL 1.5 ANT_GL_CORE_IMPL(glGenQueries) ANT_GL_CORE_IMPL(glDeleteQueries) ANT_GL_CORE_IMPL(glIsQuery) ANT_GL_CORE_IMPL(glBeginQuery) ANT_GL_CORE_IMPL(glEndQuery) ANT_GL_CORE_IMPL(glGetQueryiv) ANT_GL_CORE_IMPL(glGetQueryObjectiv) ANT_GL_CORE_IMPL(glGetQueryObjectuiv) ANT_GL_CORE_IMPL(glBindBuffer) ANT_GL_CORE_IMPL(glDeleteBuffers) ANT_GL_CORE_IMPL(glGenBuffers) ANT_GL_CORE_IMPL(glIsBuffer) ANT_GL_CORE_IMPL(glBufferData) ANT_GL_CORE_IMPL(glBufferSubData) ANT_GL_CORE_IMPL(glGetBufferSubData) ANT_GL_CORE_IMPL(glMapBuffer) ANT_GL_CORE_IMPL(glUnmapBuffer) ANT_GL_CORE_IMPL(glGetBufferParameteriv) ANT_GL_CORE_IMPL(glGetBufferPointerv) // GL 2.0 ANT_GL_CORE_IMPL(glBlendEquationSeparate) ANT_GL_CORE_IMPL(glDrawBuffers) ANT_GL_CORE_IMPL(glStencilOpSeparate) ANT_GL_CORE_IMPL(glStencilFuncSeparate) ANT_GL_CORE_IMPL(glStencilMaskSeparate) ANT_GL_CORE_IMPL(glAttachShader) ANT_GL_CORE_IMPL(glBindAttribLocation) ANT_GL_CORE_IMPL(glCompileShader) ANT_GL_CORE_IMPL(glCreateProgram) ANT_GL_CORE_IMPL(glCreateShader) ANT_GL_CORE_IMPL(glDeleteProgram) ANT_GL_CORE_IMPL(glDeleteShader) ANT_GL_CORE_IMPL(glDetachShader) ANT_GL_CORE_IMPL(glDisableVertexAttribArray) ANT_GL_CORE_IMPL(glEnableVertexAttribArray) ANT_GL_CORE_IMPL(glGetActiveAttrib) ANT_GL_CORE_IMPL(glGetActiveUniform) ANT_GL_CORE_IMPL(glGetAttachedShaders) ANT_GL_CORE_IMPL(glGetAttribLocation) ANT_GL_CORE_IMPL(glGetProgramiv) ANT_GL_CORE_IMPL(glGetProgramInfoLog) ANT_GL_CORE_IMPL(glGetShaderiv) ANT_GL_CORE_IMPL(glGetShaderInfoLog) ANT_GL_CORE_IMPL(glGetShaderSource) ANT_GL_CORE_IMPL(glGetUniformLocation) ANT_GL_CORE_IMPL(glGetUniformfv) ANT_GL_CORE_IMPL(glGetUniformiv) ANT_GL_CORE_IMPL(glGetVertexAttribdv) ANT_GL_CORE_IMPL(glGetVertexAttribfv) ANT_GL_CORE_IMPL(glGetVertexAttribiv) ANT_GL_CORE_IMPL(glGetVertexAttribPointerv) ANT_GL_CORE_IMPL(glIsProgram) ANT_GL_CORE_IMPL(glIsShader) ANT_GL_CORE_IMPL(glLinkProgram) ANT_GL_CORE_IMPL(glShaderSource) ANT_GL_CORE_IMPL(glUseProgram) ANT_GL_CORE_IMPL(glUniform1f) ANT_GL_CORE_IMPL(glUniform2f) ANT_GL_CORE_IMPL(glUniform3f) ANT_GL_CORE_IMPL(glUniform4f) ANT_GL_CORE_IMPL(glUniform1i) ANT_GL_CORE_IMPL(glUniform2i) ANT_GL_CORE_IMPL(glUniform3i) ANT_GL_CORE_IMPL(glUniform4i) ANT_GL_CORE_IMPL(glUniform1fv) ANT_GL_CORE_IMPL(glUniform2fv) ANT_GL_CORE_IMPL(glUniform3fv) ANT_GL_CORE_IMPL(glUniform4fv) ANT_GL_CORE_IMPL(glUniform1iv) ANT_GL_CORE_IMPL(glUniform2iv) ANT_GL_CORE_IMPL(glUniform3iv) ANT_GL_CORE_IMPL(glUniform4iv) ANT_GL_CORE_IMPL(glUniformMatrix2fv) ANT_GL_CORE_IMPL(glUniformMatrix3fv) ANT_GL_CORE_IMPL(glUniformMatrix4fv) ANT_GL_CORE_IMPL(glValidateProgram) ANT_GL_CORE_IMPL(glVertexAttrib1d) ANT_GL_CORE_IMPL(glVertexAttrib1dv) ANT_GL_CORE_IMPL(glVertexAttrib1f) ANT_GL_CORE_IMPL(glVertexAttrib1fv) ANT_GL_CORE_IMPL(glVertexAttrib1s) ANT_GL_CORE_IMPL(glVertexAttrib1sv) ANT_GL_CORE_IMPL(glVertexAttrib2d) ANT_GL_CORE_IMPL(glVertexAttrib2dv) ANT_GL_CORE_IMPL(glVertexAttrib2f) ANT_GL_CORE_IMPL(glVertexAttrib2fv) ANT_GL_CORE_IMPL(glVertexAttrib2s) ANT_GL_CORE_IMPL(glVertexAttrib2sv) ANT_GL_CORE_IMPL(glVertexAttrib3d) ANT_GL_CORE_IMPL(glVertexAttrib3dv) ANT_GL_CORE_IMPL(glVertexAttrib3f) ANT_GL_CORE_IMPL(glVertexAttrib3fv) ANT_GL_CORE_IMPL(glVertexAttrib3s) ANT_GL_CORE_IMPL(glVertexAttrib3sv) ANT_GL_CORE_IMPL(glVertexAttrib4Nbv) ANT_GL_CORE_IMPL(glVertexAttrib4Niv) ANT_GL_CORE_IMPL(glVertexAttrib4Nsv) ANT_GL_CORE_IMPL(glVertexAttrib4Nub) ANT_GL_CORE_IMPL(glVertexAttrib4Nubv) ANT_GL_CORE_IMPL(glVertexAttrib4Nuiv) ANT_GL_CORE_IMPL(glVertexAttrib4Nusv) ANT_GL_CORE_IMPL(glVertexAttrib4bv) ANT_GL_CORE_IMPL(glVertexAttrib4d) ANT_GL_CORE_IMPL(glVertexAttrib4dv) ANT_GL_CORE_IMPL(glVertexAttrib4f) ANT_GL_CORE_IMPL(glVertexAttrib4fv) ANT_GL_CORE_IMPL(glVertexAttrib4iv) ANT_GL_CORE_IMPL(glVertexAttrib4s) ANT_GL_CORE_IMPL(glVertexAttrib4sv) ANT_GL_CORE_IMPL(glVertexAttrib4ubv) ANT_GL_CORE_IMPL(glVertexAttrib4uiv) ANT_GL_CORE_IMPL(glVertexAttrib4usv) ANT_GL_CORE_IMPL(glVertexAttribPointer) // GL 2.1 ANT_GL_CORE_IMPL(glUniformMatrix2x3fv) ANT_GL_CORE_IMPL(glUniformMatrix3x2fv) ANT_GL_CORE_IMPL(glUniformMatrix2x4fv) ANT_GL_CORE_IMPL(glUniformMatrix4x2fv) ANT_GL_CORE_IMPL(glUniformMatrix3x4fv) ANT_GL_CORE_IMPL(glUniformMatrix4x3fv) // GL 3.0 ANT_GL_CORE_IMPL(glColorMaski) ANT_GL_CORE_IMPL(glGetBooleani_v) ANT_GL_CORE_IMPL(glGetIntegeri_v) ANT_GL_CORE_IMPL(glEnablei) ANT_GL_CORE_IMPL(glDisablei) ANT_GL_CORE_IMPL(glIsEnabledi) ANT_GL_CORE_IMPL(glBeginTransformFeedback) ANT_GL_CORE_IMPL(glEndTransformFeedback) ANT_GL_CORE_IMPL(glBindBufferRange) ANT_GL_CORE_IMPL(glBindBufferBase) ANT_GL_CORE_IMPL(glTransformFeedbackVaryings) ANT_GL_CORE_IMPL(glGetTransformFeedbackVarying) ANT_GL_CORE_IMPL(glClampColor) ANT_GL_CORE_IMPL(glBeginConditionalRender) ANT_GL_CORE_IMPL(glEndConditionalRender) ANT_GL_CORE_IMPL(glVertexAttribIPointer) ANT_GL_CORE_IMPL(glGetVertexAttribIiv) ANT_GL_CORE_IMPL(glGetVertexAttribIuiv) ANT_GL_CORE_IMPL(glVertexAttribI1i) ANT_GL_CORE_IMPL(glVertexAttribI2i) ANT_GL_CORE_IMPL(glVertexAttribI3i) ANT_GL_CORE_IMPL(glVertexAttribI4i) ANT_GL_CORE_IMPL(glVertexAttribI1ui) ANT_GL_CORE_IMPL(glVertexAttribI2ui) ANT_GL_CORE_IMPL(glVertexAttribI3ui) ANT_GL_CORE_IMPL(glVertexAttribI4ui) ANT_GL_CORE_IMPL(glVertexAttribI1iv) ANT_GL_CORE_IMPL(glVertexAttribI2iv) ANT_GL_CORE_IMPL(glVertexAttribI3iv) ANT_GL_CORE_IMPL(glVertexAttribI4iv) ANT_GL_CORE_IMPL(glVertexAttribI1uiv) ANT_GL_CORE_IMPL(glVertexAttribI2uiv) ANT_GL_CORE_IMPL(glVertexAttribI3uiv) ANT_GL_CORE_IMPL(glVertexAttribI4uiv) ANT_GL_CORE_IMPL(glVertexAttribI4bv) ANT_GL_CORE_IMPL(glVertexAttribI4sv) ANT_GL_CORE_IMPL(glVertexAttribI4ubv) ANT_GL_CORE_IMPL(glVertexAttribI4usv) ANT_GL_CORE_IMPL(glGetUniformuiv) ANT_GL_CORE_IMPL(glBindFragDataLocation) ANT_GL_CORE_IMPL(glGetFragDataLocation) ANT_GL_CORE_IMPL(glUniform1ui) ANT_GL_CORE_IMPL(glUniform2ui) ANT_GL_CORE_IMPL(glUniform3ui) ANT_GL_CORE_IMPL(glUniform4ui) ANT_GL_CORE_IMPL(glUniform1uiv) ANT_GL_CORE_IMPL(glUniform2uiv) ANT_GL_CORE_IMPL(glUniform3uiv) ANT_GL_CORE_IMPL(glUniform4uiv) ANT_GL_CORE_IMPL(glTexParameterIiv) ANT_GL_CORE_IMPL(glTexParameterIuiv) ANT_GL_CORE_IMPL(glGetTexParameterIiv) ANT_GL_CORE_IMPL(glGetTexParameterIuiv) ANT_GL_CORE_IMPL(glClearBufferiv) ANT_GL_CORE_IMPL(glClearBufferuiv) ANT_GL_CORE_IMPL(glClearBufferfv) ANT_GL_CORE_IMPL(glClearBufferfi) ANT_GL_CORE_IMPL(glGetStringi) // GL 3.1 ANT_GL_CORE_IMPL(glDrawArraysInstanced) ANT_GL_CORE_IMPL(glDrawElementsInstanced) ANT_GL_CORE_IMPL(glTexBuffer) ANT_GL_CORE_IMPL(glPrimitiveRestartIndex) // GL 3.2 //ANT_GL_CORE_IMPL(glGetInteger64i_v) //ANT_GL_CORE_IMPL(glGetBufferParameteri64v) ANT_GL_CORE_IMPL(glFramebufferTexture) // GL_ARB_vertex_array_object ANT_GL_CORE_IMPL(glBindVertexArray) ANT_GL_CORE_IMPL(glDeleteVertexArrays) ANT_GL_CORE_IMPL(glGenVertexArrays) ANT_GL_CORE_IMPL(glIsVertexArray) #if defined(ANT_WINDOWS) ANT_GL_CORE_IMPL(wglGetProcAddress) #endif namespace GLCore { PFNGLGetProcAddress _glGetProcAddress = NULL; } // --------------------------------------------------------------------------- #if defined(ANT_WINDOWS) // --------------------------------------------------------------------------- int LoadOpenGLCore() { if( g_OGLCoreModule!=NULL ) { return 1; // "OpenGL library already loaded" } g_OGLCoreModule = LoadLibrary("OPENGL32.DLL"); if( g_OGLCoreModule ) { // Info(VERB_LOW, "Load %d OpenGL Core functions", g_NbOGLCoreFunc); int Res = 1; // Use wglGetProcAddress to retreive Core functions _glGetProcAddress = reinterpret_cast(GetProcAddress(g_OGLCoreModule, "wglGetProcAddress")); if( _glGetProcAddress!=NULL ) for(int i=0; i0); // Try to get the function pointer with wglGetProcAddress *(g_OGLCoreFuncRec[i].m_FuncPtr) = reinterpret_cast(_glGetProcAddress(g_OGLCoreFuncRec[i].m_Name)); if( *(g_OGLCoreFuncRec[i].m_FuncPtr)==NULL ) { // Try to get the function pointer with GetProcAddress *(g_OGLCoreFuncRec[i].m_FuncPtr) = reinterpret_cast(GetProcAddress(g_OGLCoreModule, g_OGLCoreFuncRec[i].m_Name)); if( *(g_OGLCoreFuncRec[i].m_FuncPtr)==NULL ) { #ifdef _DEBUG fprintf(stderr, "AntTweakBar: Cannot load function %s\n", g_OGLCoreFuncRec[i].m_Name); #endif Res = 0; // Error("cannot find OpenGL Core function"); } } } return Res; } else { // InternDisplayLastErrorWIN("Cannot load opengl32 DLL", false); return 0; // cannot load DLL } } // --------------------------------------------------------------------------- int UnloadOpenGLCore() { if( g_OGLCoreModule==NULL ) { return 1; // "OpenGL library not loaded" } // Info(VERB_LOW, "Unload %d OpenGL Core functions", g_NbOGLCoreFunc); for(int i=0; i0); *(g_OGLCoreFuncRec[i].m_FuncPtr) = NULL; } if( FreeLibrary(g_OGLCoreModule) ) { // Info(VERB_LOW, "OpenGL library unloaded"); g_OGLCoreModule = NULL; return 1; } else { // InternDisplayLastErrorWIN("Cannot unload opengl32 DLL", false); return 0; // cannot unload opengl32.dll } } // --------------------------------------------------------------------------- namespace GLCore { PFNOpenGL Record(const char *_FuncName, PFNOpenGL *_FuncPtr) { if( g_NbOGLCoreFunc>=ANT_NB_OGL_CORE_FUNC_MAX ) { fprintf(stderr, "Too many OpenGL Core functions declared. Change ANT_NB_OGL_CORE_FUNC_MAX."); exit(-1); } g_OGLCoreFuncRec[g_NbOGLCoreFunc].m_Name = _FuncName; g_OGLCoreFuncRec[g_NbOGLCoreFunc].m_FuncPtr = _FuncPtr; ++g_NbOGLCoreFunc; return NULL; } } // namespace GL // --------------------------------------------------------------------------- #endif // defined(ANT_WINDOWS) // --------------------------------------------------------------------------- #if defined(ANT_UNIX) int LoadOpenGLCore() { _glGetProcAddress = reinterpret_cast(glXGetProcAddressARB); return 1; // "OpenGL library is statically linked" } int UnloadOpenGLCore() { return 1; // "OpenGL library is statically linked" } #elif defined(ANT_OSX) #include static void *gl_dyld = NULL; void *NSGLGetProcAddressNew(const GLubyte *name) { void *proc=NULL; if (gl_dyld == NULL) { gl_dyld = dlopen("OpenGL",RTLD_LAZY); } if (gl_dyld) { NSString *sym = [[NSString alloc] initWithFormat: @"_%s",name]; proc = dlsym(gl_dyld,[sym UTF8String]); [sym release]; } return proc; } int LoadOpenGLCore() { _glGetProcAddress = reinterpret_cast(NSGLGetProcAddressNew); return 1; } int UnloadOpenGLCore() { if (gl_dyld) { dlclose(gl_dyld); gl_dyld = NULL; } return 1; } #endif // defined(ANT_UNIX) // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/LoadOGLCore.h0000644000000000000000000006413212635011627024760 0ustar rootroot// --------------------------------------------------------------------------- // // @file LoadOGLCore.h // @brief OpenGL Core Profile declarations for dynamic loading // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_LOAD_OGL_CORE_INCLUDED #define ANT_LOAD_OGL_CORE_INCLUDED #define ANT_GL_CORE_DECL(_Ret, _Fct, _Params) \ extern "C" { typedef _Ret (APIENTRY* PFN##_Fct)_Params; } \ namespace GLCore { extern PFN##_Fct _##_Fct; } \ using GLCore::_##_Fct; #if defined(ANT_WINDOWS) # define ANT_GL_CORE_IMPL(_Fct) \ namespace GLCore { PFN##_Fct _##_Fct = (PFN##_Fct)Record(#_Fct, (PFNOpenGL*)(&_##_Fct)); } #elif defined(ANT_UNIX) || defined(ANT_OSX) # define ANT_GL_CORE_IMPL(_Fct) \ namespace GLCore { PFN##_Fct _##_Fct = _Fct; } # if !defined(APIENTRY) # define APIENTRY # endif #endif int LoadOpenGLCore(); int UnloadOpenGLCore(); namespace GLCore { extern "C" { typedef void (APIENTRY* PFNOpenGL)(); } PFNOpenGL Record(const char *_FuncName, PFNOpenGL *_FuncPtr); extern "C" { typedef PFNOpenGL (APIENTRY *PFNGLGetProcAddress)(const char *); } extern PFNGLGetProcAddress _glGetProcAddress; } using GLCore::_glGetProcAddress; // GL 1.0 ANT_GL_CORE_DECL(void, glCullFace, (GLenum mode)) ANT_GL_CORE_DECL(void, glFrontFace, (GLenum mode)) ANT_GL_CORE_DECL(void, glHint, (GLenum target, GLenum mode)) ANT_GL_CORE_DECL(void, glLineWidth, (GLfloat width)) ANT_GL_CORE_DECL(void, glPointSize, (GLfloat size)) ANT_GL_CORE_DECL(void, glPolygonMode, (GLenum face, GLenum mode)) ANT_GL_CORE_DECL(void, glScissor, (GLint x, GLint y, GLsizei width, GLsizei height)) ANT_GL_CORE_DECL(void, glTexParameterf, (GLenum target, GLenum pname, GLfloat param)) ANT_GL_CORE_DECL(void, glTexParameterfv, (GLenum target, GLenum pname, const GLfloat *params)) ANT_GL_CORE_DECL(void, glTexParameteri, (GLenum target, GLenum pname, GLint param)) ANT_GL_CORE_DECL(void, glTexParameteriv, (GLenum target, GLenum pname, const GLint *params)) #if defined(ANT_OSX) // Mac OSX redefined these OpenGL calls: glTexImage1D, glTexImage2D ANT_GL_CORE_DECL(void, glTexImage1D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_CORE_DECL(void, glTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) #else ANT_GL_CORE_DECL(void, glTexImage1D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_CORE_DECL(void, glTexImage2D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) #endif ANT_GL_CORE_DECL(void, glDrawBuffer, (GLenum mode)) ANT_GL_CORE_DECL(void, glClear, (GLbitfield mask)) ANT_GL_CORE_DECL(void, glClearColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) ANT_GL_CORE_DECL(void, glClearStencil, (GLint s)) ANT_GL_CORE_DECL(void, glClearDepth, (GLclampd depth)) ANT_GL_CORE_DECL(void, glStencilMask, (GLuint mask)) ANT_GL_CORE_DECL(void, glColorMask, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) ANT_GL_CORE_DECL(void, glDepthMask, (GLboolean flag)) ANT_GL_CORE_DECL(void, glDisable, (GLenum cap)) ANT_GL_CORE_DECL(void, glEnable, (GLenum cap)) ANT_GL_CORE_DECL(void, glFinish, (void)) ANT_GL_CORE_DECL(void, glFlush, (void)) ANT_GL_CORE_DECL(void, glBlendFunc, (GLenum sfactor, GLenum dfactor)) ANT_GL_CORE_DECL(void, glLogicOp, (GLenum opcode)) ANT_GL_CORE_DECL(void, glStencilFunc, (GLenum func, GLint ref, GLuint mask)) ANT_GL_CORE_DECL(void, glStencilOp, (GLenum fail, GLenum zfail, GLenum zpass)) ANT_GL_CORE_DECL(void, glDepthFunc, (GLenum func)) ANT_GL_CORE_DECL(void, glPixelStoref, (GLenum pname, GLfloat param)) ANT_GL_CORE_DECL(void, glPixelStorei, (GLenum pname, GLint param)) ANT_GL_CORE_DECL(void, glReadBuffer, (GLenum mode)) ANT_GL_CORE_DECL(void, glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)) ANT_GL_CORE_DECL(void, glGetBooleanv, (GLenum pname, GLboolean *params)) ANT_GL_CORE_DECL(void, glGetDoublev, (GLenum pname, GLdouble *params)) ANT_GL_CORE_DECL(GLenum, glGetError, (void)) ANT_GL_CORE_DECL(void, glGetFloatv, (GLenum pname, GLfloat *params)) ANT_GL_CORE_DECL(void, glGetIntegerv, (GLenum pname, GLint *params)) ANT_GL_CORE_DECL(const GLubyte *, glGetString, (GLenum name)) ANT_GL_CORE_DECL(void, glGetTexImage, (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels)) ANT_GL_CORE_DECL(void, glGetTexParameterfv, (GLenum target, GLenum pname, GLfloat *params)) ANT_GL_CORE_DECL(void, glGetTexParameteriv, (GLenum target, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetTexLevelParameterfv, (GLenum target, GLint level, GLenum pname, GLfloat *params)) ANT_GL_CORE_DECL(void, glGetTexLevelParameteriv, (GLenum target, GLint level, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(GLboolean, glIsEnabled, (GLenum cap)) ANT_GL_CORE_DECL(void, glDepthRange, (GLclampd near, GLclampd far)) ANT_GL_CORE_DECL(void, glViewport, (GLint x, GLint y, GLsizei width, GLsizei height)) // GL 1.1 ANT_GL_CORE_DECL(void, glDrawArrays, (GLenum mode, GLint first, GLsizei count)) ANT_GL_CORE_DECL(void, glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)) ANT_GL_CORE_DECL(void, glGetPointerv, (GLenum pname, GLvoid* *params)) ANT_GL_CORE_DECL(void, glPolygonOffset, (GLfloat factor, GLfloat units)) ANT_GL_CORE_DECL(void, glCopyTexImage1D, (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border)) ANT_GL_CORE_DECL(void, glCopyTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)) ANT_GL_CORE_DECL(void, glCopyTexSubImage1D, (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)) ANT_GL_CORE_DECL(void, glCopyTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)) ANT_GL_CORE_DECL(void, glTexSubImage1D, (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_CORE_DECL(void, glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_CORE_DECL(void, glBindTexture, (GLenum target, GLuint texture)) ANT_GL_CORE_DECL(void, glDeleteTextures, (GLsizei n, const GLuint *textures)) ANT_GL_CORE_DECL(void, glGenTextures, (GLsizei n, GLuint *textures)) ANT_GL_CORE_DECL(GLboolean, glIsTexture, (GLuint texture)) // GL 1.2 ANT_GL_CORE_DECL(void, glBlendColor, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) ANT_GL_CORE_DECL(void, glBlendEquation, (GLenum mode)) ANT_GL_CORE_DECL(void, glDrawRangeElements, (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices)) ANT_GL_CORE_DECL(void, glTexImage3D, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_CORE_DECL(void, glTexSubImage3D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels)) ANT_GL_CORE_DECL(void, glCopyTexSubImage3D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)) // GL 1.3 ANT_GL_CORE_DECL(void, glActiveTexture, (GLenum texture)) ANT_GL_CORE_DECL(void, glSampleCoverage, (GLclampf value, GLboolean invert)) ANT_GL_CORE_DECL(void, glCompressedTexImage3D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data)) ANT_GL_CORE_DECL(void, glCompressedTexImage2D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)) ANT_GL_CORE_DECL(void, glCompressedTexImage1D, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data)) ANT_GL_CORE_DECL(void, glCompressedTexSubImage3D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data)) ANT_GL_CORE_DECL(void, glCompressedTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)) ANT_GL_CORE_DECL(void, glCompressedTexSubImage1D, (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data)) ANT_GL_CORE_DECL(void, glGetCompressedTexImage, (GLenum target, GLint level, GLvoid *img)) // GL 1.4 ANT_GL_CORE_DECL(void, glBlendFuncSeparate, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) ANT_GL_CORE_DECL(void, glMultiDrawArrays, (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount)) ANT_GL_CORE_DECL(void, glMultiDrawElements, (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount)) ANT_GL_CORE_DECL(void, glPointParameterf, (GLenum pname, GLfloat param)) ANT_GL_CORE_DECL(void, glPointParameterfv, (GLenum pname, const GLfloat *params)) ANT_GL_CORE_DECL(void, glPointParameteri, (GLenum pname, GLint param)) ANT_GL_CORE_DECL(void, glPointParameteriv, (GLenum pname, const GLint *params)) // GL 1.5 typedef ptrdiff_t GLintptr; typedef ptrdiff_t GLsizeiptr; ANT_GL_CORE_DECL(void, glGenQueries, (GLsizei n, GLuint *ids)) ANT_GL_CORE_DECL(void, glDeleteQueries, (GLsizei n, const GLuint *ids)) ANT_GL_CORE_DECL(GLboolean, glIsQuery, (GLuint id)) ANT_GL_CORE_DECL(void, glBeginQuery, (GLenum target, GLuint id)) ANT_GL_CORE_DECL(void, glEndQuery, (GLenum target)) ANT_GL_CORE_DECL(void, glGetQueryiv, (GLenum target, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetQueryObjectiv, (GLuint id, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetQueryObjectuiv, (GLuint id, GLenum pname, GLuint *params)) ANT_GL_CORE_DECL(void, glBindBuffer, (GLenum target, GLuint buffer)) ANT_GL_CORE_DECL(void, glDeleteBuffers, (GLsizei n, const GLuint *buffers)) ANT_GL_CORE_DECL(void, glGenBuffers, (GLsizei n, GLuint *buffers)) ANT_GL_CORE_DECL(GLboolean, glIsBuffer, (GLuint buffer)) ANT_GL_CORE_DECL(void, glBufferData, (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)) ANT_GL_CORE_DECL(void, glBufferSubData, (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)) ANT_GL_CORE_DECL(void, glGetBufferSubData, (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data)) ANT_GL_CORE_DECL(GLvoid*, glMapBuffer, (GLenum target, GLenum access)) ANT_GL_CORE_DECL(GLboolean, glUnmapBuffer, (GLenum target)) ANT_GL_CORE_DECL(void, glGetBufferParameteriv, (GLenum target, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetBufferPointerv, (GLenum target, GLenum pname, GLvoid* *params)) // GL 2.0 typedef char GLchar; ANT_GL_CORE_DECL(void, glBlendEquationSeparate, (GLenum modeRGB, GLenum modeAlpha)) ANT_GL_CORE_DECL(void, glDrawBuffers, (GLsizei n, const GLenum *bufs)) ANT_GL_CORE_DECL(void, glStencilOpSeparate, (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)) ANT_GL_CORE_DECL(void, glStencilFuncSeparate, (GLenum face, GLenum func, GLint ref, GLuint mask)) ANT_GL_CORE_DECL(void, glStencilMaskSeparate, (GLenum face, GLuint mask)) ANT_GL_CORE_DECL(void, glAttachShader, (GLuint program, GLuint shader)) ANT_GL_CORE_DECL(void, glBindAttribLocation, (GLuint program, GLuint index, const GLchar *name)) ANT_GL_CORE_DECL(void, glCompileShader, (GLuint shader)) ANT_GL_CORE_DECL(GLuint, glCreateProgram, (void)) ANT_GL_CORE_DECL(GLuint, glCreateShader, (GLenum type)) ANT_GL_CORE_DECL(void, glDeleteProgram, (GLuint program)) ANT_GL_CORE_DECL(void, glDeleteShader, (GLuint shader)) ANT_GL_CORE_DECL(void, glDetachShader, (GLuint program, GLuint shader)) ANT_GL_CORE_DECL(void, glDisableVertexAttribArray, (GLuint index)) ANT_GL_CORE_DECL(void, glEnableVertexAttribArray, (GLuint index)) ANT_GL_CORE_DECL(void, glGetActiveAttrib, (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)) ANT_GL_CORE_DECL(void, glGetActiveUniform, (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)) ANT_GL_CORE_DECL(void, glGetAttachedShaders, (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj)) ANT_GL_CORE_DECL(GLint, glGetAttribLocation, (GLuint program, const GLchar *name)) ANT_GL_CORE_DECL(void, glGetProgramiv, (GLuint program, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetProgramInfoLog, (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog)) ANT_GL_CORE_DECL(void, glGetShaderiv, (GLuint shader, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetShaderInfoLog, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)) ANT_GL_CORE_DECL(void, glGetShaderSource, (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source)) ANT_GL_CORE_DECL(GLint, glGetUniformLocation, (GLuint program, const GLchar *name)) ANT_GL_CORE_DECL(void, glGetUniformfv, (GLuint program, GLint location, GLfloat *params)) ANT_GL_CORE_DECL(void, glGetUniformiv, (GLuint program, GLint location, GLint *params)) ANT_GL_CORE_DECL(void, glGetVertexAttribdv, (GLuint index, GLenum pname, GLdouble *params)) ANT_GL_CORE_DECL(void, glGetVertexAttribfv, (GLuint index, GLenum pname, GLfloat *params)) ANT_GL_CORE_DECL(void, glGetVertexAttribiv, (GLuint index, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetVertexAttribPointerv, (GLuint index, GLenum pname, GLvoid* *pointer)) ANT_GL_CORE_DECL(GLboolean, glIsProgram, (GLuint program)) ANT_GL_CORE_DECL(GLboolean, glIsShader, (GLuint shader)) ANT_GL_CORE_DECL(void, glLinkProgram, (GLuint program)) ANT_GL_CORE_DECL(void, glShaderSource, (GLuint shader, GLsizei count, const GLchar* *string, const GLint *length)) ANT_GL_CORE_DECL(void, glUseProgram, (GLuint program)) ANT_GL_CORE_DECL(void, glUniform1f, (GLint location, GLfloat v0)) ANT_GL_CORE_DECL(void, glUniform2f, (GLint location, GLfloat v0, GLfloat v1)) ANT_GL_CORE_DECL(void, glUniform3f, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)) ANT_GL_CORE_DECL(void, glUniform4f, (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)) ANT_GL_CORE_DECL(void, glUniform1i, (GLint location, GLint v0)) ANT_GL_CORE_DECL(void, glUniform2i, (GLint location, GLint v0, GLint v1)) ANT_GL_CORE_DECL(void, glUniform3i, (GLint location, GLint v0, GLint v1, GLint v2)) ANT_GL_CORE_DECL(void, glUniform4i, (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)) ANT_GL_CORE_DECL(void, glUniform1fv, (GLint location, GLsizei count, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniform2fv, (GLint location, GLsizei count, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniform3fv, (GLint location, GLsizei count, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniform4fv, (GLint location, GLsizei count, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniform1iv, (GLint location, GLsizei count, const GLint *value)) ANT_GL_CORE_DECL(void, glUniform2iv, (GLint location, GLsizei count, const GLint *value)) ANT_GL_CORE_DECL(void, glUniform3iv, (GLint location, GLsizei count, const GLint *value)) ANT_GL_CORE_DECL(void, glUniform4iv, (GLint location, GLsizei count, const GLint *value)) ANT_GL_CORE_DECL(void, glUniformMatrix2fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniformMatrix3fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniformMatrix4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glValidateProgram, (GLuint program)) ANT_GL_CORE_DECL(void, glVertexAttrib1d, (GLuint index, GLdouble x)) ANT_GL_CORE_DECL(void, glVertexAttrib1dv, (GLuint index, const GLdouble *v)) ANT_GL_CORE_DECL(void, glVertexAttrib1f, (GLuint index, GLfloat x)) ANT_GL_CORE_DECL(void, glVertexAttrib1fv, (GLuint index, const GLfloat *v)) ANT_GL_CORE_DECL(void, glVertexAttrib1s, (GLuint index, GLshort x)) ANT_GL_CORE_DECL(void, glVertexAttrib1sv, (GLuint index, const GLshort *v)) ANT_GL_CORE_DECL(void, glVertexAttrib2d, (GLuint index, GLdouble x, GLdouble y)) ANT_GL_CORE_DECL(void, glVertexAttrib2dv, (GLuint index, const GLdouble *v)) ANT_GL_CORE_DECL(void, glVertexAttrib2f, (GLuint index, GLfloat x, GLfloat y)) ANT_GL_CORE_DECL(void, glVertexAttrib2fv, (GLuint index, const GLfloat *v)) ANT_GL_CORE_DECL(void, glVertexAttrib2s, (GLuint index, GLshort x, GLshort y)) ANT_GL_CORE_DECL(void, glVertexAttrib2sv, (GLuint index, const GLshort *v)) ANT_GL_CORE_DECL(void, glVertexAttrib3d, (GLuint index, GLdouble x, GLdouble y, GLdouble z)) ANT_GL_CORE_DECL(void, glVertexAttrib3dv, (GLuint index, const GLdouble *v)) ANT_GL_CORE_DECL(void, glVertexAttrib3f, (GLuint index, GLfloat x, GLfloat y, GLfloat z)) ANT_GL_CORE_DECL(void, glVertexAttrib3fv, (GLuint index, const GLfloat *v)) ANT_GL_CORE_DECL(void, glVertexAttrib3s, (GLuint index, GLshort x, GLshort y, GLshort z)) ANT_GL_CORE_DECL(void, glVertexAttrib3sv, (GLuint index, const GLshort *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4Nbv, (GLuint index, const GLbyte *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4Niv, (GLuint index, const GLint *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4Nsv, (GLuint index, const GLshort *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4Nub, (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w)) ANT_GL_CORE_DECL(void, glVertexAttrib4Nubv, (GLuint index, const GLubyte *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4Nuiv, (GLuint index, const GLuint *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4Nusv, (GLuint index, const GLushort *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4bv, (GLuint index, const GLbyte *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4d, (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w)) ANT_GL_CORE_DECL(void, glVertexAttrib4dv, (GLuint index, const GLdouble *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4f, (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)) ANT_GL_CORE_DECL(void, glVertexAttrib4fv, (GLuint index, const GLfloat *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4iv, (GLuint index, const GLint *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4s, (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w)) ANT_GL_CORE_DECL(void, glVertexAttrib4sv, (GLuint index, const GLshort *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4ubv, (GLuint index, const GLubyte *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4uiv, (GLuint index, const GLuint *v)) ANT_GL_CORE_DECL(void, glVertexAttrib4usv, (GLuint index, const GLushort *v)) ANT_GL_CORE_DECL(void, glVertexAttribPointer, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer)) // GL 2.1 ANT_GL_CORE_DECL(void, glUniformMatrix2x3fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniformMatrix3x2fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniformMatrix2x4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniformMatrix4x2fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniformMatrix3x4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) ANT_GL_CORE_DECL(void, glUniformMatrix4x3fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)) // GL 3.0 ANT_GL_CORE_DECL(void, glColorMaski, (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a)) ANT_GL_CORE_DECL(void, glGetBooleani_v, (GLenum target, GLuint index, GLboolean *data)) ANT_GL_CORE_DECL(void, glGetIntegeri_v, (GLenum target, GLuint index, GLint *data)) ANT_GL_CORE_DECL(void, glEnablei, (GLenum target, GLuint index)) ANT_GL_CORE_DECL(void, glDisablei, (GLenum target, GLuint index)) ANT_GL_CORE_DECL(GLboolean, glIsEnabledi, (GLenum target, GLuint index)) ANT_GL_CORE_DECL(void, glBeginTransformFeedback, (GLenum primitiveMode)) ANT_GL_CORE_DECL(void, glEndTransformFeedback, (void)) ANT_GL_CORE_DECL(void, glBindBufferRange, (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)) ANT_GL_CORE_DECL(void, glBindBufferBase, (GLenum target, GLuint index, GLuint buffer)) ANT_GL_CORE_DECL(void, glTransformFeedbackVaryings, (GLuint program, GLsizei count, const GLchar* *varyings, GLenum bufferMode)) ANT_GL_CORE_DECL(void, glGetTransformFeedbackVarying, (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)) ANT_GL_CORE_DECL(void, glClampColor, (GLenum target, GLenum clamp)) ANT_GL_CORE_DECL(void, glBeginConditionalRender, (GLuint id, GLenum mode)) ANT_GL_CORE_DECL(void, glEndConditionalRender, (void)) ANT_GL_CORE_DECL(void, glVertexAttribIPointer, (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)) ANT_GL_CORE_DECL(void, glGetVertexAttribIiv, (GLuint index, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetVertexAttribIuiv, (GLuint index, GLenum pname, GLuint *params)) ANT_GL_CORE_DECL(void, glVertexAttribI1i, (GLuint index, GLint x)) ANT_GL_CORE_DECL(void, glVertexAttribI2i, (GLuint index, GLint x, GLint y)) ANT_GL_CORE_DECL(void, glVertexAttribI3i, (GLuint index, GLint x, GLint y, GLint z)) ANT_GL_CORE_DECL(void, glVertexAttribI4i, (GLuint index, GLint x, GLint y, GLint z, GLint w)) ANT_GL_CORE_DECL(void, glVertexAttribI1ui, (GLuint index, GLuint x)) ANT_GL_CORE_DECL(void, glVertexAttribI2ui, (GLuint index, GLuint x, GLuint y)) ANT_GL_CORE_DECL(void, glVertexAttribI3ui, (GLuint index, GLuint x, GLuint y, GLuint z)) ANT_GL_CORE_DECL(void, glVertexAttribI4ui, (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)) ANT_GL_CORE_DECL(void, glVertexAttribI1iv, (GLuint index, const GLint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI2iv, (GLuint index, const GLint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI3iv, (GLuint index, const GLint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI4iv, (GLuint index, const GLint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI1uiv, (GLuint index, const GLuint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI2uiv, (GLuint index, const GLuint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI3uiv, (GLuint index, const GLuint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI4uiv, (GLuint index, const GLuint *v)) ANT_GL_CORE_DECL(void, glVertexAttribI4bv, (GLuint index, const GLbyte *v)) ANT_GL_CORE_DECL(void, glVertexAttribI4sv, (GLuint index, const GLshort *v)) ANT_GL_CORE_DECL(void, glVertexAttribI4ubv, (GLuint index, const GLubyte *v)) ANT_GL_CORE_DECL(void, glVertexAttribI4usv, (GLuint index, const GLushort *v)) ANT_GL_CORE_DECL(void, glGetUniformuiv, (GLuint program, GLint location, GLuint *params)) ANT_GL_CORE_DECL(void, glBindFragDataLocation, (GLuint program, GLuint color, const GLchar *name)) ANT_GL_CORE_DECL(GLint, glGetFragDataLocation, (GLuint program, const GLchar *name)) ANT_GL_CORE_DECL(void, glUniform1ui, (GLint location, GLuint v0)) ANT_GL_CORE_DECL(void, glUniform2ui, (GLint location, GLuint v0, GLuint v1)) ANT_GL_CORE_DECL(void, glUniform3ui, (GLint location, GLuint v0, GLuint v1, GLuint v2)) ANT_GL_CORE_DECL(void, glUniform4ui, (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)) ANT_GL_CORE_DECL(void, glUniform1uiv, (GLint location, GLsizei count, const GLuint *value)) ANT_GL_CORE_DECL(void, glUniform2uiv, (GLint location, GLsizei count, const GLuint *value)) ANT_GL_CORE_DECL(void, glUniform3uiv, (GLint location, GLsizei count, const GLuint *value)) ANT_GL_CORE_DECL(void, glUniform4uiv, (GLint location, GLsizei count, const GLuint *value)) ANT_GL_CORE_DECL(void, glTexParameterIiv, (GLenum target, GLenum pname, const GLint *params)) ANT_GL_CORE_DECL(void, glTexParameterIuiv, (GLenum target, GLenum pname, const GLuint *params)) ANT_GL_CORE_DECL(void, glGetTexParameterIiv, (GLenum target, GLenum pname, GLint *params)) ANT_GL_CORE_DECL(void, glGetTexParameterIuiv, (GLenum target, GLenum pname, GLuint *params)) ANT_GL_CORE_DECL(void, glClearBufferiv, (GLenum buffer, GLint drawbuffer, const GLint *value)) ANT_GL_CORE_DECL(void, glClearBufferuiv, (GLenum buffer, GLint drawbuffer, const GLuint *value)) ANT_GL_CORE_DECL(void, glClearBufferfv, (GLenum buffer, GLint drawbuffer, const GLfloat *value)) ANT_GL_CORE_DECL(void, glClearBufferfi, (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)) ANT_GL_CORE_DECL(const GLubyte *, glGetStringi, (GLenum name, GLuint index)) // GL 3.1 ANT_GL_CORE_DECL(void, glDrawArraysInstanced, (GLenum mode, GLint first, GLsizei count, GLsizei primcount)) ANT_GL_CORE_DECL(void, glDrawElementsInstanced, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount)) ANT_GL_CORE_DECL(void, glTexBuffer, (GLenum target, GLenum internalformat, GLuint buffer)) ANT_GL_CORE_DECL(void, glPrimitiveRestartIndex, (GLuint index)) // GL 3.2 //typedef int64_t GLint64; //ANT_GL_CORE_DECL(void, glGetInteger64i_v, (GLenum target, GLuint index, GLint64 *data)) //ANT_GL_CORE_DECL(void, glGetBufferParameteri64v, (GLenum target, GLenum pname, GLint64 *params)) ANT_GL_CORE_DECL(void, glFramebufferTexture, (GLenum target, GLenum attachment, GLuint texture, GLint level)) // GL_ARB_vertex_array_object ANT_GL_CORE_DECL(void, glBindVertexArray, (GLuint array)) ANT_GL_CORE_DECL(void, glDeleteVertexArrays, (GLsizei n, const GLuint *arrays)) ANT_GL_CORE_DECL(void, glGenVertexArrays, (GLsizei n, GLuint *arrays)) ANT_GL_CORE_DECL(GLboolean, glIsVertexArray, (GLuint array)) #ifdef ANT_WINDOWS ANT_GL_CORE_DECL(PROC, wglGetProcAddress, (LPCSTR)) #endif #endif // !defined ANT_LOAD_OGL_CORE_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/Makefile.am0000644000000000000000000000224612635011627024607 0ustar rootrootnoinst_LTLIBRARIES = libAntTweakBar.la AM_CPPFLAGS = -I${top_srcdir}/include $(OPENGL_FLAGS) AM_LDFLAGS = $(OPENGL_LIBS) libAntTweakBar_la_SOURCES = AntPerfTimer.h \ LoadOGL.cpp \ LoadOGL.h \ MiniGLFW.h \ MiniGLUT.h \ MiniSDL12.h \ MiniSDL13.h \ MiniSFML16.h \ resource.h \ TwBar.cpp \ TwBar.h \ TwColors.cpp \ TwColors.h \ TwEventGLFW.c \ TwEventGLUT.c \ TwEventSDL.c \ TwEventSDL12.c \ TwEventSDL13.c \ TwEventSFML.cpp \ TwFonts.cpp \ TwFonts.h \ TwGraph.h \ TwMgr.cpp \ TwMgr.h \ TwOpenGL.cpp \ TwOpenGL.h \ TwPrecomp.cpp \ TwPrecomp.h ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/MiniGLFW.h0000644000000000000000000001076312635011627024303 0ustar rootroot// --------------------------------------------------------------------------- // // @file MiniGLFW.h // @brief A subset of GLFW definitions needed to compile helper functions // implemented in TwEventGLFW.c // // notes: - Private header // - AntTweakBar.dll does not need to link with GLFW, // it just needs some definitions for its helper functions. // - This header is provided to avoid the need of having GLFW // installed to recompile AntTweakBar. // - Do not use this header in your own programs, better use the // glfw.h header from the actual GLFW library SDK : // http://glfw.sourceforge.net/ // // --------------------------------------------------------------------------- #if !defined MINI_GLFW_INCLUDED #define MINI_GLFW_INCLUDED #ifdef __cplusplus extern "C" { #endif // Key and button state/action definitions #define GLFW_RELEASE 0 #define GLFW_PRESS 1 // Keyboard key definitions #define GLFW_KEY_UNKNOWN -1 #define GLFW_KEY_SPACE 32 #define GLFW_KEY_SPECIAL 256 #define GLFW_KEY_ESC (GLFW_KEY_SPECIAL+1) #define GLFW_KEY_F1 (GLFW_KEY_SPECIAL+2) #define GLFW_KEY_F2 (GLFW_KEY_SPECIAL+3) #define GLFW_KEY_F3 (GLFW_KEY_SPECIAL+4) #define GLFW_KEY_F4 (GLFW_KEY_SPECIAL+5) #define GLFW_KEY_F5 (GLFW_KEY_SPECIAL+6) #define GLFW_KEY_F6 (GLFW_KEY_SPECIAL+7) #define GLFW_KEY_F7 (GLFW_KEY_SPECIAL+8) #define GLFW_KEY_F8 (GLFW_KEY_SPECIAL+9) #define GLFW_KEY_F9 (GLFW_KEY_SPECIAL+10) #define GLFW_KEY_F10 (GLFW_KEY_SPECIAL+11) #define GLFW_KEY_F11 (GLFW_KEY_SPECIAL+12) #define GLFW_KEY_F12 (GLFW_KEY_SPECIAL+13) #define GLFW_KEY_F13 (GLFW_KEY_SPECIAL+14) #define GLFW_KEY_F14 (GLFW_KEY_SPECIAL+15) #define GLFW_KEY_F15 (GLFW_KEY_SPECIAL+16) #define GLFW_KEY_F16 (GLFW_KEY_SPECIAL+17) #define GLFW_KEY_F17 (GLFW_KEY_SPECIAL+18) #define GLFW_KEY_F18 (GLFW_KEY_SPECIAL+19) #define GLFW_KEY_F19 (GLFW_KEY_SPECIAL+20) #define GLFW_KEY_F20 (GLFW_KEY_SPECIAL+21) #define GLFW_KEY_F21 (GLFW_KEY_SPECIAL+22) #define GLFW_KEY_F22 (GLFW_KEY_SPECIAL+23) #define GLFW_KEY_F23 (GLFW_KEY_SPECIAL+24) #define GLFW_KEY_F24 (GLFW_KEY_SPECIAL+25) #define GLFW_KEY_F25 (GLFW_KEY_SPECIAL+26) #define GLFW_KEY_UP (GLFW_KEY_SPECIAL+27) #define GLFW_KEY_DOWN (GLFW_KEY_SPECIAL+28) #define GLFW_KEY_LEFT (GLFW_KEY_SPECIAL+29) #define GLFW_KEY_RIGHT (GLFW_KEY_SPECIAL+30) #define GLFW_KEY_LSHIFT (GLFW_KEY_SPECIAL+31) #define GLFW_KEY_RSHIFT (GLFW_KEY_SPECIAL+32) #define GLFW_KEY_LCTRL (GLFW_KEY_SPECIAL+33) #define GLFW_KEY_RCTRL (GLFW_KEY_SPECIAL+34) #define GLFW_KEY_LALT (GLFW_KEY_SPECIAL+35) #define GLFW_KEY_RALT (GLFW_KEY_SPECIAL+36) #define GLFW_KEY_TAB (GLFW_KEY_SPECIAL+37) #define GLFW_KEY_ENTER (GLFW_KEY_SPECIAL+38) #define GLFW_KEY_BACKSPACE (GLFW_KEY_SPECIAL+39) #define GLFW_KEY_INSERT (GLFW_KEY_SPECIAL+40) #define GLFW_KEY_DEL (GLFW_KEY_SPECIAL+41) #define GLFW_KEY_PAGEUP (GLFW_KEY_SPECIAL+42) #define GLFW_KEY_PAGEDOWN (GLFW_KEY_SPECIAL+43) #define GLFW_KEY_HOME (GLFW_KEY_SPECIAL+44) #define GLFW_KEY_END (GLFW_KEY_SPECIAL+45) #define GLFW_KEY_KP_0 (GLFW_KEY_SPECIAL+46) #define GLFW_KEY_KP_1 (GLFW_KEY_SPECIAL+47) #define GLFW_KEY_KP_2 (GLFW_KEY_SPECIAL+48) #define GLFW_KEY_KP_3 (GLFW_KEY_SPECIAL+49) #define GLFW_KEY_KP_4 (GLFW_KEY_SPECIAL+50) #define GLFW_KEY_KP_5 (GLFW_KEY_SPECIAL+51) #define GLFW_KEY_KP_6 (GLFW_KEY_SPECIAL+52) #define GLFW_KEY_KP_7 (GLFW_KEY_SPECIAL+53) #define GLFW_KEY_KP_8 (GLFW_KEY_SPECIAL+54) #define GLFW_KEY_KP_9 (GLFW_KEY_SPECIAL+55) #define GLFW_KEY_KP_DIVIDE (GLFW_KEY_SPECIAL+56) #define GLFW_KEY_KP_MULTIPLY (GLFW_KEY_SPECIAL+57) #define GLFW_KEY_KP_SUBTRACT (GLFW_KEY_SPECIAL+58) #define GLFW_KEY_KP_ADD (GLFW_KEY_SPECIAL+59) #define GLFW_KEY_KP_DECIMAL (GLFW_KEY_SPECIAL+60) #define GLFW_KEY_KP_EQUAL (GLFW_KEY_SPECIAL+61) #define GLFW_KEY_KP_ENTER (GLFW_KEY_SPECIAL+62) #define GLFW_KEY_LAST GLFW_KEY_KP_ENTER // Mouse button #define GLFW_MOUSE_BUTTON_LEFT 0 #define GLFW_MOUSE_BUTTON_RIGHT 1 #define GLFW_MOUSE_BUTTON_MIDDLE 2 #ifdef __cplusplus } #endif #endif // !defined MINI_GLFW_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/MiniGLUT.h0000644000000000000000000001176312635011627024320 0ustar rootroot// --------------------------------------------------------------------------- // // @file MiniGLUT.h // @brief A subset of GLUT definitions needed to compile helper functions // implemented in TwEventGLUT.c // // notes: - Private header // - AntTweakBar.dll does not need to link with GLUT, // it just needs some definitions for its helper functions. // - This header is provided to avoid the need of having GLUT // installed to recompile AntTweakBar. // - Do not use this header in your own programs, better use the // GLUT.h header from the actual GLUT library SDK : // http://opengl.org/resources/libraries/glut // // --------------------------------------------------------------------------- #if !defined MINI_GLUT_INCLUDED #define MINI_GLUT_INCLUDED #if defined(_WIN32) || defined(_WIN64) # define WIN32_LEAN_AND_MEAN # include // needed by gl.h # define GLUT_CALL __stdcall # define GLUT_CALLBACK __cdecl # define GLUT_API __declspec(dllimport) #else # define GLUT_CALL # define GLUT_CALLBACK # define GLUT_API extern #endif #if defined(_MACOSX) # include # include #else # include // must be included after windows.h # include #endif #ifdef __cplusplus extern "C" { #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 // glutGetModifiers return mask #define GLUT_ACTIVE_SHIFT 1 #define GLUT_ACTIVE_CTRL 2 #define GLUT_ACTIVE_ALT 4 // 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 // 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 // timer #define GLUT_ELAPSED_TIME ((GLenum) 700) // functions subset GLUT_API void GLUT_CALL glutInit(int *argcp, char **argv); GLUT_API void GLUT_CALL glutInitDisplayMode(unsigned int mode); GLUT_API int GLUT_CALL glutCreateWindow(const char *title); GLUT_API int GLUT_CALL glutGetWindow(void); GLUT_API void GLUT_CALL glutSetWindow(int win); GLUT_API int GLUT_CALL glutCreateSubWindow(int win, int x, int y, int width, int height); GLUT_API int GLUT_CALL glutGet(GLenum type); GLUT_API void GLUT_CALL glutSwapBuffers(); GLUT_API void GLUT_CALL glutPostRedisplay(); GLUT_API void GLUT_CALL glutInitWindowPosition(int x, int y); GLUT_API void GLUT_CALL glutInitWindowSize(int width, int height); GLUT_API void GLUT_CALL glutPositionWindow(int x, int y); GLUT_API void GLUT_CALL glutReshapeWindow(int width, int height); GLUT_API void GLUT_CALL glutMainLoop(); GLUT_API int GLUT_CALL glutCreateMenu(void (GLUT_CALLBACK *func)(int)); GLUT_API void GLUT_CALL glutDisplayFunc(void (GLUT_CALLBACK *func)(void)); GLUT_API void GLUT_CALL glutReshapeFunc(void (GLUT_CALLBACK *func)(int width, int height)); GLUT_API void GLUT_CALL glutKeyboardFunc(void (GLUT_CALLBACK *func)(unsigned char key, int x, int y)); GLUT_API void GLUT_CALL glutMouseFunc(void (GLUT_CALLBACK *func)(int button, int state, int x, int y)); GLUT_API void GLUT_CALL glutMotionFunc(void (GLUT_CALLBACK *func)(int x, int y)); GLUT_API void GLUT_CALL glutPassiveMotionFunc(void (GLUT_CALLBACK *func)(int x, int y)); GLUT_API void GLUT_CALL glutSpecialFunc(void (GLUT_CALLBACK *func)(int key, int x, int y)); GLUT_API int GLUT_CALL glutGetModifiers(void); GLUT_API void GLUT_CALL glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); GLUT_API void GLUT_CALL glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); GLUT_API void GLUT_CALL glutSolidTeapot(GLdouble size); // GLUT exit problem workaround (see glut.h) #if (defined(_WIN32) || defined(_WIN64)) && !defined(GLUT_DISABLE_ATEXIT_HACK) extern void __cdecl exit(int); GLUT_API void GLUT_CALL __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); static void GLUT_CALL glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } #define glutInit glutInit_ATEXIT_HACK #endif #ifdef __cplusplus } #endif #endif // !defined MINI_GLUT_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/MiniSDL12.h0000644000000000000000000002041112635011627024320 0ustar rootroot// --------------------------------------------------------------------------- // // @file MiniSDL12.h // @brief A subset of SDL 1.2 definitions needed to compile helper // functions implemented in TwEventSDL12.c // // notes: - Private header // - AntTweakBar.dll does not need to link with SDL, // it just needs some definitions for its helper functions. // - This header is provided to avoid the need of having SDL // installed to recompile AntTweakBar. // - Do not use this header in your own programs, better use the // SDL.h header from the actual SDL library SDK : // http://www.libsdl.org // // --------------------------------------------------------------------------- #if !defined MINI_SDL12_INCLUDED #define MINI_SDL12_INCLUDED #ifdef __cplusplus extern "C" { #endif #define SDL_MAJOR_VERSION 1 #define SDL_MINOR_VERSION 2 #if defined(_WIN32) || defined(_WIN64) # define SDL_DECLSPEC __declspec(dllimport) # define SDL_CALL __cdecl #else # define SDL_DECLSPEC # define SDL_CALL #endif typedef unsigned char Uint8; typedef signed char Sint8; typedef unsigned short Uint16; typedef signed short Sint16; typedef unsigned int Uint32; typedef signed int Sint32; // Subset of SDL keysym typedef enum { SDLK_BACKSPACE = 8, SDLK_TAB = 9, SDLK_CLEAR = 12, SDLK_RETURN = 13, SDLK_PAUSE = 19, SDLK_ESCAPE = 27, SDLK_DELETE = 127, SDLK_UP = 273, SDLK_DOWN = 274, SDLK_RIGHT = 275, SDLK_LEFT = 276, SDLK_INSERT = 277, SDLK_HOME = 278, SDLK_END = 279, SDLK_PAGEUP = 280, SDLK_PAGEDOWN = 281, SDLK_F1 = 282, SDLK_F2 = 283, SDLK_F3 = 284, SDLK_F4 = 285, SDLK_F5 = 286, SDLK_F6 = 287, SDLK_F7 = 288, SDLK_F8 = 289, SDLK_F9 = 290, SDLK_F10 = 291, SDLK_F11 = 292, SDLK_F12 = 293, } SDLKey; typedef enum { KMOD_NONE = 0x0000, KMOD_LSHIFT = 0x0001, KMOD_RSHIFT = 0x0002, KMOD_LCTRL = 0x0040, KMOD_RCTRL = 0x0080, KMOD_LALT = 0x0100, KMOD_RALT = 0x0200, KMOD_LMETA = 0x0400, KMOD_RMETA = 0x0800, KMOD_NUM = 0x1000, KMOD_CAPS = 0x2000, KMOD_MODE = 0x4000, KMOD_RESERVED = 0x8000 } SDLMod; #define KMOD_CTRL (KMOD_LCTRL|KMOD_RCTRL) #define KMOD_SHIFT (KMOD_LSHIFT|KMOD_RSHIFT) #define KMOD_ALT (KMOD_LALT|KMOD_RALT) #define KMOD_META (KMOD_LMETA|KMOD_RMETA) typedef enum { SDL_NOEVENT = 0, SDL_ACTIVEEVENT, SDL_KEYDOWN, SDL_KEYUP, SDL_MOUSEMOTION, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_QUIT, SDL_SYSWMEVENT, SDL_EVENT_RESERVEDA, SDL_EVENT_RESERVEDB, SDL_VIDEORESIZE, SDL_VIDEOEXPOSE, SDL_EVENT_RESERVED2, SDL_EVENT_RESERVED3, SDL_EVENT_RESERVED4, SDL_EVENT_RESERVED5, SDL_EVENT_RESERVED6, SDL_EVENT_RESERVED7, SDL_USEREVENT = 24, SDL_NUMEVENTS = 32 } SDLEventEnum; typedef struct SDL_keysym { Uint8 scancode; SDLKey sym; SDLMod mod; Uint16 unicode; } SDL_keysym; typedef struct SDL_ActiveEvent { Uint8 type; Uint8 gain; Uint8 state; } SDL_ActiveEvent; typedef struct SDL_KeyboardEvent { Uint8 type; Uint8 which; Uint8 state; SDL_keysym keysym; } SDL_KeyboardEvent; typedef struct SDL_MouseMotionEvent { Uint8 type; Uint8 which; Uint8 state; Uint16 x, y; Sint16 xrel; Sint16 yrel; } SDL_MouseMotionEvent; typedef struct SDL_MouseButtonEvent { Uint8 type; Uint8 which; Uint8 button; Uint8 state; Uint16 x, y; } SDL_MouseButtonEvent; typedef struct SDL_JoyAxisEvent { Uint8 type; Uint8 which; Uint8 axis; Sint16 value; } SDL_JoyAxisEvent; typedef struct SDL_JoyBallEvent { Uint8 type; Uint8 which; Uint8 ball; Sint16 xrel; Sint16 yrel; } SDL_JoyBallEvent; typedef struct SDL_JoyHatEvent { Uint8 type; Uint8 which; Uint8 hat; Uint8 value; } SDL_JoyHatEvent; typedef struct SDL_JoyButtonEvent { Uint8 type; Uint8 which; Uint8 button; Uint8 state; } SDL_JoyButtonEvent; typedef struct SDL_ResizeEvent { Uint8 type; int w; int h; } SDL_ResizeEvent; typedef struct SDL_ExposeEvent { Uint8 type; } SDL_ExposeEvent; typedef struct SDL_QuitEvent { Uint8 type; } SDL_QuitEvent; typedef struct SDL_UserEvent { Uint8 type; int code; void *data1; void *data2; } SDL_UserEvent; struct SDL_SysWMmsg; typedef struct SDL_SysWMmsg SDL_SysWMmsg; typedef struct SDL_SysWMEvent { Uint8 type; SDL_SysWMmsg *msg; } SDL_SysWMEvent; typedef union { Uint8 type; SDL_ActiveEvent active; SDL_KeyboardEvent key; SDL_MouseMotionEvent motion; SDL_MouseButtonEvent button; SDL_JoyAxisEvent jaxis; SDL_JoyBallEvent jball; SDL_JoyHatEvent jhat; SDL_JoyButtonEvent jbutton; SDL_ResizeEvent resize; SDL_ExposeEvent expose; SDL_QuitEvent quit; SDL_UserEvent user; SDL_SysWMEvent syswm; char full[56]; } SDL_Event; typedef struct SDL_PixelFormat { void *palette; Uint8 BitsPerPixel; Uint8 BytesPerPixel; Uint8 Rloss; Uint8 Gloss; Uint8 Bloss; Uint8 Aloss; Uint8 Rshift; Uint8 Gshift; Uint8 Bshift; Uint8 Ashift; Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; Uint32 Amask; Uint32 colorkey; Uint8 alpha; } SDL_PixelFormat; typedef enum { SDL_GL_RED_SIZE, SDL_GL_GREEN_SIZE, SDL_GL_BLUE_SIZE, SDL_GL_ALPHA_SIZE, SDL_GL_BUFFER_SIZE, SDL_GL_DOUBLEBUFFER, SDL_GL_DEPTH_SIZE, SDL_GL_STENCIL_SIZE, SDL_GL_ACCUM_RED_SIZE, SDL_GL_ACCUM_GREEN_SIZE, SDL_GL_ACCUM_BLUE_SIZE, SDL_GL_ACCUM_ALPHA_SIZE, SDL_GL_STEREO, SDL_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLESAMPLES, SDL_GL_ACCELERATED_VISUAL, SDL_GL_RETAINED_BACKING, SDL_GL_CONTEXT_MAJOR_VERSION, SDL_GL_CONTEXT_MINOR_VERSION } SDL_GLattr; typedef struct SDL_VideoInfo { Uint32 hw_available :1; Uint32 wm_available :1; Uint32 UnusedBits1 :6; Uint32 UnusedBits2 :1; Uint32 blit_hw :1; Uint32 blit_hw_CC :1; Uint32 blit_hw_A :1; Uint32 blit_sw :1; Uint32 blit_sw_CC :1; Uint32 blit_sw_A :1; Uint32 blit_fill :1; Uint32 UnusedBits3 :16; Uint32 video_mem; SDL_PixelFormat *vfmt; int current_w; int current_h; } SDL_VideoInfo; #define SDL_INIT_VIDEO 0x00000020 #define SDL_SWSURFACE 0x00000000 #define SDL_HWSURFACE 0x00000001 #define SDL_ASYNCBLIT 0x00000004 #define SDL_ANYFORMAT 0x10000000 #define SDL_HWPALETTE 0x20000000 #define SDL_DOUBLEBUF 0x40000000 #define SDL_FULLSCREEN 0x80000000 #define SDL_OPENGL 0x00000002 #define SDL_OPENGLBLIT 0x0000000A #define SDL_RESIZABLE 0x00000010 #define SDL_NOFRAME 0x00000020 #define SDL_DEFAULT_REPEAT_DELAY 500 #define SDL_DEFAULT_REPEAT_INTERVAL 30 // functions subset extern SDL_DECLSPEC int SDL_CALL SDL_Init(Uint32 flags); extern SDL_DECLSPEC void SDL_CALL SDL_Quit(); extern SDL_DECLSPEC char * SDL_CALL SDL_GetError(); extern SDL_DECLSPEC const SDL_VideoInfo * SDL_CALL SDL_GetVideoInfo(); extern SDL_DECLSPEC struct SDL_Surface * SDL_CALL SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); extern SDL_DECLSPEC int SDL_CALL SDL_GL_SetAttribute(SDL_GLattr attr, int value); extern SDL_DECLSPEC void SDL_CALL SDL_GL_SwapBuffers(); extern SDL_DECLSPEC void SDL_CALL SDL_WM_SetCaption(const char *title, const char *icon); extern SDL_DECLSPEC void SDL_CALL SDL_WM_GetCaption(char **title, char **icon); extern SDL_DECLSPEC int SDL_CALL SDL_EnableUNICODE(int enable); extern SDL_DECLSPEC int SDL_CALL SDL_EnableKeyRepeat(int delay, int interval); extern SDL_DECLSPEC Uint32 SDL_CALL SDL_GetTicks(); extern SDL_DECLSPEC int SDL_CALL SDL_PollEvent(SDL_Event *event); extern SDL_DECLSPEC int SDL_CALL SDL_WaitEvent(SDL_Event *event); extern SDL_DECLSPEC int SDL_CALL SDL_PushEvent(SDL_Event *event); #ifdef __cplusplus } #endif #endif // !defined MINI_SDL12_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/MiniSDL13.h0000644000000000000000000002776312635011627024342 0ustar rootroot// --------------------------------------------------------------------------- // // @file MiniSDL13.h // @brief A subset of SDL 1.3 definitions needed to compile helper // functions implemented in TwEventSDL13.c // // notes: - Private header // - AntTweakBar.dll does not need to link with SDL, // it just needs some definitions for its helper functions. // - This header is provided to avoid the need of having SDL // installed to recompile AntTweakBar. // - Do not use this header in your own programs, better use the // SDL.h header from the actual SDL library SDK : // http://www.libsdl.org // // --------------------------------------------------------------------------- #if !defined MINI_SDL_INCLUDED #define MINI_SDL_INCLUDED #ifdef __cplusplus extern "C" { #endif #define SDL_MAJOR_VERSION 1 #define SDL_MINOR_VERSION 3 #if defined(_WIN32) || defined(_WIN64) # define SDL_DECLSPEC __declspec(dllimport) # define SDL_CALL __cdecl #else # define SDL_DECLSPEC # define SDL_CALL #endif typedef unsigned char Uint8; typedef signed char Sint8; typedef unsigned short Uint16; typedef signed short Sint16; typedef unsigned int Uint32; typedef signed int Sint32; #define SDLK_SCANCODE_MASK (1<<30) #define SDL_SCANCODE_TO_KEYCODE(X) (X | SDLK_SCANCODE_MASK) // Subset of SDL scancodes. // Note: some SDL scancodes seems to be wrong in the original // SDL scancode header file. typedef enum { SDL_SCANCODE_F1 = 58, SDL_SCANCODE_F2 = 59, SDL_SCANCODE_F3 = 60, SDL_SCANCODE_F4 = 61, SDL_SCANCODE_F5 = 62, SDL_SCANCODE_F6 = 63, SDL_SCANCODE_F7 = 64, SDL_SCANCODE_F8 = 65, SDL_SCANCODE_F9 = 66, SDL_SCANCODE_F10 = 67, SDL_SCANCODE_F11 = 68, SDL_SCANCODE_F12 = 69, SDL_SCANCODE_INSERT = 98, //73, SDL_SCANCODE_HOME = 95, //74, SDL_SCANCODE_PAGEUP = 97, //75, SDL_SCANCODE_DELETE = 99, //76, SDL_SCANCODE_END = 89, //77, SDL_SCANCODE_PAGEDOWN = 91, //78, SDL_SCANCODE_RIGHT = 94, //79, SDL_SCANCODE_LEFT = 92, //80, SDL_SCANCODE_DOWN = 90, //81, SDL_SCANCODE_UP = 96 //82 } SDL_scancode; // Subset of SDL keysym typedef enum { SDLK_BACKSPACE = 8, SDLK_TAB = 9, SDLK_CLEAR = 12, SDLK_RETURN = 13, SDLK_PAUSE = 19, SDLK_ESCAPE = 27, SDLK_DELETE = 127, SDLK_UP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UP), SDLK_DOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DOWN), SDLK_RIGHT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RIGHT), SDLK_LEFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LEFT), SDLK_INSERT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INSERT), SDLK_HOME = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HOME), SDLK_END = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_END), SDLK_PAGEUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEUP), SDLK_PAGEDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEDOWN), SDLK_F1 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F1), SDLK_F2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F2), SDLK_F3 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F3), SDLK_F4 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F4), SDLK_F5 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F5), SDLK_F6 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F6), SDLK_F7 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F7), SDLK_F8 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F8), SDLK_F9 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F9), SDLK_F10 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F10), SDLK_F11 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F11), SDLK_F12 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F12) } SDLKey; typedef enum { KMOD_NONE = 0x0000, KMOD_LSHIFT = 0x0001, KMOD_RSHIFT = 0x0002, KMOD_LCTRL = 0x0040, KMOD_RCTRL = 0x0080, KMOD_LALT = 0x0100, KMOD_RALT = 0x0200, KMOD_LGUI = 0x0400, KMOD_RGUI = 0x0800, KMOD_NUM = 0x1000, KMOD_CAPS = 0x2000, KMOD_MODE = 0x4000, KMOD_RESERVED = 0x8000 } SDLMod; #define KMOD_CTRL (KMOD_LCTRL|KMOD_RCTRL) #define KMOD_SHIFT (KMOD_LSHIFT|KMOD_RSHIFT) #define KMOD_ALT (KMOD_LALT|KMOD_RALT) #define KMOD_GUI (KMOD_LGUI|KMOD_RGUI) typedef enum { SDL_NOEVENT = 0, SDL_WINDOWEVENT, SDL_KEYDOWN, SDL_KEYUP, SDL_TEXTEDITING, SDL_TEXTINPUT, SDL_MOUSEMOTION, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEWHEEL, SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_QUIT, SDL_SYSWMEVENT, SDL_PROXIMITYIN, SDL_PROXIMITYOUT, SDL_EVENT_RESERVED1, SDL_EVENT_RESERVED2, SDL_EVENT_RESERVED3, SDL_USEREVENT = 24, SDL_NUMEVENTS = 32 } SDL_EventType; #define SDL_ACTIVEEVENT SDL_EVENT_RESERVED1 #define SDL_VIDEORESIZE SDL_EVENT_RESERVED2 #define SDL_VIDEOEXPOSE SDL_EVENT_RESERVED3 typedef Uint32 SDL_WindowID; typedef struct SDL_keysym { SDL_scancode scancode; SDLKey sym; Uint16 mod; Uint32 unicode; } SDL_keysym; typedef struct SDL_WindowEvent { Uint8 type; SDL_WindowID windowID; Uint8 event; int data1; int data2; } SDL_WindowEvent; typedef struct SDL_KeyboardEvent { Uint8 type; SDL_WindowID windowID; Uint8 which; Uint8 state; SDL_keysym keysym; } SDL_KeyboardEvent; #define SDL_TEXTEDITINGEVENT_TEXT_SIZE (32) typedef struct SDL_TextEditingEvent { Uint8 type; char text[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; int start; int length; } SDL_TextEditingEvent; #define SDL_TEXTINPUTEVENT_TEXT_SIZE (32) typedef struct SDL_TextInputEvent { Uint8 type; SDL_WindowID windowID; Uint8 which; char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; } SDL_TextInputEvent; typedef struct SDL_MouseMotionEvent { Uint8 type; SDL_WindowID windowID; Uint8 which; Uint8 state; int x; int y; int z; int pressure; int pressure_max; int pressure_min; int rotation; int tilt; int cursor; int xrel; int yrel; } SDL_MouseMotionEvent; typedef struct SDL_MouseButtonEvent { Uint8 type; SDL_WindowID windowID; Uint8 which; Uint8 button; Uint8 state; int x; int y; } SDL_MouseButtonEvent; typedef struct SDL_MouseWheelEvent { Uint8 type; SDL_WindowID windowID; Uint8 which; int x; int y; } SDL_MouseWheelEvent; typedef struct SDL_JoyAxisEvent { Uint8 type; Uint8 which; Uint8 axis; Sint16 value; } SDL_JoyAxisEvent; typedef struct SDL_JoyBallEvent { Uint8 type; Uint8 which; Uint8 ball; Sint16 xrel; Sint16 yrel; } SDL_JoyBallEvent; typedef struct SDL_JoyHatEvent { Uint8 type; Uint8 which; Uint8 hat; Uint8 value; } SDL_JoyHatEvent; typedef struct SDL_JoyButtonEvent { Uint8 type; Uint8 which; Uint8 button; Uint8 state; } SDL_JoyButtonEvent; typedef struct SDL_ActiveEvent { Uint8 type; Uint8 gain; Uint8 state; } SDL_ActiveEvent; typedef struct SDL_ResizeEvent { Uint8 type; int w; int h; } SDL_ResizeEvent; typedef struct SDL_ExposeEvent { Uint8 type; } SDL_ExposeEvent; typedef struct SDL_QuitEvent { Uint8 type; } SDL_QuitEvent; typedef struct SDL_UserEvent { Uint8 type; SDL_WindowID windowID; int code; void *data1; void *data2; } SDL_UserEvent; struct SDL_SysWMmsg; typedef struct SDL_SysWMmsg SDL_SysWMmsg; typedef struct SDL_SysWMEvent { Uint8 type; SDL_SysWMmsg *msg; } SDL_SysWMEvent; typedef struct SDL_ProximityEvent { Uint8 type; SDL_WindowID windowID; Uint8 which; int cursor; int x; int y; } SDL_ProximityEvent; typedef union SDL_Event { Uint8 type; SDL_WindowEvent window; SDL_KeyboardEvent key; SDL_TextEditingEvent edit; SDL_TextInputEvent text; SDL_MouseMotionEvent motion; SDL_MouseButtonEvent button; SDL_MouseWheelEvent wheel; SDL_JoyAxisEvent jaxis; SDL_JoyBallEvent jball; SDL_JoyHatEvent jhat; SDL_JoyButtonEvent jbutton; SDL_QuitEvent quit; SDL_UserEvent user; SDL_SysWMEvent syswm; SDL_ProximityEvent proximity; SDL_ActiveEvent active; SDL_ResizeEvent resize; } SDL_Event; typedef struct SDL_PixelFormat { void *palette; Uint8 BitsPerPixel; Uint8 BytesPerPixel; Uint8 Rloss; Uint8 Gloss; Uint8 Bloss; Uint8 Aloss; Uint8 Rshift; Uint8 Gshift; Uint8 Bshift; Uint8 Ashift; Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; Uint32 Amask; } SDL_PixelFormat; typedef enum SDL_GLattr { SDL_GL_RED_SIZE, SDL_GL_GREEN_SIZE, SDL_GL_BLUE_SIZE, SDL_GL_ALPHA_SIZE, SDL_GL_BUFFER_SIZE, SDL_GL_DOUBLEBUFFER, SDL_GL_DEPTH_SIZE, SDL_GL_STENCIL_SIZE, SDL_GL_ACCUM_RED_SIZE, SDL_GL_ACCUM_GREEN_SIZE, SDL_GL_ACCUM_BLUE_SIZE, SDL_GL_ACCUM_ALPHA_SIZE, SDL_GL_STEREO, SDL_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLESAMPLES, SDL_GL_ACCELERATED_VISUAL, SDL_GL_RETAINED_BACKING, SDL_GL_CONTEXT_MAJOR_VERSION, SDL_GL_CONTEXT_MINOR_VERSION } SDL_GLattr; typedef struct SDL_VideoInfo { Uint32 hw_available :1; Uint32 wm_available :1; Uint32 UnusedBits1 :6; Uint32 UnusedBits2 :1; Uint32 blit_hw :1; Uint32 blit_hw_CC :1; Uint32 blit_hw_A :1; Uint32 blit_sw :1; Uint32 blit_sw_CC :1; Uint32 blit_sw_A :1; Uint32 blit_fill :1; Uint32 UnusedBits3 :16; Uint32 video_mem; SDL_PixelFormat *vfmt; int current_w; int current_h; } SDL_VideoInfo; #define SDL_INIT_VIDEO 0x00000020 #define SDL_ANYFORMAT 0x00100000 #define SDL_HWPALETTE 0x00200000 #define SDL_DOUBLEBUF 0x00400000 #define SDL_FULLSCREEN 0x00800000 #define SDL_RESIZABLE 0x01000000 #define SDL_NOFRAME 0x02000000 #define SDL_OPENGL 0x04000000 #define SDL_HWSURFACE 0x08000001 #define SDL_DEFAULT_REPEAT_DELAY 500 #define SDL_DEFAULT_REPEAT_INTERVAL 30 // functions subset extern SDL_DECLSPEC int SDL_CALL SDL_Init(Uint32 flags); extern SDL_DECLSPEC void SDL_CALL SDL_Quit(); extern SDL_DECLSPEC char * SDL_CALL SDL_GetError(); extern SDL_DECLSPEC const SDL_VideoInfo * SDL_CALL SDL_GetVideoInfo(); extern SDL_DECLSPEC struct SDL_Surface * SDL_CALL SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); extern SDL_DECLSPEC int SDL_CALL SDL_GL_SetAttribute(SDL_GLattr attr, int value); extern SDL_DECLSPEC void SDL_CALL SDL_GL_SwapBuffers(); extern SDL_DECLSPEC void SDL_CALL SDL_WM_SetCaption(const char *title, const char *icon); extern SDL_DECLSPEC void SDL_CALL SDL_WM_GetCaption(char **title, char **icon); extern SDL_DECLSPEC int SDL_CALL SDL_EnableUNICODE(int enable); extern SDL_DECLSPEC int SDL_CALL SDL_EnableKeyRepeat(int delay, int interval); extern SDL_DECLSPEC Uint32 SDL_CALL SDL_GetTicks(); extern SDL_DECLSPEC int SDL_CALL SDL_PollEvent(SDL_Event *event); extern SDL_DECLSPEC int SDL_CALL SDL_WaitEvent(SDL_Event *event); extern SDL_DECLSPEC int SDL_CALL SDL_PushEvent(SDL_Event *event); #ifdef __cplusplus } #endif #endif // !defined MINI_SDL_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/MiniSFML16.h0000644000000000000000000001637712635011627024463 0ustar rootroot// --------------------------------------------------------------------------- // // @file MiniSFML16.h // @brief A subset of SFML 1.6 definitions needed to compile helper // functions implemented in TwEventSFML.cpp // // notes: - Private header // - AntTweakBar.dll does not need to link with SFML, // it just needs some definitions for its helper functions. // - This header is provided to avoid the need of having SFML // installed to recompile AntTweakBar. // It declares a small and incomplete part of SFML classes. // For instance, many non-virtual methods have been stripped out. // - Do not use this header in your own programs, better use the // SFML headers from the actual SFML library SDK : // http://www.sfml-dev.org // // --------------------------------------------------------------------------- #if !defined MINI_SFML16_INCLUDED #define MINI_SFML16_INCLUDED namespace sf { namespace Key { enum Code { A = 'a', B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, Num0 = '0', Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Escape = 256, LControl, LShift, LAlt, LSystem, RControl, RShift, RAlt, RSystem, Menu, LBracket, RBracket, SemiColon, Comma, Period, Quote, Slash, BackSlash, Tilde, Equal, Dash, Space, Return, Back, Tab, PageUp, PageDown, End, Home, Insert, Delete, Add, Subtract, Multiply, Divide, Left, Right, Up, Down, Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, Pause, Count }; } namespace Mouse { enum Button { Left, Right, Middle, XButton1, XButton2, Count }; } namespace Joy { enum Axis { AxisX, AxisY, AxisZ, AxisR, AxisU, AxisV, AxisPOV, AxisCount }; enum { Count = 4, ButtonCount = 32}; } typedef unsigned char Uint8; typedef unsigned int Uint32; class Event { public : struct KeyEvent { Key::Code Code; bool Alt, Control, Shift; }; struct TextEvent { Uint32 Unicode; }; struct MouseMoveEvent { int X, Y; }; struct MouseButtonEvent { Mouse::Button Button; int X, Y; }; struct MouseWheelEvent { int Delta; }; struct JoyMoveEvent { unsigned int JoystickId; Joy::Axis Axis; float Position; }; struct JoyButtonEvent { unsigned int JoystickId, Button; }; struct SizeEvent { unsigned int Width, Height; }; enum EventType { Closed, Resized, LostFocus, GainedFocus, TextEntered, KeyPressed, KeyReleased, MouseWheelMoved, MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseEntered, MouseLeft, JoyButtonPressed, JoyButtonReleased, JoyMoved }; EventType Type; union { KeyEvent Key; TextEvent Text; MouseMoveEvent MouseMove; MouseButtonEvent MouseButton; MouseWheelEvent MouseWheel; JoyMoveEvent JoyMove; JoyButtonEvent JoyButton; SizeEvent Size; }; }; } // namespace sf #ifdef USE_MINI_SFML // we also need some the definition of sf::RenderWindow to compile our SFML example #include #include namespace sf { class Input; class Drawable; typedef void* WindowHandle; namespace priv { class WindowImpl; } class WindowListener { public : virtual void OnEvent(const Event& EventReceived) = 0; protected : virtual ~WindowListener(); }; class VideoMode { public : VideoMode(unsigned int ModeWidth, unsigned int ModeHeight, unsigned int ModeBpp = 32); unsigned int Width, Height, BitsPerPixel; }; namespace Style { enum { None = 0, Titlebar = 1 << 0, Resize = 1 << 1, Close = 1 << 2, Fullscreen = 1 << 3 }; } struct WindowSettings { explicit WindowSettings(unsigned int Depth = 24, unsigned int Stencil = 8, unsigned int Antialiasing = 0); unsigned int DepthBits, StencilBits, AntialiasingLevel; }; class Clock { public : Clock(); float GetElapsedTime() const; void Reset(); private : double myStartTime; }; class Input : public WindowListener { private : virtual void OnEvent(const Event& EventReceived); bool myKeys[Key::Count]; bool myMouseButtons[Mouse::Count]; int myMouseX; int myMouseY; bool myJoystickButtons[Joy::Count][Joy::ButtonCount]; float myJoystickAxis[Joy::Count][Joy::AxisCount]; }; class Window : public WindowListener { public : Window(VideoMode Mode, const std::string& Title, unsigned long WindowStyle = Style::Resize | Style::Close, const WindowSettings& Params = WindowSettings()); virtual ~Window(); void Close(); bool IsOpened() const; unsigned int GetWidth() const; unsigned int GetHeight() const; bool GetEvent(Event& EventReceived); void Display(); private : virtual void OnCreate(); virtual void OnEvent(const Event& EventReceived); priv::WindowImpl* myWindow; std::queue myEvents; Input myInput; Clock myClock; WindowSettings mySettings; float myLastFrameTime; bool myIsExternal; unsigned int myFramerateLimit; int mySetCursorPosX; int mySetCursorPosY; }; template class Vector2 { public : T x, y; }; typedef Vector2 Vector2f; template class Rect { public : T Left, Top, Right, Bottom; }; typedef Rect FloatRect; class Matrix3 { private : float myData[16]; }; class View { private : sf::Vector2f myCenter; sf::Vector2f myHalfSize; FloatRect myRect; Matrix3 myMatrix; bool myNeedUpdate; }; class RenderTarget { public : virtual ~RenderTarget(); virtual void Draw(const Drawable& Object); virtual unsigned int GetWidth() const = 0; virtual unsigned int GetHeight() const = 0; void PreserveOpenGLStates(bool Preserve); private : virtual bool Activate(bool Active) = 0; View myDefaultView; const View* myCurrentView; bool myPreserveStates; bool myIsDrawing; }; class RenderWindow : public Window, public RenderTarget { public : RenderWindow(VideoMode Mode, const std::string& Title, unsigned long WindowStyle = Style::Resize | Style::Close, const WindowSettings& Params = WindowSettings()); virtual ~RenderWindow(); virtual unsigned int GetWidth() const; virtual unsigned int GetHeight() const; private : virtual void OnCreate(); virtual bool Activate(bool Active); }; } // namespace sf #endif // USE_MINI_SFML #endif // !defined MINI_SFML16_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwBar.cpp0000644000000000000000000111210412635011627024272 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwBar.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include #include "TwMgr.h" #include "TwBar.h" #include "TwColors.h" using namespace std; extern const char *g_ErrNotFound; const char *g_ErrUnknownAttrib = "Unknown parameter"; const char *g_ErrInvalidAttrib = "Invalid parameter"; const char *g_ErrNotGroup = "Value is not a group"; const char *g_ErrNoValue = "Value required"; const char *g_ErrBadValue = "Bad value"; const char *g_ErrUnknownType = "Unknown type"; const char *g_ErrNotEnum = "Must be of type Enum"; #undef PERF // comment to print benchs #define PERF(cmd) PerfTimer g_BarTimer; #define ANT_SET_CURSOR(_Name) g_TwMgr->SetCursor(g_TwMgr->m_Cursor##_Name) #define ANT_SET_ROTO_CURSOR(_Num) g_TwMgr->SetCursor(g_TwMgr->m_RotoCursors[_Num]) #if !defined(ANT_WINDOWS) # define _stricmp strcasecmp # define _strdup strdup #endif // defined(ANT_WINDOWS) #if !defined(M_PI) # define M_PI 3.1415926535897932384626433832795 #endif // !defined(M_PI) const float FLOAT_MAX = 3.0e+38f; const double DOUBLE_MAX = 1.0e+308; const double DOUBLE_EPS = 1.0e-307; bool IsCustomType(int _Type) { return (g_TwMgr && _Type>=TW_TYPE_CUSTOM_BASE && _Typem_Customs.size()); } bool IsCSStringType(int _Type) { return (_Type>TW_TYPE_CSSTRING_BASE && _Type<=TW_TYPE_CSSTRING_MAX); } bool IsEnumType(int _Type) { return (g_TwMgr && _Type>=TW_TYPE_ENUM_BASE && _Typem_Enums.size()); } // --------------------------------------------------------------------------- CTwVar::CTwVar() { m_IsRoot = false; m_DontClip = false; m_Visible = true; m_LeftMargin = 0; m_TopMargin = 0; m_ColorPtr = &COLOR32_WHITE; m_BgColorPtr = &COLOR32_ZERO; // default } CTwVarAtom::CTwVarAtom() { m_Type = TW_TYPE_UNDEF; m_Ptr = NULL; m_SetCallback = NULL; m_GetCallback = NULL; m_ClientData = NULL; m_ReadOnly = false; m_NoSlider = false; m_KeyIncr[0] = 0; m_KeyIncr[1] = 0; m_KeyDecr[0] = 0; m_KeyDecr[1] = 0; memset(&m_Val, 0, sizeof(UVal)); } CTwVarAtom::~CTwVarAtom() { if( m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP ) { if( m_Val.m_Bool.m_FreeTrueString && m_Val.m_Bool.m_TrueString!=NULL ) { free(m_Val.m_Bool.m_TrueString); m_Val.m_Bool.m_TrueString = NULL; } if( m_Val.m_Bool.m_FreeFalseString && m_Val.m_Bool.m_FalseString!=NULL ) { free(m_Val.m_Bool.m_FalseString); m_Val.m_Bool.m_FalseString = NULL; } } else if( m_Type==TW_TYPE_CDSTDSTRING && m_GetCallback==CTwMgr::CCDStdString::GetCB && m_ClientData!=NULL && g_TwMgr!=NULL ) { // delete corresponding g_TwMgr->m_CDStdStrings element const CTwMgr::CCDStdString *CDStdString = (const CTwMgr::CCDStdString *)m_ClientData; //if( &(*CDStdString->m_This)==CDStdString ) // g_TwMgr->m_CDStdStrings.erase(CDStdString->m_This); for( list::iterator it=g_TwMgr->m_CDStdStrings.begin(); it!=g_TwMgr->m_CDStdStrings.end(); ++it ) if( &(*it)==CDStdString ) { g_TwMgr->m_CDStdStrings.erase(it); break; } } /* else if( m_Type==TW_TYPE_ENUM8 || m_Type==TW_TYPE_ENUM16 || m_Type==TW_TYPE_ENUM32 ) { if( m_Val.m_Enum.m_Entries!=NULL ) { delete m_Val.m_Enum.m_Entries; m_Val.m_Enum.m_Entries = NULL; } } */ } // --------------------------------------------------------------------------- void CTwVarAtom::ValueToString(string *_Str) const { assert(_Str!=NULL); static const char *ErrStr = "unreachable"; char Tmp[1024]; if( m_Type==TW_TYPE_UNDEF || m_Type==TW_TYPE_HELP_ATOM || m_Type==TW_TYPE_HELP_GRP || m_Type==TW_TYPE_BUTTON ) // has no value { *_Str = ""; return; } else if( m_Type==TW_TYPE_HELP_HEADER ) { *_Str = "SHORTCUTS"; return; } else if( m_Type==TW_TYPE_SHORTCUT ) // special case for help bar: display shortcut { *_Str = ""; if( m_ReadOnly && m_Val.m_Shortcut.m_Incr[0]==0 && m_Val.m_Shortcut.m_Decr[0]==0 ) (*_Str) = "(read only)"; else { if( m_Val.m_Shortcut.m_Incr[0]>0 ) TwGetKeyString(_Str, m_Val.m_Shortcut.m_Incr[0], m_Val.m_Shortcut.m_Incr[1]); else (*_Str) += "(none)"; if( m_Val.m_Shortcut.m_Decr[0]>0 ) { (*_Str) += " "; TwGetKeyString(_Str, m_Val.m_Shortcut.m_Decr[0], m_Val.m_Shortcut.m_Decr[1]); } } return; } else if( m_Type==TW_TYPE_HELP_STRUCT ) { int idx = m_Val.m_HelpStruct.m_StructType - TW_TYPE_STRUCT_BASE; if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() ) { if( g_TwMgr->m_Structs[idx].m_Name.length()>0 ) (*_Str) = '{' + g_TwMgr->m_Structs[idx].m_Name + '}'; else (*_Str) = "{struct}"; } return; } if( m_Ptr==NULL && m_GetCallback==NULL ) { *_Str = ErrStr; return; } bool UseGet = (m_GetCallback!=NULL); switch( m_Type ) { case TW_TYPE_BOOLCPP: { bool Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(bool *)m_Ptr; if( Val ) *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1"; else *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0"; } break; case TW_TYPE_BOOL8: { char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(char *)m_Ptr; if( Val ) *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1"; else *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0"; } break; case TW_TYPE_BOOL16: { short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(short *)m_Ptr; if( Val ) *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1"; else *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0"; } break; case TW_TYPE_BOOL32: { int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(int *)m_Ptr; if( Val ) *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1"; else *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0"; } break; case TW_TYPE_CHAR: { unsigned char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned char *)m_Ptr; if( Val!=0 ) { int d = Val; if( m_Val.m_Char.m_Hexa ) sprintf(Tmp, "%c (0x%.2X)", Val, d); else sprintf(Tmp, "%c (%d)", Val, d); *_Str = Tmp; } else { *_Str = " (0)"; const_cast(_Str->c_str())[0] = '\0'; } } break; case TW_TYPE_INT8: { signed char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(signed char *)m_Ptr; int d = Val; if( m_Val.m_Int8.m_Hexa ) sprintf(Tmp, "0x%.2X", d&0xff); else sprintf(Tmp, "%d", d); *_Str = Tmp; } break; case TW_TYPE_UINT8: { unsigned char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned char *)m_Ptr; unsigned int d = Val; if( m_Val.m_UInt8.m_Hexa ) sprintf(Tmp, "0x%.2X", d); else sprintf(Tmp, "%u", d); *_Str = Tmp; } break; case TW_TYPE_INT16: { short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(short *)m_Ptr; int d = Val; if( m_Val.m_Int16.m_Hexa ) sprintf(Tmp, "0x%.4X", d&0xffff); else sprintf(Tmp, "%d", d); *_Str = Tmp; } break; case TW_TYPE_UINT16: { unsigned short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned short *)m_Ptr; unsigned int d = Val; if( m_Val.m_UInt16.m_Hexa ) sprintf(Tmp, "0x%.4X", d); else sprintf(Tmp, "%u", d); *_Str = Tmp; } break; case TW_TYPE_INT32: { int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(int *)m_Ptr; if( m_Val.m_Int32.m_Hexa ) sprintf(Tmp, "0x%.8X", Val); else sprintf(Tmp, "%d", Val); *_Str = Tmp; } break; case TW_TYPE_UINT32: { unsigned int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned int *)m_Ptr; if( m_Val.m_UInt32.m_Hexa ) sprintf(Tmp, "0x%.8X", Val); else sprintf(Tmp, "%u", Val); *_Str = Tmp; } break; case TW_TYPE_FLOAT: { float Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(float *)m_Ptr; if( m_Val.m_Float32.m_Precision<0 ) sprintf(Tmp, "%g", Val); else { char Fmt[64]; sprintf(Fmt, "%%.%df", (int)m_Val.m_Float32.m_Precision); sprintf(Tmp, Fmt, Val); } *_Str = Tmp; } break; case TW_TYPE_DOUBLE: { double Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(double *)m_Ptr; if( m_Val.m_Float64.m_Precision<0 ) sprintf(Tmp, "%g", Val); else { char Fmt[128]; sprintf(Fmt, "%%.%dlf", (int)m_Val.m_Float64.m_Precision); sprintf(Tmp, Fmt, Val); } *_Str = Tmp; } break; case TW_TYPE_STDSTRING: { if( UseGet ) m_GetCallback(_Str, m_ClientData); else *_Str = *(std::string *)m_Ptr; } break; /* case TW_TYPE_ENUM8: case TW_TYPE_ENUM16: case TW_TYPE_ENUM32: { unsigned int d = 0; if( m_Type==TW_TYPE_ENUM8 ) { unsigned char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned char *)m_Ptr; d = Val; } else if( m_Type==TW_TYPE_ENUM16 ) { unsigned short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned short *)m_Ptr; d = Val; } else { assert(m_Type==TW_TYPE_ENUM32); unsigned int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned int *)m_Ptr; d = Val; } bool Found = false; if( m_Val.m_Enum.m_Entries!=NULL ) { UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(d); if( It!=m_Val.m_Enum.m_Entries->end() ) { *_Str = It->second; Found = true; } } if( !Found ) { sprintf(Tmp, "%u", d); *_Str = Tmp; } } break; */ default: if( IsEnumType(m_Type) ) { unsigned int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned int *)m_Ptr; CTwMgr::CEnum& e = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE]; CTwMgr::CEnum::CEntries::iterator It = e.m_Entries.find(Val); if( It!=e.m_Entries.end() ) *_Str = It->second; else { sprintf(Tmp, "%u", Val); *_Str = Tmp; } } else if( IsCSStringType(m_Type) ) { char *Val = NULL; if( UseGet ) { int n = TW_CSSTRING_SIZE(m_Type); if( n+32>(int)g_TwMgr->m_CSStringBuffer.size() ) g_TwMgr->m_CSStringBuffer.resize(n+32); Val = &(g_TwMgr->m_CSStringBuffer[0]); m_GetCallback(Val , m_ClientData); Val[n] = '\0'; } else Val = (char *)m_Ptr; if( Val!=NULL ) *_Str = Val; else *_Str = ""; } else if( m_Type==TW_TYPE_CDSTRING || m_Type==TW_TYPE_CDSTDSTRING ) { char *Val = NULL; if( UseGet ) m_GetCallback(&Val , m_ClientData); else Val = *(char **)m_Ptr; if( Val!=NULL ) *_Str = Val; else *_Str = ""; } else if( IsCustom() ) // m_Type>=TW_TYPE_CUSTOM_BASE && m_Typem_Customs.size() ) { *_Str = ""; } else { *_Str = "unknown type"; const_cast(this)->m_ReadOnly = true; } } } // --------------------------------------------------------------------------- double CTwVarAtom::ValueToDouble() const { if( m_Ptr==NULL && m_GetCallback==NULL ) return 0; // unreachable bool UseGet = (m_GetCallback!=NULL); switch( m_Type ) { case TW_TYPE_BOOLCPP: { bool Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(bool *)m_Ptr; if( Val ) return 1; else return 0; } break; case TW_TYPE_BOOL8: { char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(char *)m_Ptr; if( Val ) return 1; else return 0; } break; case TW_TYPE_BOOL16: { short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(short *)m_Ptr; if( Val ) return 1; else return 0; } break; case TW_TYPE_BOOL32: { int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(int *)m_Ptr; if( Val ) return 1; else return 0; } break; case TW_TYPE_CHAR: { unsigned char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned char *)m_Ptr; return Val; } break; case TW_TYPE_INT8: { signed char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(signed char *)m_Ptr; int d = Val; return d; } break; case TW_TYPE_UINT8: { unsigned char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned char *)m_Ptr; unsigned int d = Val; return d; } break; case TW_TYPE_INT16: { short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(short *)m_Ptr; int d = Val; return d; } break; case TW_TYPE_UINT16: { unsigned short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned short *)m_Ptr; unsigned int d = Val; return d; } break; case TW_TYPE_INT32: { int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(int *)m_Ptr; return Val; } break; case TW_TYPE_UINT32: { unsigned int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned int *)m_Ptr; return Val; } break; case TW_TYPE_FLOAT: { float Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(float *)m_Ptr; return Val; } break; case TW_TYPE_DOUBLE: { double Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(double *)m_Ptr; return Val; } break; /* case TW_TYPE_ENUM8: case TW_TYPE_ENUM16: case TW_TYPE_ENUM32: { unsigned int d = 0; if( m_Type==TW_TYPE_ENUM8 ) { unsigned char Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned char *)m_Ptr; d = Val; } else if( m_Type==TW_TYPE_ENUM16 ) { unsigned short Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned short *)m_Ptr; d = Val; } else { assert(m_Type==TW_TYPE_ENUM32); unsigned int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned int *)m_Ptr; d = Val; } return d; } break; */ default: if( IsEnumType(m_Type) ) { unsigned int Val = 0; if( UseGet ) m_GetCallback(&Val, m_ClientData); else Val = *(unsigned int *)m_Ptr; return Val; } else return 0; // unknown type } } // --------------------------------------------------------------------------- void CTwVarAtom::ValueFromDouble(double _Val) { if( m_Ptr==NULL && m_SetCallback==NULL ) return; // unreachable bool UseSet = (m_SetCallback!=NULL); switch( m_Type ) { case TW_TYPE_BOOLCPP: { bool Val = (_Val!=0); if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(bool*)m_Ptr = Val; } break; case TW_TYPE_BOOL8: { char Val = (_Val!=0) ? 1 : 0; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(char*)m_Ptr = Val; } break; case TW_TYPE_BOOL16: { short Val = (_Val!=0) ? 1 : 0; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(short*)m_Ptr = Val; } break; case TW_TYPE_BOOL32: { int Val = (_Val!=0) ? 1 : 0; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(int*)m_Ptr = Val; } break; case TW_TYPE_CHAR: { unsigned char Val = (unsigned char)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(unsigned char*)m_Ptr = Val; } break; case TW_TYPE_INT8: { signed char Val = (signed char)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(signed char*)m_Ptr = Val; } break; case TW_TYPE_UINT8: //case TW_TYPE_ENUM8: { unsigned char Val = (unsigned char)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(unsigned char*)m_Ptr = Val; } break; case TW_TYPE_INT16: { short Val = (short)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(short*)m_Ptr = Val; } break; case TW_TYPE_UINT16: //case TW_TYPE_ENUM16: { unsigned short Val = (unsigned short)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(unsigned short*)m_Ptr = Val; } break; case TW_TYPE_INT32: { int Val = (int)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(int*)m_Ptr = Val; } break; case TW_TYPE_UINT32: //case TW_TYPE_ENUM32: { unsigned int Val = (unsigned int)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(unsigned int*)m_Ptr = Val; } break; case TW_TYPE_FLOAT: { float Val = (float)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(float*)m_Ptr = Val; } break; case TW_TYPE_DOUBLE: { double Val = (double)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(double*)m_Ptr = Val; } break; default: if( IsEnumType(m_Type) ) { unsigned int Val = (unsigned int)_Val; if( UseSet ) m_SetCallback(&Val, m_ClientData); else *(unsigned int*)m_Ptr = Val; } } } // --------------------------------------------------------------------------- void CTwVarAtom::MinMaxStepToDouble(double *_Min, double *_Max, double *_Step) const { double max = DOUBLE_MAX; double min = -DOUBLE_MAX; double step = 1; switch( m_Type ) { case TW_TYPE_BOOLCPP: case TW_TYPE_BOOL8: case TW_TYPE_BOOL16: case TW_TYPE_BOOL32: min = 0; max = 1; step = 1; break; case TW_TYPE_CHAR: min = (double)m_Val.m_Char.m_Min; max = (double)m_Val.m_Char.m_Max; step = (double)m_Val.m_Char.m_Step; break; case TW_TYPE_INT8: min = (double)m_Val.m_Int8.m_Min; max = (double)m_Val.m_Int8.m_Max; step = (double)m_Val.m_Int8.m_Step; break; case TW_TYPE_UINT8: min = (double)m_Val.m_UInt8.m_Min; max = (double)m_Val.m_UInt8.m_Max; step = (double)m_Val.m_UInt8.m_Step; break; case TW_TYPE_INT16: min = (double)m_Val.m_Int16.m_Min; max = (double)m_Val.m_Int16.m_Max; step = (double)m_Val.m_Int16.m_Step; break; case TW_TYPE_UINT16: min = (double)m_Val.m_UInt16.m_Min; max = (double)m_Val.m_UInt16.m_Max; step = (double)m_Val.m_UInt16.m_Step; break; case TW_TYPE_INT32: min = (double)m_Val.m_Int32.m_Min; max = (double)m_Val.m_Int32.m_Max; step = (double)m_Val.m_Int32.m_Step; break; case TW_TYPE_UINT32: min = (double)m_Val.m_UInt32.m_Min; max = (double)m_Val.m_UInt32.m_Max; step = (double)m_Val.m_UInt32.m_Step; break; case TW_TYPE_FLOAT: min = (double)m_Val.m_Float32.m_Min; max = (double)m_Val.m_Float32.m_Max; step = (double)m_Val.m_Float32.m_Step; break; case TW_TYPE_DOUBLE: min = m_Val.m_Float64.m_Min; max = m_Val.m_Float64.m_Max; step = m_Val.m_Float64.m_Step; break; default: {} // nothing } if( _Min!=NULL ) *_Min = min; if( _Max!=NULL ) *_Max = max; if( _Step!=NULL ) *_Step = step; } // --------------------------------------------------------------------------- const CTwVar *CTwVarAtom::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) const { if( strcmp(_Name, m_Name.c_str())==0 ) { if( _Parent!=NULL ) *_Parent = NULL; if( _Index!=NULL ) *_Index = -1; return this; } else return NULL; } // --------------------------------------------------------------------------- enum EVarAttribs { V_LABEL = 1, V_HELP, V_GROUP, V_SHOW, V_HIDE, V_READONLY, V_READWRITE, V_ORDER, V_VISIBLE, V_ENDTAG }; int CTwVar::HasAttrib(const char *_Attrib, bool *_HasValue) const { *_HasValue = true; if( _stricmp(_Attrib, "label")==0 ) return V_LABEL; else if( _stricmp(_Attrib, "help")==0 ) return V_HELP; else if( _stricmp(_Attrib, "group")==0 ) return V_GROUP; else if( _stricmp(_Attrib, "order")==0 ) return V_ORDER; else if( _stricmp(_Attrib, "visible")==0 ) return V_VISIBLE; else if( _stricmp(_Attrib, "readonly")==0 ) return V_READONLY; // for backward compatibility *_HasValue = false; if( _stricmp(_Attrib, "show")==0 ) return V_SHOW; else if( _stricmp(_Attrib, "hide")==0 ) return V_HIDE; if( _stricmp(_Attrib, "readonly")==0 ) return V_READONLY; else if( _stricmp(_Attrib, "readwrite")==0 ) return V_READWRITE; return 0; // not found } int CTwVar::SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex) { switch( _AttribID ) { case V_LABEL: case V_HELP: if( _Value && strlen(_Value)>0 ) { /* if( IsGroup() && static_cast(this)->m_StructValuePtr!=NULL ) { int Idx = static_cast(this)->m_StructType-TW_TYPE_STRUCT_BASE; if( Idx>=0 && Idx<(int)g_TwMgr->m_Structs.size() ) if( _AttribID==V_LABEL ) g_TwMgr->m_Structs[Idx].m_Label = _Value; else // V_HELP g_TwMgr->m_Structs[Idx].m_Help = _Value; } else */ { CTwVarGroup *Parent = NULL; CTwVar *ThisVar = _Bar->Find(m_Name.c_str(), &Parent); if( this==ThisVar && Parent!=NULL && Parent->m_StructValuePtr!=NULL ) { int Idx = Parent->m_StructType-TW_TYPE_STRUCT_BASE; if( Idx>=0 && Idx<(int)g_TwMgr->m_Structs.size() ) { size_t nl = m_Name.length(); for( size_t im=0; imm_Structs[Idx].m_Members.size(); ++im ) { size_t ml = g_TwMgr->m_Structs[Idx].m_Members[im].m_Name.length(); if( nl>=ml && strcmp(g_TwMgr->m_Structs[Idx].m_Members[im].m_Name.c_str(), m_Name.c_str()+(nl-ml))==0 ) { // TODO: would have to be applied to other vars already created if( _AttribID==V_LABEL ) { g_TwMgr->m_Structs[Idx].m_Members[im].m_Label = _Value; // m_Label = _Value; } else // V_HELP g_TwMgr->m_Structs[Idx].m_Members[im].m_Help = _Value; break; } } } } else { if( _AttribID==V_LABEL ) m_Label = _Value; else // V_HELP m_Help = _Value; } } _Bar->NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case V_GROUP: { CTwVarGroup *Grp = NULL; if( _Value==NULL || strlen(_Value)<=0 ) Grp = &(_Bar->m_VarRoot); else { CTwVar *v = _Bar->Find(_Value, NULL, NULL); if( v && !v->IsGroup() ) { g_TwMgr->SetLastError(g_ErrNotGroup); return 0; } Grp = static_cast(v); if( Grp==NULL ) { Grp = new CTwVarGroup; Grp->m_Name = _Value; Grp->m_Open = true; Grp->m_SummaryCallback = NULL; Grp->m_SummaryClientData = NULL; Grp->m_StructValuePtr = NULL; Grp->m_ColorPtr = &(_Bar->m_ColGrpText); _Bar->m_VarRoot.m_Vars.push_back(Grp); } } Grp->m_Vars.push_back(this); if( _VarParent!=NULL && _VarIndex>=0 ) { _VarParent->m_Vars.erase(_VarParent->m_Vars.begin()+_VarIndex); if( _VarParent!=&(_Bar->m_VarRoot) && _VarParent->m_Vars.size()<=0 ) TwRemoveVar(_Bar, _VarParent->m_Name.c_str()); } _Bar->NotUpToDate(); return 1; } case V_SHOW: // for backward compatibility if( !m_Visible ) { m_Visible = true; _Bar->NotUpToDate(); } return 1; case V_HIDE: // for backward compatibility if( m_Visible ) { m_Visible = false; _Bar->NotUpToDate(); } return 1; /* case V_READONLY: SetReadOnly(true); _Bar->NotUpToDate(); return 1; */ case V_READWRITE: // for backward compatibility SetReadOnly(false); _Bar->NotUpToDate(); return 1; case V_ORDER: // a special case for compatibility with deprecated command 'option=ogl/dx' if( IsGroup() && _Value!=NULL && static_cast(this)->m_SummaryCallback==CColorExt::SummaryCB && static_cast(this)->m_StructValuePtr!=NULL ) // is tw_type_color? { if( _stricmp(_Value, "ogl")==0 ) { static_cast(static_cast(this)->m_StructValuePtr)->m_OGL = true; return 1; } else if( _stricmp(_Value, "dx")==0 ) { static_cast(static_cast(this)->m_StructValuePtr)->m_OGL = false; return 1; } } // todo: general 'order' command (no else) return 0; case V_VISIBLE: if( _Value!=NULL && strlen(_Value)>0 ) { if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 ) { if( !m_Visible ) { m_Visible = true; _Bar->NotUpToDate(); } return 1; } else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 ) { if( m_Visible ) { m_Visible = false; _Bar->NotUpToDate(); } return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case V_READONLY: if( _Value==NULL || strlen(_Value)==0 // no value is acceptable (for backward compatibility) || _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 ) { if( !IsReadOnly() ) { SetReadOnly(true); _Bar->NotUpToDate(); } return 1; } else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 ) { if( IsReadOnly() ) { SetReadOnly(false); _Bar->NotUpToDate(); } return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } default: g_TwMgr->SetLastError(g_ErrUnknownAttrib); return 0; } } ERetType CTwVar::GetAttrib(int _AttribID, TwBar * /*_Bar*/, CTwVarGroup * _VarParent, int /*_VarIndex*/, std::vector& outDoubles, std::ostringstream& outString) const { outDoubles.clear(); outString.clear(); switch( _AttribID ) { case V_LABEL: outString << m_Label; return RET_STRING; case V_HELP: outString << m_Help; return RET_STRING; case V_GROUP: if( _VarParent!=NULL ) outString << _VarParent->m_Name; return RET_STRING; case V_VISIBLE: outDoubles.push_back(m_Visible ? 1 : 0); return RET_DOUBLE; case V_READONLY: outDoubles.push_back(IsReadOnly() ? 1 : 0); return RET_DOUBLE; default: g_TwMgr->SetLastError(g_ErrUnknownAttrib); return RET_ERROR; } } // --------------------------------------------------------------------------- enum EVarAtomAttribs { VA_KEY_INCR = V_ENDTAG+1, VA_KEY_DECR, VA_MIN, VA_MAX, VA_STEP, VA_PRECISION, VA_HEXA, VA_DECIMAL, // for backward compatibility VA_TRUE, VA_FALSE, VA_ENUM, VA_VALUE }; int CTwVarAtom::HasAttrib(const char *_Attrib, bool *_HasValue) const { *_HasValue = true; if( _stricmp(_Attrib, "keyincr")==0 || _stricmp(_Attrib, "key")==0 ) return VA_KEY_INCR; else if( _stricmp(_Attrib, "keydecr")==0 ) return VA_KEY_DECR; else if( _stricmp(_Attrib, "min")==0 ) return VA_MIN; else if( _stricmp(_Attrib, "max")==0 ) return VA_MAX; else if( _stricmp(_Attrib, "step")==0 ) return VA_STEP; else if( _stricmp(_Attrib, "precision")==0 ) return VA_PRECISION; else if( _stricmp(_Attrib, "hexa")==0 ) return VA_HEXA; else if( _stricmp(_Attrib, "decimal")==0 ) // for backward compatibility { *_HasValue = false; return VA_DECIMAL; } else if( _stricmp(_Attrib, "true")==0 ) return VA_TRUE; else if( _stricmp(_Attrib, "false")==0 ) return VA_FALSE; else if( _stricmp(_Attrib, "enum")==0 || _stricmp(_Attrib, "val")==0 ) // for backward compatibility return VA_ENUM; else if( _stricmp(_Attrib, "value")==0 ) return VA_VALUE; return CTwVar::HasAttrib(_Attrib, _HasValue); } int CTwVarAtom::SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex) { switch( _AttribID ) { case VA_KEY_INCR: { int Key = 0; int Mod = 0; if( TwGetKeyCode(&Key, &Mod, _Value) ) { m_KeyIncr[0] = Key; m_KeyIncr[1] = Mod; return 1; } else return 0; } case VA_KEY_DECR: { int Key = 0; int Mod = 0; if( TwGetKeyCode(&Key, &Mod, _Value) ) { m_KeyDecr[0] = Key; m_KeyDecr[1] = Mod; return 1; } else return 0; } case VA_TRUE: if( (m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP) && _Value!=NULL ) { if( m_Val.m_Bool.m_FreeTrueString && m_Val.m_Bool.m_TrueString!=NULL ) free(m_Val.m_Bool.m_TrueString); m_Val.m_Bool.m_TrueString = _strdup(_Value); m_Val.m_Bool.m_FreeTrueString = true; return 1; } else return 0; case VA_FALSE: if( (m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP) && _Value!=NULL ) { if( m_Val.m_Bool.m_FreeFalseString && m_Val.m_Bool.m_FalseString!=NULL ) free(m_Val.m_Bool.m_FalseString); m_Val.m_Bool.m_FalseString = _strdup(_Value); m_Val.m_Bool.m_FreeFalseString = true; return 1; } else return 0; case VA_MIN: case VA_MAX: case VA_STEP: if( _Value && strlen(_Value)>0 ) { void *Ptr = NULL; const char *Fmt = NULL; int d = 0; unsigned int u = 0; int Num = (_AttribID==VA_STEP) ? 2 : ((_AttribID==VA_MAX) ? 1 : 0); switch( m_Type ) { case TW_TYPE_CHAR: //Ptr = (&m_Val.m_Char.m_Min) + Num; //Fmt = "%c"; Ptr = &u; Fmt = "%u"; break; case TW_TYPE_INT16: Ptr = (&m_Val.m_Int16.m_Min) + Num; Fmt = "%hd"; break; case TW_TYPE_INT32: Ptr = (&m_Val.m_Int32.m_Min) + Num; Fmt = "%d"; break; case TW_TYPE_UINT16: Ptr = (&m_Val.m_UInt16.m_Min) + Num; Fmt = "%hu"; break; case TW_TYPE_UINT32: Ptr = (&m_Val.m_UInt32.m_Min) + Num; Fmt = "%u"; break; case TW_TYPE_FLOAT: Ptr = (&m_Val.m_Float32.m_Min) + Num; Fmt = "%f"; break; case TW_TYPE_DOUBLE: Ptr = (&m_Val.m_Float64.m_Min) + Num; Fmt = "%lf"; break; case TW_TYPE_INT8: Ptr = &d; Fmt = "%d"; break; case TW_TYPE_UINT8: Ptr = &u; Fmt = "%u"; break; default: g_TwMgr->SetLastError(g_ErrUnknownType); return 0; } if( Fmt!=NULL && Ptr!=NULL && sscanf(_Value, Fmt, Ptr)==1 ) { if( m_Type==TW_TYPE_CHAR ) *((&m_Val.m_Char.m_Min)+Num) = (unsigned char)(u); else if( m_Type==TW_TYPE_INT8 ) *((&m_Val.m_Int8.m_Min)+Num) = (signed char)(d); else if( m_Type==TW_TYPE_UINT8 ) *((&m_Val.m_UInt8.m_Min)+Num) = (unsigned char)(u); // set precision if( _AttribID==VA_STEP && ((m_Type==TW_TYPE_FLOAT && m_Val.m_Float32.m_Precision<0) || (m_Type==TW_TYPE_DOUBLE && m_Val.m_Float64.m_Precision<0)) ) { double Step = fabs( (m_Type==TW_TYPE_FLOAT) ? m_Val.m_Float32.m_Step : m_Val.m_Float64.m_Step ); signed char *Precision = (m_Type==TW_TYPE_FLOAT) ? &m_Val.m_Float32.m_Precision : &m_Val.m_Float64.m_Precision; const double K_EPS = 1.0 - 1.0e-6; if( Step>=1 ) *Precision = 0; else if( Step>=0.1*K_EPS ) *Precision = 1; else if( Step>=0.01*K_EPS ) *Precision = 2; else if( Step>=0.001*K_EPS ) *Precision = 3; else if( Step>=0.0001*K_EPS ) *Precision = 4; else if( Step>=0.00001*K_EPS ) *Precision = 5; else if( Step>=0.000001*K_EPS ) *Precision = 6; else if( Step>=0.0000001*K_EPS ) *Precision = 7; else if( Step>=0.00000001*K_EPS ) *Precision = 8; else if( Step>=0.000000001*K_EPS ) *Precision = 9; else if( Step>=0.0000000001*K_EPS ) *Precision = 10; else if( Step>=0.00000000001*K_EPS ) *Precision = 11; else if( Step>=0.000000000001*K_EPS ) *Precision = 12; else *Precision = -1; } return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case VA_PRECISION: if( _Value && strlen(_Value)>0 ) { int Precision = 0; if( sscanf(_Value, "%d", &Precision)==1 && Precision>=-1 && Precision<=12 ) { if( m_Type==TW_TYPE_FLOAT ) m_Val.m_Float32.m_Precision = (signed char)Precision; else if ( m_Type==TW_TYPE_DOUBLE ) m_Val.m_Float64.m_Precision = (signed char)Precision; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case VA_HEXA: case VA_DECIMAL: { bool hexa = false; if (_AttribID==VA_HEXA) { if( _Value==NULL || strlen(_Value)==0 // no value is acceptable (for backward compatibility) || _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 ) hexa = true; } switch( m_Type ) { case TW_TYPE_CHAR: m_Val.m_Char.m_Hexa = hexa; return 1; case TW_TYPE_INT8: m_Val.m_Int8.m_Hexa = hexa; return 1; case TW_TYPE_INT16: m_Val.m_Int16.m_Hexa = hexa; return 1; case TW_TYPE_INT32: m_Val.m_Int32.m_Hexa = hexa; return 1; case TW_TYPE_UINT8: m_Val.m_UInt8.m_Hexa = hexa; return 1; case TW_TYPE_UINT16: m_Val.m_UInt16.m_Hexa = hexa; return 1; case TW_TYPE_UINT32: m_Val.m_UInt32.m_Hexa = hexa; return 1; default: return 0; } } case VA_ENUM: if( _Value && strlen(_Value)>0 && IsEnumType(m_Type) ) { const char *s = _Value; int n = 0, i = 0; unsigned int u; bool Cont; g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.clear(); // anyway reset entries do { Cont = false; i = 0; char Sep; n = sscanf(s, "%u %c%n", &u, &Sep, &i); if( n==2 && i>0 && ( Sep=='<' || Sep=='{' || Sep=='[' || Sep=='(' ) ) { if( Sep=='<' ) // Change to closing separator Sep = '>'; else if( Sep=='{' ) Sep = '}'; else if( Sep=='[' ) Sep = ']'; else if( Sep=='(' ) Sep = ')'; s += i; i = 0; while( s[i]!=Sep && s[i]!=0 ) ++i; if( s[i]==Sep ) { //if( m_Val.m_Enum.m_Entries==NULL ) // m_Val.m_Enum.m_Entries = new UVal::CEnumVal::CEntries; //UVal::CEnumVal::CEntries::value_type v(u, ""); CTwMgr::CEnum::CEntries::value_type v(u, ""); if( i>0 ) v.second.assign(s, i); //m_Val.m_Enum.m_Entries->insert(v); pair ret; ret = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.insert(v); if( !ret.second ) // force overwrite if element already exists { g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.erase(ret.first); g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.insert(v); } s += i+1; i = 0; n = sscanf(s, " ,%n", &i); if( n==0 && i>=1 ) { s += i; Cont = true; } } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } while( Cont ); return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } break; case VA_VALUE: if( _Value!=NULL && strlen(_Value)>0 ) // do not check ReadOnly here. { if( !( m_Type==TW_TYPE_BUTTON || IsCustom() ) ) // || (m_Type>=TW_TYPE_CUSTOM_BASE && m_Typem_Customs.size()) ) ) { if( m_Type==TW_TYPE_CDSTRING || m_Type==TW_TYPE_CDSTDSTRING ) { if( m_SetCallback!=NULL ) { m_SetCallback(&_Value, m_ClientData); if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call _Bar->NotUpToDate(); return 1; } else if( m_Type!=TW_TYPE_CDSTDSTRING ) { char **StringPtr = (char **)m_Ptr; if( StringPtr!=NULL && g_TwMgr->m_CopyCDStringToClient!=NULL ) { g_TwMgr->m_CopyCDStringToClient(StringPtr, _Value); _Bar->NotUpToDate(); return 1; } } } else if( IsCSStringType(m_Type) ) { int n = TW_CSSTRING_SIZE(m_Type); if( n>0 ) { string str = _Value; if( (int)str.length()>n-1 ) str.resize(n-1); if( m_SetCallback!=NULL ) { m_SetCallback(str.c_str(), m_ClientData); if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call _Bar->NotUpToDate(); return 1; } else if( m_Ptr!=NULL ) { if( n>1 ) strncpy((char *)m_Ptr, str.c_str(), n-1); ((char *)m_Ptr)[n-1] = '\0'; _Bar->NotUpToDate(); return 1; } } } else { double dbl; if( sscanf(_Value, "%lf", &dbl)==1 ) { ValueFromDouble(dbl); if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call _Bar->NotUpToDate(); return 1; } } } } return 0; default: return CTwVar::SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex); } } ERetType CTwVarAtom::GetAttrib(int _AttribID, TwBar *_Bar, CTwVarGroup *_VarParent, int _VarIndex, std::vector& outDoubles, std::ostringstream& outString) const { outDoubles.clear(); outString.clear(); std::string str; int num = 0; switch( _AttribID ) { case VA_KEY_INCR: if( TwGetKeyString(&str, m_KeyIncr[0], m_KeyIncr[1]) ) outString << str; return RET_STRING; case VA_KEY_DECR: if( TwGetKeyString(&str, m_KeyDecr[0], m_KeyDecr[1]) ) outString << str; return RET_STRING; case VA_TRUE: if( m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP ) { outString << m_Val.m_Bool.m_TrueString; return RET_STRING; } else { g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; } case VA_FALSE: if( m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP ) { outString << m_Val.m_Bool.m_FalseString; return RET_STRING; } else { g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; } case VA_MIN: case VA_MAX: case VA_STEP: num = (_AttribID==VA_STEP) ? 2 : ((_AttribID==VA_MAX) ? 1 : 0); switch( m_Type ) { case TW_TYPE_CHAR: outDoubles.push_back( *((&m_Val.m_Char.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_INT8: outDoubles.push_back( *((&m_Val.m_Int8.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_UINT8: outDoubles.push_back( *((&m_Val.m_UInt8.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_INT16: outDoubles.push_back( *((&m_Val.m_Int16.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_INT32: outDoubles.push_back( *((&m_Val.m_Int32.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_UINT16: outDoubles.push_back( *((&m_Val.m_UInt16.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_UINT32: outDoubles.push_back( *((&m_Val.m_UInt32.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_FLOAT: outDoubles.push_back( *((&m_Val.m_Float32.m_Min) + num) ); return RET_DOUBLE; case TW_TYPE_DOUBLE: outDoubles.push_back( *((&m_Val.m_Float64.m_Min) + num) ); return RET_DOUBLE; default: g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; } case VA_PRECISION: if( m_Type==TW_TYPE_FLOAT ) { outDoubles.push_back( m_Val.m_Float32.m_Precision ); return RET_DOUBLE; } else if ( m_Type==TW_TYPE_DOUBLE ) { outDoubles.push_back( m_Val.m_Float64.m_Precision ); return RET_DOUBLE; } else { g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; } case VA_HEXA: switch( m_Type ) { case TW_TYPE_CHAR: outDoubles.push_back( m_Val.m_Char.m_Hexa ); return RET_DOUBLE; case TW_TYPE_INT8: outDoubles.push_back( m_Val.m_Int8.m_Hexa ); return RET_DOUBLE; case TW_TYPE_INT16: outDoubles.push_back( m_Val.m_Int16.m_Hexa ); return RET_DOUBLE; case TW_TYPE_INT32: outDoubles.push_back( m_Val.m_Int32.m_Hexa ); return RET_DOUBLE; case TW_TYPE_UINT8: outDoubles.push_back( m_Val.m_UInt8.m_Hexa ); return RET_DOUBLE; case TW_TYPE_UINT16: outDoubles.push_back( m_Val.m_UInt16.m_Hexa ); return RET_DOUBLE; case TW_TYPE_UINT32: outDoubles.push_back( m_Val.m_UInt32.m_Hexa ); return RET_DOUBLE; default: g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; } case VA_ENUM: if( IsEnumType(m_Type) ) { CTwMgr::CEnum::CEntries::iterator it = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.begin(); for( ; it != g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.end(); ++it ) { if( it != g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.begin() ) outString << ','; outString << it->first << ' '; if( it->second.find_first_of("{}")==std::string::npos ) outString << '{' << it->second << '}'; else if ( it->second.find_first_of("<>")==std::string::npos ) outString << '<' << it->second << '>'; else if ( it->second.find_first_of("()")==std::string::npos ) outString << '(' << it->second << ')'; else if ( it->second.find_first_of("[]")==std::string::npos ) outString << '[' << it->second << ']'; else outString << '{' << it->second << '}'; // should not occured (use braces) } return RET_STRING; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; case VA_VALUE: if( !( m_Type==TW_TYPE_BUTTON || IsCustom() ) ) // || (m_Type>=TW_TYPE_CUSTOM_BASE && m_Typem_Customs.size()) ) ) { if( m_Type==TW_TYPE_CDSTRING || m_Type==TW_TYPE_CDSTDSTRING || IsCSStringType(m_Type) ) { string str; ValueToString(&str); outString << str; return RET_STRING; } else { outDoubles.push_back( ValueToDouble() ); return RET_DOUBLE; } } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; default: return CTwVar::GetAttrib(_AttribID, _Bar, _VarParent, _VarIndex, outDoubles, outString); } } // --------------------------------------------------------------------------- void CTwVarAtom::Increment(int _Step) { if( _Step==0 ) return; switch( m_Type ) { case TW_TYPE_BOOL8: { char v = false; if( m_Ptr!=NULL ) v = *((char *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); if( v ) v = false; else v = true; if( m_Ptr!=NULL ) *((char *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_BOOL16: { short v = false; if( m_Ptr!=NULL ) v = *((short *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); if( v ) v = false; else v = true; if( m_Ptr!=NULL ) *((short *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_BOOL32: { int v = false; if( m_Ptr!=NULL ) v = *((int *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); if( v ) v = false; else v = true; if( m_Ptr!=NULL ) *((int *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_BOOLCPP: { bool v = false; if( m_Ptr!=NULL ) v = *((bool *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); if( v ) v = false; else v = true; if( m_Ptr!=NULL ) *((bool *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_CHAR: { unsigned char v = 0; if( m_Ptr!=NULL ) v = *((unsigned char *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); int iv = _Step*(int)m_Val.m_Char.m_Step + (int)v; if( ivm_Val.m_Char.m_Max ) iv = m_Val.m_Char.m_Max; if( iv<0 ) iv = 0; else if( iv>0xff ) iv = 0xff; v = (unsigned char)iv; if( m_Ptr!=NULL ) *((unsigned char *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_INT8: { signed char v = 0; if( m_Ptr!=NULL ) v = *((signed char *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); int iv = _Step*(int)m_Val.m_Int8.m_Step + (int)v; if( ivm_Val.m_Int8.m_Max ) iv = m_Val.m_Int8.m_Max; v = (signed char)iv; if( m_Ptr!=NULL ) *((signed char *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_UINT8: { unsigned char v = 0; if( m_Ptr!=NULL ) v = *((unsigned char *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); int iv = _Step*(int)m_Val.m_UInt8.m_Step + (int)v; if( ivm_Val.m_UInt8.m_Max ) iv = m_Val.m_UInt8.m_Max; if( iv<0 ) iv = 0; else if( iv>0xff ) iv = 0xff; v = (unsigned char)iv; if( m_Ptr!=NULL ) *((unsigned char *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_INT16: { short v = 0; if( m_Ptr!=NULL ) v = *((short *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); int iv = _Step*(int)m_Val.m_Int16.m_Step + (int)v; if( ivm_Val.m_Int16.m_Max ) iv = m_Val.m_Int16.m_Max; v = (short)iv; if( m_Ptr!=NULL ) *((short *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_UINT16: { unsigned short v = 0; if( m_Ptr!=NULL ) v = *((unsigned short *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); int iv = _Step*(int)m_Val.m_UInt16.m_Step + (int)v; if( ivm_Val.m_UInt16.m_Max ) iv = m_Val.m_UInt16.m_Max; if( iv<0 ) iv = 0; else if( iv>0xffff ) iv = 0xffff; v = (unsigned short)iv; if( m_Ptr!=NULL ) *((unsigned short *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_INT32: { int v = 0; if( m_Ptr!=NULL ) v = *((int *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); double dv = (double)_Step*(double)m_Val.m_Int32.m_Step + (double)v; if( dv>(double)0x7fffffff ) v = 0x7fffffff; else if( dv<(double)(-0x7fffffff-1) ) v = -0x7fffffff-1; else v = _Step*m_Val.m_Int32.m_Step + v; if( vm_Val.m_Int32.m_Max ) v = m_Val.m_Int32.m_Max; if( m_Ptr!=NULL ) *((int *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_UINT32: { unsigned int v = 0; if( m_Ptr!=NULL ) v = *((unsigned int *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); double dv = (double)_Step*(double)m_Val.m_UInt32.m_Step + (double)v; if( dv>(double)0xffffffff ) v = 0xffffffff; else if( dv<0 ) v = 0; else v = _Step*m_Val.m_UInt32.m_Step + v; if( vm_Val.m_UInt32.m_Max ) v = m_Val.m_UInt32.m_Max; if( m_Ptr!=NULL ) *((unsigned int *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_FLOAT: { float v = 0; if( m_Ptr!=NULL ) v = *((float *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); v += _Step*m_Val.m_Float32.m_Step; if( vm_Val.m_Float32.m_Max ) v = m_Val.m_Float32.m_Max; if( m_Ptr!=NULL ) *((float *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; case TW_TYPE_DOUBLE: { double v = 0; if( m_Ptr!=NULL ) v = *((double *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); v += _Step*m_Val.m_Float64.m_Step; if( vm_Val.m_Float64.m_Max ) v = m_Val.m_Float64.m_Max; if( m_Ptr!=NULL ) *((double *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } break; /* case TW_TYPE_ENUM8: { assert(_Step==1 || _Step==-1); unsigned char v = 0; if( m_Ptr!=NULL ) v = *((unsigned char *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); if( m_Val.m_Enum.m_Entries!=NULL ) { UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(v); if( It==m_Val.m_Enum.m_Entries->end() ) It = m_Val.m_Enum.m_Entries->begin(); else if( _Step==1 ) { ++It; if( It==m_Val.m_Enum.m_Entries->end() ) It = m_Val.m_Enum.m_Entries->begin(); } else if( _Step==-1 ) { if( It==m_Val.m_Enum.m_Entries->begin() ) It = m_Val.m_Enum.m_Entries->end(); if( It!=m_Val.m_Enum.m_Entries->begin() ) --It; } if( It != m_Val.m_Enum.m_Entries->end() ) { v = (unsigned char)(It->first); if( m_Ptr!=NULL ) *((unsigned char *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } } } break; case TW_TYPE_ENUM16: { assert(_Step==1 || _Step==-1); unsigned short v = 0; if( m_Ptr!=NULL ) v = *((unsigned short *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); if( m_Val.m_Enum.m_Entries!=NULL ) { UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(v); if( It==m_Val.m_Enum.m_Entries->end() ) It = m_Val.m_Enum.m_Entries->begin(); else if( _Step==1 ) { ++It; if( It==m_Val.m_Enum.m_Entries->end() ) It = m_Val.m_Enum.m_Entries->begin(); } else if( _Step==-1 ) { if( It==m_Val.m_Enum.m_Entries->begin() ) It = m_Val.m_Enum.m_Entries->end(); if( It!=m_Val.m_Enum.m_Entries->begin() ) --It; } if( It != m_Val.m_Enum.m_Entries->end() ) { v = (unsigned short)(It->first); if( m_Ptr!=NULL ) *((unsigned short *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } } } break; case TW_TYPE_ENUM32: { assert(_Step==1 || _Step==-1); unsigned int v = 0; if( m_Ptr!=NULL ) v = *((unsigned int *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); if( m_Val.m_Enum.m_Entries!=NULL ) { UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(v); if( It==m_Val.m_Enum.m_Entries->end() ) It = m_Val.m_Enum.m_Entries->begin(); else if( _Step==1 ) { ++It; if( It==m_Val.m_Enum.m_Entries->end() ) It = m_Val.m_Enum.m_Entries->begin(); } else if( _Step==-1 ) { if( It==m_Val.m_Enum.m_Entries->begin() ) It = m_Val.m_Enum.m_Entries->end(); if( It!=m_Val.m_Enum.m_Entries->begin() ) --It; } if( It!=m_Val.m_Enum.m_Entries->end() ) { v = (unsigned int)(It->first); if( m_Ptr!=NULL ) *((unsigned int *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } } } break; */ default: if( m_Type==TW_TYPE_BUTTON ) { if( m_Val.m_Button.m_Callback!=NULL ) { m_Val.m_Button.m_Callback(m_ClientData); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return; } } else if( IsEnumType(m_Type) ) { assert(_Step==1 || _Step==-1); unsigned int v = 0; if( m_Ptr!=NULL ) v = *((unsigned int *)m_Ptr); else if( m_GetCallback!=NULL ) m_GetCallback(&v, m_ClientData); CTwMgr::CEnum& e = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE]; CTwMgr::CEnum::CEntries::iterator It = e.m_Entries.find(v); if( It==e.m_Entries.end() ) It = e.m_Entries.begin(); else if( _Step==1 ) { ++It; if( It==e.m_Entries.end() ) It = e.m_Entries.begin(); } else if( _Step==-1 ) { if( It==e.m_Entries.begin() ) It = e.m_Entries.end(); if( It!=e.m_Entries.begin() ) --It; } if( It!=e.m_Entries.end() ) { v = (unsigned int)(It->first); if( m_Ptr!=NULL ) *((unsigned int *)m_Ptr) = v; else if( m_SetCallback!=NULL ) m_SetCallback(&v, m_ClientData); } } else fprintf(stderr, "CTwVarAtom::Increment : unknown or unimplemented type\n"); } } // --------------------------------------------------------------------------- void CTwVarAtom::SetDefaults() { switch( m_Type ) { case TW_TYPE_BOOL8: case TW_TYPE_BOOL16: case TW_TYPE_BOOL32: case TW_TYPE_BOOLCPP: m_NoSlider = true; break; case TW_TYPE_CHAR: m_Val.m_Char.m_Max = 0xff; m_Val.m_Char.m_Min = 0; m_Val.m_Char.m_Step = 1; m_Val.m_Char.m_Precision = -1; m_Val.m_Char.m_Hexa = false; break; case TW_TYPE_INT8: m_Val.m_Int8.m_Max = 0x7f; m_Val.m_Int8.m_Min = -m_Val.m_Int8.m_Max-1; m_Val.m_Int8.m_Step = 1; m_Val.m_Int8.m_Precision = -1; m_Val.m_Int8.m_Hexa = false; break; case TW_TYPE_UINT8: m_Val.m_UInt8.m_Max = 0xff; m_Val.m_UInt8.m_Min = 0; m_Val.m_UInt8.m_Step = 1; m_Val.m_UInt8.m_Precision = -1; m_Val.m_UInt8.m_Hexa = false; break; case TW_TYPE_INT16: m_Val.m_Int16.m_Max = 0x7fff; m_Val.m_Int16.m_Min = -m_Val.m_Int16.m_Max-1; m_Val.m_Int16.m_Step = 1; m_Val.m_Int16.m_Precision = -1; m_Val.m_Int16.m_Hexa = false; break; case TW_TYPE_UINT16: m_Val.m_UInt16.m_Max = 0xffff; m_Val.m_UInt16.m_Min = 0; m_Val.m_UInt16.m_Step = 1; m_Val.m_UInt16.m_Precision = -1; m_Val.m_UInt16.m_Hexa = false; break; case TW_TYPE_INT32: m_Val.m_Int32.m_Max = 0x7fffffff; m_Val.m_Int32.m_Min = -m_Val.m_Int32.m_Max-1; m_Val.m_Int32.m_Step = 1; m_Val.m_Int32.m_Precision = -1; m_Val.m_Int32.m_Hexa = false; break; case TW_TYPE_UINT32: m_Val.m_UInt32.m_Max = 0xffffffff; m_Val.m_UInt32.m_Min = 0; m_Val.m_UInt32.m_Step = 1; m_Val.m_UInt32.m_Precision = -1; m_Val.m_UInt32.m_Hexa = false; break; case TW_TYPE_FLOAT: m_Val.m_Float32.m_Max = FLOAT_MAX; m_Val.m_Float32.m_Min = -FLOAT_MAX; m_Val.m_Float32.m_Step = 1; m_Val.m_Float32.m_Precision = -1; m_Val.m_Float32.m_Hexa = false; break; case TW_TYPE_DOUBLE: m_Val.m_Float64.m_Max = DOUBLE_MAX; m_Val.m_Float64.m_Min = -DOUBLE_MAX; m_Val.m_Float64.m_Step = 1; m_Val.m_Float64.m_Precision = -1; m_Val.m_Float64.m_Hexa = false; break; case TW_TYPE_CDSTRING: case TW_TYPE_STDSTRING: m_NoSlider = true; break; /* case TW_TYPE_ENUM8: case TW_TYPE_ENUM16: case TW_TYPE_ENUM32: m_NoSlider = true; break; */ default: {} // nothing } // special types if( m_Type==TW_TYPE_BUTTON || IsEnumType(m_Type) // (m_Type>=TW_TYPE_ENUM_BASE && m_Typem_Enums.size()) || IsCSStringType(m_Type) // (m_Type>=TW_TYPE_CSSTRING_BASE && m_Type<=TW_TYPE_CSSTRING_MAX) || m_Type==TW_TYPE_CDSTDSTRING || IsCustom() ) // (m_Type>=TW_TYPE_CUSTOM_BASE && m_Typem_Customs.size()) ) m_NoSlider = true; } // --------------------------------------------------------------------------- /* int CTwVarAtom::DefineEnum(const TwEnumVal *_EnumValues, unsigned int _NbValues) { assert(_EnumValues!=NULL); if( m_Type!=TW_TYPE_ENUM8 && m_Type!=TW_TYPE_ENUM16 && m_Type!=TW_TYPE_ENUM32 ) { g_TwMgr->SetLastError(g_ErrNotEnum); return 0; } if( m_Val.m_Enum.m_Entries==NULL ) m_Val.m_Enum.m_Entries = new UVal::CEnumVal::CEntries; for(unsigned int i=0; i<_NbValues; ++i) { UVal::CEnumVal::CEntries::value_type Entry(_EnumValues[i].Value, (_EnumValues[i].Label!=NULL)?_EnumValues[i].Label:""); pair Result = m_Val.m_Enum.m_Entries->insert(Entry); if( !Result.second ) (Result.first)->second = Entry.second; } return 1; } */ // --------------------------------------------------------------------------- enum EVarGroupAttribs { VG_OPEN = V_ENDTAG+1, // for backward compatibility VG_CLOSE, // for backward compatibility VG_OPENED, VG_TYPEID, // used internally for structs VG_VALPTR, // used internally for structs VG_ALPHA, // for backward compatibility VG_NOALPHA, // for backward compatibility VG_COLORALPHA, // tw_type_color* only VG_HLS, // for backward compatibility VG_RGB, // for backward compatibility VG_COLORMODE, // tw_type_color* only VG_COLORORDER, // tw_type_color* only VG_ARROW, // tw_type_quat* only VG_ARROWCOLOR, // tw_type_quat* only VG_AXISX, // tw_type_quat* only VG_AXISY, // tw_type_quat* only VG_AXISZ, // tw_type_quat* only VG_SHOWVAL // tw_type_quat* only }; int CTwVarGroup::HasAttrib(const char *_Attrib, bool *_HasValue) const { *_HasValue = false; if( _stricmp(_Attrib, "open")==0 ) // for backward compatibility return VG_OPEN; else if( _stricmp(_Attrib, "close")==0 ) // for backward compatibility return VG_CLOSE; else if( _stricmp(_Attrib, "opened")==0 ) { *_HasValue = true; return VG_OPENED; } else if( _stricmp(_Attrib, "typeid")==0 ) { *_HasValue = true; return VG_TYPEID; } else if( _stricmp(_Attrib, "valptr")==0 ) { *_HasValue = true; return VG_VALPTR; } else if( _stricmp(_Attrib, "alpha")==0 ) // for backward compatibility return VG_ALPHA; else if( _stricmp(_Attrib, "noalpha")==0 ) // for backward compatibility return VG_NOALPHA; else if( _stricmp(_Attrib, "coloralpha")==0 ) { *_HasValue = true; return VG_COLORALPHA; } else if( _stricmp(_Attrib, "hls")==0 ) // for backward compatibility return VG_HLS; else if( _stricmp(_Attrib, "rgb")==0 ) // for backward compatibility return VG_RGB; else if( _stricmp(_Attrib, "colormode")==0 ) { *_HasValue = true; return VG_COLORMODE; } else if( _stricmp(_Attrib, "colororder")==0 ) { *_HasValue = true; return VG_COLORORDER; } else if( _stricmp(_Attrib, "arrow")==0 ) { *_HasValue = true; return VG_ARROW; } else if( _stricmp(_Attrib, "arrowcolor")==0 ) { *_HasValue = true; return VG_ARROWCOLOR; } else if( _stricmp(_Attrib, "axisx")==0 ) { *_HasValue = true; return VG_AXISX; } else if( _stricmp(_Attrib, "axisy")==0 ) { *_HasValue = true; return VG_AXISY; } else if( _stricmp(_Attrib, "axisz")==0 ) { *_HasValue = true; return VG_AXISZ; } else if( _stricmp(_Attrib, "showval")==0 ) { *_HasValue = true; return VG_SHOWVAL; } return CTwVar::HasAttrib(_Attrib, _HasValue); } int CTwVarGroup::SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex) { switch( _AttribID ) { case VG_OPEN: // for backward compatibility if( !m_Open ) { m_Open = true; _Bar->NotUpToDate(); } return 1; case VG_CLOSE: // for backward compatibility if( m_Open ) { m_Open = false; _Bar->NotUpToDate(); } return 1; case VG_OPENED: if( _Value!=NULL && strlen(_Value)>0 ) { if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 ) { if( !m_Open ) { m_Open = true; _Bar->NotUpToDate(); } return 1; } else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 ) { if( m_Open ) { m_Open = false; _Bar->NotUpToDate(); } return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case VG_TYPEID: { int type = TW_TYPE_UNDEF; if( _Value!=NULL && sscanf(_Value, "%d", &type)==1 ) { int idx = type - TW_TYPE_STRUCT_BASE; if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() ) { m_SummaryCallback = g_TwMgr->m_Structs[idx].m_SummaryCallback; m_SummaryClientData = g_TwMgr->m_Structs[idx].m_SummaryClientData; m_StructType = (TwType)type; return 1; } } return 0; } case VG_VALPTR: { void *structValuePtr = NULL; if( _Value!=NULL && sscanf(_Value, "%p", &structValuePtr)==1 ) { m_StructValuePtr = structValuePtr; m_ColorPtr = &(_Bar->m_ColStructText); return 1; } return 0; } case VG_ALPHA: // for backward compatibility if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? if( static_cast(m_StructValuePtr)->m_CanHaveAlpha ) { static_cast(m_StructValuePtr)->m_HasAlpha = true; _Bar->NotUpToDate(); return 1; } return 0; case VG_NOALPHA: // for backward compatibility if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { static_cast(m_StructValuePtr)->m_HasAlpha = false; _Bar->NotUpToDate(); return 1; } else return 0; case VG_COLORALPHA: if( _Value!=NULL && strlen(_Value)>0 ) { if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 ) { if( static_cast(m_StructValuePtr)->m_CanHaveAlpha ) { if( !static_cast(m_StructValuePtr)->m_HasAlpha ) { static_cast(m_StructValuePtr)->m_HasAlpha = true; _Bar->NotUpToDate(); } return 1; } } else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 ) { if( static_cast(m_StructValuePtr)->m_HasAlpha ) { static_cast(m_StructValuePtr)->m_HasAlpha = false; _Bar->NotUpToDate(); } return 1; } } } return 0; case VG_HLS: // for backward compatibility if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { static_cast(m_StructValuePtr)->m_HLS = true; _Bar->NotUpToDate(); return 1; } else return 0; case VG_RGB: // for backward compatibility if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { static_cast(m_StructValuePtr)->m_HLS = false; _Bar->NotUpToDate(); return 1; } else return 0; case VG_COLORMODE: if( _Value!=NULL && strlen(_Value)>0 ) { if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { if( _stricmp(_Value, "hls")==0 ) { if( !static_cast(m_StructValuePtr)->m_HLS ) { static_cast(m_StructValuePtr)->m_HLS = true; _Bar->NotUpToDate(); } return 1; } else if( _stricmp(_Value, "rgb")==0 ) { if( static_cast(m_StructValuePtr)->m_HLS ) { static_cast(m_StructValuePtr)->m_HLS = false; _Bar->NotUpToDate(); } return 1; } } } return 0; case VG_COLORORDER: if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { if( _Value!=NULL ) { if( _stricmp(_Value, "rgba")==0 ) static_cast(m_StructValuePtr)->m_OGL = true; else if( _stricmp(_Value, "argb")==0 ) static_cast(m_StructValuePtr)->m_OGL = false; else return 0; return 1; } return 0; } else return 0; case VG_ARROW: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { if( _Value!=NULL ) { double *dir = static_cast(m_StructValuePtr)->m_Dir; double x, y, z; if( sscanf(_Value, "%lf %lf %lf", &x, &y, &z)==3 ) { dir[0] = x; dir[1] = y; dir[2] = z; } else if( _stricmp(_Value, "off")==0 || _stricmp(_Value, "0")==0 ) dir[0] = dir[1] = dir[2] = 0; else return 0; return 1; } return 0; } else return 0; case VG_ARROWCOLOR: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { if( _Value!=NULL ) { int r, g, b; if( sscanf(_Value, "%d %d %d", &r, &g, &b)==3 ) static_cast(m_StructValuePtr)->m_DirColor = Color32FromARGBi(255, r, g, b); else return 0; return 1; } return 0; } else return 0; case VG_AXISX: case VG_AXISY: case VG_AXISZ: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { if( _Value!=NULL ) { float x = 0, y = 0, z = 0; if( _stricmp(_Value, "x")==0 || _stricmp(_Value, "+x")==0 ) x = 1; else if( _stricmp(_Value, "-x")==0 ) x = -1; else if( _stricmp(_Value, "y")==0 || _stricmp(_Value, "+y")==0 ) y = 1; else if( _stricmp(_Value, "-y")==0 ) y = -1; else if( _stricmp(_Value, "z")==0 || _stricmp(_Value, "+z")==0 ) z = 1; else if( _stricmp(_Value, "-z")==0 ) z = -1; else return 0; int i = (_AttribID==VG_AXISX) ? 0 : ((_AttribID==VG_AXISY) ? 1 : 2); static_cast(m_StructValuePtr)->m_Permute[i][0] = x; static_cast(m_StructValuePtr)->m_Permute[i][1] = y; static_cast(m_StructValuePtr)->m_Permute[i][2] = z; return 1; } return 0; } else return 0; case VG_SHOWVAL: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { if( _Value!=NULL ) { if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "on")==0 || _stricmp(_Value, "1")==0 ) { static_cast(m_StructValuePtr)->m_ShowVal = true; _Bar->NotUpToDate(); return 1; } else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "off")==0 || _stricmp(_Value, "0")==0 ) { static_cast(m_StructValuePtr)->m_ShowVal = false; _Bar->NotUpToDate(); return 1; } } return 0; } else return 0; default: return CTwVar::SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex); } } ERetType CTwVarGroup::GetAttrib(int _AttribID, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex, std::vector& outDoubles, std::ostringstream& outString) const { outDoubles.clear(); outString.clear(); switch( _AttribID ) { case VG_OPENED: outDoubles.push_back( m_Open ); return RET_DOUBLE; case VG_COLORALPHA: if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { outDoubles.push_back( static_cast(m_StructValuePtr)->m_HasAlpha ); return RET_DOUBLE; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; case VG_COLORMODE: if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { if( static_cast(m_StructValuePtr)->m_HLS ) outString << "hls"; else outString << "rgb"; return RET_STRING; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; case VG_COLORORDER: if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color? { if( static_cast(m_StructValuePtr)->m_OGL ) outString << "rgba"; else outString << "argb"; return RET_STRING; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; case VG_ARROW: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { double *dir = static_cast(m_StructValuePtr)->m_Dir; outDoubles.push_back(dir[0]); outDoubles.push_back(dir[1]); outDoubles.push_back(dir[2]); return RET_DOUBLE; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; case VG_ARROWCOLOR: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { int a, r, g, b; a = r = g = b = 0; Color32ToARGBi(static_cast(m_StructValuePtr)->m_DirColor, &a, &r, &g, &b); outDoubles.push_back(r); outDoubles.push_back(g); outDoubles.push_back(b); return RET_DOUBLE; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; case VG_AXISX: case VG_AXISY: case VG_AXISZ: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { int i = (_AttribID==VG_AXISX) ? 0 : ((_AttribID==VG_AXISY) ? 1 : 2); float x = static_cast(m_StructValuePtr)->m_Permute[i][0]; float y = static_cast(m_StructValuePtr)->m_Permute[i][1]; float z = static_cast(m_StructValuePtr)->m_Permute[i][2]; if( x>0 ) outString << "+x"; else if( x<0 ) outString << "-x"; else if( y>0 ) outString << "+y"; else if( y<0 ) outString << "-y"; else if( z>0 ) outString << "+z"; else if( z<0 ) outString << "-z"; else outString << "0"; // should not happened return RET_DOUBLE; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; case VG_SHOWVAL: if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat? { outDoubles.push_back( static_cast(m_StructValuePtr)->m_ShowVal ); return RET_DOUBLE; } g_TwMgr->SetLastError(g_ErrInvalidAttrib); return RET_ERROR; default: return CTwVar::GetAttrib(_AttribID, _Bar, _VarParent, _VarIndex, outDoubles, outString); } } // --------------------------------------------------------------------------- const CTwVar *CTwVarGroup::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) const { if( strcmp(_Name, m_Name.c_str())==0 ) { if( _Parent!=NULL ) *_Parent = NULL; if( _Index!=NULL ) *_Index = -1; return this; } else { const CTwVar *v; for( size_t i=0; iFind(_Name, _Parent, _Index); if( v!=NULL ) { if( _Parent!=NULL && *_Parent==NULL ) { *_Parent = const_cast(this); if( _Index!=NULL ) *_Index = (int)i; } return v; } } return NULL; } } // --------------------------------------------------------------------------- size_t CTwVar::GetDataSize(TwType _Type) { switch( _Type ) { case TW_TYPE_BOOLCPP: return sizeof(bool); case TW_TYPE_BOOL8: case TW_TYPE_CHAR: case TW_TYPE_INT8: case TW_TYPE_UINT8: //case TW_TYPE_ENUM8: return 1; case TW_TYPE_BOOL16: case TW_TYPE_INT16: case TW_TYPE_UINT16: //case TW_TYPE_ENUM16: return 2; case TW_TYPE_BOOL32: case TW_TYPE_INT32: case TW_TYPE_UINT32: case TW_TYPE_FLOAT: //case TW_TYPE_ENUM32: return 4; case TW_TYPE_DOUBLE: return 8; case TW_TYPE_CDSTRING: return sizeof(char *); case TW_TYPE_STDSTRING: return (g_TwMgr!=0) ? g_TwMgr->m_ClientStdStringStructSize : sizeof(std::string); default: if( g_TwMgr && _Type>=TW_TYPE_STRUCT_BASE && _Typem_Structs.size() ) { const CTwMgr::CStruct& s = g_TwMgr->m_Structs[_Type-TW_TYPE_STRUCT_BASE]; return s.m_Size; /* size_t size = 0; for( size_t i=0; im_ClientStdStringStructSize : sizeof(std::string); else // includes TW_TYPE_BUTTON return 0; } } // --------------------------------------------------------------------------- CTwBar::CTwBar(const char *_Name) { assert(g_TwMgr!=NULL && g_TwMgr->m_Graph!=NULL); m_Name = _Name; m_Visible = true; m_VarRoot.m_IsRoot = true; m_VarRoot.m_Open = true; m_VarRoot.m_SummaryCallback = NULL; m_VarRoot.m_SummaryClientData = NULL; m_VarRoot.m_StructValuePtr = NULL; m_UpToDate = false; int n = (int)g_TwMgr->m_Bars.size(); m_PosX = 24*n-8; m_PosY = 24*n-8; m_Width = 200; m_Height = 320; int cr, cg, cb; if( g_TwMgr->m_UseOldColorScheme ) { ColorHLSToRGBi(g_TwMgr->m_BarInitColorHue%256, 180, 200, &cr, &cg, &cb); m_Color = Color32FromARGBi(0xf0, cr, cg, cb); m_DarkText = true; } else { ColorHLSToRGBi(g_TwMgr->m_BarInitColorHue%256, 80, 200, &cr, &cg, &cb); m_Color = Color32FromARGBi(64, cr, cg, cb); m_DarkText = false; } g_TwMgr->m_BarInitColorHue -= 16; if( g_TwMgr->m_BarInitColorHue<0 ) g_TwMgr->m_BarInitColorHue += 256; m_Font = g_TwMgr->m_CurrentFont; //m_Font = g_DefaultNormalFont; //m_Font = g_DefaultSmallFont; //m_Font = g_DefaultLargeFont; m_TitleWidth = 0; m_Sep = 1; m_ValuesWidth = 10*(m_Font->m_CharHeight/2); // about 10 characters m_NbHierLines = 0; m_NbDisplayedLines = 0; m_FirstLine = 0; m_LastUpdateTime = 0; m_UpdatePeriod = 2; m_ScrollYW = 0; m_ScrollYH = 0; m_ScrollY0 = 0; m_ScrollY1 = 0; m_DrawHandles = false; m_DrawIncrDecrBtn = false; m_DrawRotoBtn = false; m_DrawClickBtn = false; m_DrawListBtn = false; m_DrawBoolBtn = false; m_MouseDrag = false; m_MouseDragVar = false; m_MouseDragTitle = false; m_MouseDragScroll = false; m_MouseDragResizeUR = false; m_MouseDragResizeUL = false; m_MouseDragResizeLR = false; m_MouseDragResizeLL = false; m_MouseDragValWidth = false; m_MouseOriginX = 0; m_MouseOriginY = 0; m_ValuesWidthRatio = 0; m_VarHasBeenIncr = true; m_FirstLine0 = 0; m_HighlightedLine = -1; m_HighlightedLinePrev = -1; m_HighlightedLineLastValid = -1; m_HighlightIncrBtn = false; m_HighlightDecrBtn = false; m_HighlightRotoBtn = false; m_HighlightClickBtn = false; m_HighlightClickBtnAuto = 0; m_HighlightListBtn = false; m_HighlightBoolBtn = false; m_HighlightTitle = false; m_HighlightScroll = false; m_HighlightUpScroll = false; m_HighlightDnScroll = false; m_HighlightMinimize = false; m_HighlightFont = false; m_HighlightValWidth = false; m_HighlightLabelsHeader = false; m_HighlightValuesHeader = false; m_ButtonAlign = g_TwMgr->m_ButtonAlign; m_IsMinimized = false; m_MinNumber = 0; m_MinPosX = 0; m_MinPosY = 0; m_HighlightMaximize = false; m_IsHelpBar = false; m_IsPopupList = false; m_VarEnumLinkedToPopupList = NULL; m_BarLinkedToPopupList = NULL; m_Resizable = true; m_Movable = true; m_Iconifiable = true; m_Contained = g_TwMgr->m_Contained; m_TitleTextObj = g_TwMgr->m_Graph->NewTextObj(); m_LabelsTextObj = g_TwMgr->m_Graph->NewTextObj(); m_ValuesTextObj = g_TwMgr->m_Graph->NewTextObj(); m_ShortcutTextObj = g_TwMgr->m_Graph->NewTextObj(); m_HeadersTextObj = g_TwMgr->m_Graph->NewTextObj(); m_ShortcutLine = -1; m_RotoMinRadius = 24; m_RotoNbSubdiv = 256; // number of steps for one turn m_CustomActiveStructProxy = NULL; UpdateColors(); NotUpToDate(); } // --------------------------------------------------------------------------- CTwBar::~CTwBar() { if( m_IsMinimized ) g_TwMgr->Maximize(this); if( m_TitleTextObj ) g_TwMgr->m_Graph->DeleteTextObj(m_TitleTextObj); if( m_LabelsTextObj ) g_TwMgr->m_Graph->DeleteTextObj(m_LabelsTextObj); if( m_ValuesTextObj ) g_TwMgr->m_Graph->DeleteTextObj(m_ValuesTextObj); if( m_ShortcutTextObj ) g_TwMgr->m_Graph->DeleteTextObj(m_ShortcutTextObj); if( m_HeadersTextObj ) g_TwMgr->m_Graph->DeleteTextObj(m_HeadersTextObj); } // --------------------------------------------------------------------------- const CTwVar *CTwBar::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) const { return m_VarRoot.Find(_Name, _Parent, _Index); } CTwVar *CTwBar::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) { return const_cast(const_cast(this)->Find(_Name, _Parent, _Index)); } // --------------------------------------------------------------------------- enum EBarAttribs { BAR_LABEL = 1, BAR_HELP, BAR_COLOR, BAR_ALPHA, BAR_TEXT, BAR_SHOW, // deprecated, used BAR_VISIBLE instead BAR_HIDE, // deprecated, used BAR_VISIBLE instead BAR_ICONIFY, // deprecated, used BAR_ICONIFIED instead BAR_VISIBLE, BAR_ICONIFIED, BAR_SIZE, BAR_POSITION, BAR_REFRESH, BAR_FONT_SIZE, BAR_VALUES_WIDTH, BAR_ICON_POS, BAR_ICON_ALIGN, BAR_ICON_MARGIN, BAR_RESIZABLE, BAR_MOVABLE, BAR_ICONIFIABLE, BAR_FONT_RESIZABLE, BAR_ALWAYS_TOP, BAR_ALWAYS_BOTTOM, BAR_COLOR_SCHEME, BAR_CONTAINED, BAR_BUTTON_ALIGN }; int CTwBar::HasAttrib(const char *_Attrib, bool *_HasValue) const { *_HasValue = true; if( _stricmp(_Attrib, "label")==0 ) return BAR_LABEL; else if( _stricmp(_Attrib, "help")==0 ) return BAR_HELP; else if( _stricmp(_Attrib, "color")==0 ) return BAR_COLOR; else if( _stricmp(_Attrib, "alpha")==0 ) return BAR_ALPHA; else if( _stricmp(_Attrib, "text")==0 ) return BAR_TEXT; else if( _stricmp(_Attrib, "size")==0 ) return BAR_SIZE; else if( _stricmp(_Attrib, "position")==0 ) return BAR_POSITION; else if( _stricmp(_Attrib, "refresh")==0 ) return BAR_REFRESH; else if( _stricmp(_Attrib, "fontsize")==0 ) return BAR_FONT_SIZE; else if( _stricmp(_Attrib, "valueswidth")==0 ) return BAR_VALUES_WIDTH; else if( _stricmp(_Attrib, "iconpos")==0 ) return BAR_ICON_POS; else if( _stricmp(_Attrib, "iconalign")==0 ) return BAR_ICON_ALIGN; else if( _stricmp(_Attrib, "iconmargin")==0 ) return BAR_ICON_MARGIN; else if( _stricmp(_Attrib, "resizable")==0 ) return BAR_RESIZABLE; else if( _stricmp(_Attrib, "movable")==0 ) return BAR_MOVABLE; else if( _stricmp(_Attrib, "iconifiable")==0 ) return BAR_ICONIFIABLE; else if( _stricmp(_Attrib, "fontresizable")==0 ) return BAR_FONT_RESIZABLE; else if( _stricmp(_Attrib, "alwaystop")==0 ) return BAR_ALWAYS_TOP; else if( _stricmp(_Attrib, "alwaysbottom")==0 ) return BAR_ALWAYS_BOTTOM; else if( _stricmp(_Attrib, "visible")==0 ) return BAR_VISIBLE; else if( _stricmp(_Attrib, "iconified")==0 ) return BAR_ICONIFIED; else if( _stricmp(_Attrib, "colorscheme")==0 ) return BAR_COLOR_SCHEME; else if( _stricmp(_Attrib, "contained")==0 ) return BAR_CONTAINED; else if( _stricmp(_Attrib, "buttonalign")==0 ) return BAR_BUTTON_ALIGN; *_HasValue = false; if( _stricmp(_Attrib, "show")==0 ) // for backward compatibility return BAR_SHOW; else if( _stricmp(_Attrib, "hide")==0 ) // for backward compatibility return BAR_HIDE; else if( _stricmp(_Attrib, "iconify")==0 ) // for backward compatibility return BAR_ICONIFY; return 0; // not found } int CTwBar::SetAttrib(int _AttribID, const char *_Value) { switch( _AttribID ) { case BAR_LABEL: if( _Value && strlen(_Value)>0 ) { m_Label = _Value; NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_HELP: if( _Value && strlen(_Value)>0 ) { m_Help = _Value; NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_COLOR: if( _Value && strlen(_Value)>0 ) { int v0, v1, v2, v3; int n = sscanf(_Value, "%d%d%d%d", &v0, &v1, &v2, &v3); color32 c; int alpha = (m_Color>>24) & 0xff; if( n==3 && v0>=0 && v0<=255 && v1>=0 && v1<=255 && v2>=0 && v2<=255 ) c = Color32FromARGBi(alpha, v0, v1, v2); else if( n==4 && v0>=0 && v0<=255 && v1>=0 && v1<=255 && v2>=0 && v2<=255 && v3>=0 && v3<=255 ) c = Color32FromARGBi(v0, v1, v2, v3); else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } m_Color = c; NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_ALPHA: if( _Value && strlen(_Value)>0 ) { int alpha = 255; int n = sscanf(_Value, "%d", &alpha); if( n==1 && alpha>=0 && alpha<=255 ) m_Color = (alpha<<24) | (m_Color & 0xffffff); else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_TEXT: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "dark")==0 ) m_DarkText = true; else if( _stricmp(_Value, "light")==0 ) m_DarkText = false; else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_SIZE: if( _Value && strlen(_Value)>0 ) { int sx, sy; int n = sscanf(_Value, "%d%d", &sx, &sy); if( n==2 && sx>0 && sy>0 ) { m_Width = sx; m_Height = sy; NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_POSITION: if( _Value && strlen(_Value)>0 ) { int x, y; int n = sscanf(_Value, "%d%d", &x, &y); if( n==2 && x>=0 && y>=0 ) { m_PosX = x; m_PosY = y; NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_REFRESH: if( _Value && strlen(_Value)>0 ) { float r; int n = sscanf(_Value, "%f", &r); if( n==1 && r>=0 ) { m_UpdatePeriod = r; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_VALUES_WIDTH: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "fit")==0 ) { m_ValuesWidth = VALUES_WIDTH_FIT; NotUpToDate(); return 1; } else { int w; int n = sscanf(_Value, "%d", &w); if( n==1 && w>0 ) { m_ValuesWidth = w; NotUpToDate(); return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_FONT_SIZE: return g_TwMgr->SetAttrib(MGR_FONT_SIZE, _Value); case BAR_ICON_POS: return g_TwMgr->SetAttrib(MGR_ICON_POS, _Value); case BAR_ICON_ALIGN: return g_TwMgr->SetAttrib(MGR_ICON_ALIGN, _Value); case BAR_ICON_MARGIN: return g_TwMgr->SetAttrib(MGR_ICON_MARGIN, _Value); case BAR_SHOW: // deprecated TwSetBarState(this, TW_STATE_SHOWN); return 1; case BAR_HIDE: // deprecated TwSetBarState(this, TW_STATE_HIDDEN); return 1; case BAR_ICONIFY: // deprecated TwSetBarState(this, TW_STATE_ICONIFIED); return 1; case BAR_RESIZABLE: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { m_Resizable = true; return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { m_Resizable = false; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_MOVABLE: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { m_Movable = true; return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { m_Movable = false; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_ICONIFIABLE: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { m_Iconifiable = true; return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { m_Iconifiable = false; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_FONT_RESIZABLE: return g_TwMgr->SetAttrib(MGR_FONT_RESIZABLE, _Value); case BAR_ALWAYS_TOP: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { g_TwMgr->m_BarAlwaysOnTop = m_Name; if( g_TwMgr->m_BarAlwaysOnBottom.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnBottom.c_str(), m_Name.c_str())==0 ) g_TwMgr->m_BarAlwaysOnBottom.clear(); TwSetTopBar(this); return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { if( g_TwMgr->m_BarAlwaysOnTop.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnTop.c_str(), m_Name.c_str())==0 ) g_TwMgr->m_BarAlwaysOnTop.clear(); return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_ALWAYS_BOTTOM: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { g_TwMgr->m_BarAlwaysOnBottom = m_Name; if( g_TwMgr->m_BarAlwaysOnTop.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnTop.c_str(), m_Name.c_str())==0 ) g_TwMgr->m_BarAlwaysOnTop.clear(); TwSetBottomBar(this); return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { if( g_TwMgr->m_BarAlwaysOnBottom.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnBottom.c_str(), m_Name.c_str())==0 ) g_TwMgr->m_BarAlwaysOnBottom.clear(); return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_VISIBLE: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { TwSetBarState(this, TW_STATE_SHOWN); return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { TwSetBarState(this, TW_STATE_HIDDEN); return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_ICONIFIED: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { TwSetBarState(this, TW_STATE_ICONIFIED); return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { TwSetBarState(this, TW_STATE_UNICONIFIED); return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_COLOR_SCHEME: return g_TwMgr->SetAttrib(MGR_COLOR_SCHEME, _Value); case BAR_CONTAINED: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { m_Contained = true; return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { m_Contained = false; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case BAR_BUTTON_ALIGN: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "left")==0 ) { m_ButtonAlign = BUTTON_ALIGN_LEFT; return 1; } else if( _stricmp(_Value, "center")==0 ) { m_ButtonAlign = BUTTON_ALIGN_CENTER; return 1; } if( _stricmp(_Value, "right")==0 ) { m_ButtonAlign = BUTTON_ALIGN_RIGHT; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } default: g_TwMgr->SetLastError(g_ErrUnknownAttrib); return 0; } } ERetType CTwBar::GetAttrib(int _AttribID, std::vector& outDoubles, std::ostringstream& outString) const { outDoubles.clear(); outString.clear(); switch( _AttribID ) { case BAR_LABEL: outString << m_Label; return RET_STRING; case BAR_HELP: outString << m_Help; return RET_STRING; case BAR_COLOR: { int a, r, g, b; a = r = g = b = 0; Color32ToARGBi(m_Color, &a, &r, &g, &b); outDoubles.push_back(r); outDoubles.push_back(g); outDoubles.push_back(b); return RET_DOUBLE; } case BAR_ALPHA: { int a, r, g, b; a = r = g = b = 0; Color32ToARGBi(m_Color, &a, &r, &g, &b); outDoubles.push_back(a); return RET_DOUBLE; } case BAR_TEXT: if( m_DarkText ) outString << "dark"; else outString << "light"; return RET_STRING; case BAR_SIZE: outDoubles.push_back(m_Width); outDoubles.push_back(m_Height); return RET_DOUBLE; case BAR_POSITION: outDoubles.push_back(m_PosX); outDoubles.push_back(m_PosY); return RET_DOUBLE; case BAR_REFRESH: outDoubles.push_back(m_UpdatePeriod); return RET_DOUBLE; case BAR_VALUES_WIDTH: outDoubles.push_back(m_ValuesWidth); return RET_DOUBLE; case BAR_FONT_SIZE: return g_TwMgr->GetAttrib(MGR_FONT_SIZE, outDoubles, outString); case BAR_ICON_POS: return g_TwMgr->GetAttrib(MGR_ICON_POS, outDoubles, outString); case BAR_ICON_ALIGN: return g_TwMgr->GetAttrib(MGR_ICON_ALIGN, outDoubles, outString); case BAR_ICON_MARGIN: return g_TwMgr->GetAttrib(MGR_ICON_MARGIN, outDoubles, outString); case BAR_RESIZABLE: outDoubles.push_back(m_Resizable); return RET_DOUBLE; case BAR_MOVABLE: outDoubles.push_back(m_Movable); return RET_DOUBLE; case BAR_ICONIFIABLE: outDoubles.push_back(m_Iconifiable); return RET_DOUBLE; case BAR_FONT_RESIZABLE: return g_TwMgr->GetAttrib(MGR_FONT_RESIZABLE, outDoubles, outString); case BAR_ALWAYS_TOP: outDoubles.push_back( g_TwMgr->m_BarAlwaysOnTop == m_Name ); return RET_DOUBLE; case BAR_ALWAYS_BOTTOM: outDoubles.push_back( g_TwMgr->m_BarAlwaysOnBottom == m_Name ); return RET_DOUBLE; case BAR_VISIBLE: outDoubles.push_back(m_Visible); return RET_DOUBLE; case BAR_ICONIFIED: outDoubles.push_back(m_IsMinimized); return RET_DOUBLE; case BAR_COLOR_SCHEME: return g_TwMgr->GetAttrib(MGR_COLOR_SCHEME, outDoubles, outString); case BAR_CONTAINED: outDoubles.push_back(m_Contained); return RET_DOUBLE; case BAR_BUTTON_ALIGN: if( m_ButtonAlign==BUTTON_ALIGN_LEFT ) outString << "left"; else if( m_ButtonAlign==BUTTON_ALIGN_CENTER ) outString << "center"; else outString << "right"; return RET_STRING; default: g_TwMgr->SetLastError(g_ErrUnknownAttrib); return RET_ERROR; } } // --------------------------------------------------------------------------- void CTwBar::NotUpToDate() { m_UpToDate = false; } // --------------------------------------------------------------------------- void CTwBar::UpdateColors() { float a, r, g, b, h, l, s; Color32ToARGBf(m_Color, &a, &r, &g, &b); ColorRGBToHLSf(r, g, b, &h, &l, &s); bool lightText = !m_DarkText; // Colors independant of m_Color // Highlighted line background ramp m_ColHighBg0 = lightText ? Color32FromARGBf(0.4f, 0.9f, 0.9f, 0.9f) : Color32FromARGBf(0.4f, 1.0f, 1.0f, 1.0f); m_ColHighBg1 = lightText ? Color32FromARGBf(0.4f, 0.2f, 0.2f, 0.2f) : Color32FromARGBf(0.1f, 0.7f, 0.7f, 0.7f); // Text colors & background m_ColLabelText = lightText ? COLOR32_WHITE : COLOR32_BLACK; m_ColStructText = lightText ? 0xffefef00 : 0xff303000; m_ColValText = lightText ? 0xffc7d7ff : 0xff000080; m_ColValTextRO = lightText ? 0xffb7b7b7 : 0xff505050; m_ColValMin = lightText ? 0xff9797ff : 0xff0000f0; m_ColValMax = m_ColValMin; m_ColValTextNE = lightText ? 0xff97f797 : 0xff004000; m_ColValBg = lightText ? Color32FromARGBf(0.2f+0.3f*a, 0.1f, 0.1f, 0.1f) : Color32FromARGBf(0.2f+0.3f*a, 1, 1, 1); m_ColStructBg = lightText ? Color32FromARGBf(0.4f*a, 0, 0, 0) : Color32FromARGBf(0.4f*a, 1, 1, 1); m_ColLine = lightText ? Color32FromARGBf(0.6f, 1, 1, 1) : Color32FromARGBf(0.6f, 0.3f, 0.3f, 0.3f); m_ColLineShadow = lightText ? Color32FromARGBf(0.6f, 0, 0, 0) : Color32FromARGBf(0.6f, 0, 0, 0); m_ColUnderline = lightText ? 0xffd0d0d0 : 0xff202000; m_ColGrpBg = lightText ? Color32FromARGBf(0.1f+0.25f*a, 1, 1, 1) : Color32FromARGBf(0.1f+0.05f*a, 0, 0, 0); m_ColGrpText = lightText ? 0xffffff80 : 0xff000000; m_ColShortcutText = lightText ? 0xffffb060 : 0xff802000; m_ColShortcutBg = lightText ? Color32FromARGBf(0.4f*a, 0.2f, 0.2f, 0.2f) : Color32FromARGBf(0.4f*a, 0.8f, 0.8f, 0.8f); m_ColInfoText = lightText ? Color32FromARGBf(1.0f, 0.7f, 0.7f, 0.7f) : Color32FromARGBf(1.0f, 0.3f, 0.3f, 0.3f); m_ColRoto = lightText ? Color32FromARGBf(0.8f, 0.85f, 0.85f, 0.85f) : Color32FromARGBf(0.8f, 0.1f, 0.1f, 0.1f); m_ColRotoVal = Color32FromARGBf(1, 1.0f, 0.2f, 0.2f); m_ColRotoBound = lightText ? Color32FromARGBf(0.8f, 0.6f, 0.6f, 0.6f) : Color32FromARGBf(0.8f, 0.3f, 0.3f, 0.3f); m_ColEditText = lightText ? COLOR32_WHITE : COLOR32_BLACK; m_ColEditBg = lightText ? 0xff575757 : 0xffc7c7c7; // must be opaque m_ColEditSelText = lightText ? COLOR32_BLACK : COLOR32_WHITE; m_ColEditSelBg = lightText ? 0xffc7c7c7 : 0xff575757; // Colors dependant of m_Colors // Bar background ColorHLSToRGBf(h, l, s, &r, &g, &b); m_ColBg = Color32FromARGBf(a, r, g, b); ColorHLSToRGBf(h, l-0.05f, s, &r, &g, &b); m_ColBg1 = Color32FromARGBf(a, r, g, b); ColorHLSToRGBf(h, l-0.1f, s, &r, &g, &b); m_ColBg2 = Color32FromARGBf(a, r, g, b); ColorHLSToRGBf(h, l-0.15f, s, &r, &g, &b); m_ColTitleBg = Color32FromARGBf(a+0.9f, r, g, b); m_ColTitleText = lightText ? COLOR32_WHITE : COLOR32_BLACK; m_ColTitleShadow = lightText ? 0x40000000 : 0x00000000; ColorHLSToRGBf(h, l-0.25f, s, &r, &g, &b); m_ColTitleHighBg = Color32FromARGBf(a+0.8f, r, g, b); ColorHLSToRGBf(h, l-0.3f, s, &r, &g, &b); m_ColTitleUnactiveBg = Color32FromARGBf(a+0.2f, r, g, b); ColorHLSToRGBf(h, l-0.2f, s, &r, &g, &b); m_ColHierBg = Color32FromARGBf(a, r, g, b); ColorHLSToRGBf(h, l+0.1f, s, &r, &g, &b); m_ColBtn = Color32FromARGBf(0.2f+0.4f*a, r, g, b); ColorHLSToRGBf(h, l-0.35f, s, &r, &g, &b); m_ColHighBtn = Color32FromARGBf(0.4f+0.4f*a, r, g, b); ColorHLSToRGBf(h, l-0.25f, s, &r, &g, &b); m_ColFold = Color32FromARGBf(0.1f+0.4f*a, r, g, b); ColorHLSToRGBf(h, l-0.35f, s, &r, &g, &b); m_ColHighFold = Color32FromARGBf(0.3f+0.4f*a, r, g, b); ColorHLSToRGBf(h, 0.75f, s, &r, &g, &b); m_ColHelpBg = Color32FromARGBf(0.2f, 1, 1, 1); m_ColHelpText = lightText ? Color32FromARGBf(1, 0.2f, 1.0f, 0.2f) : Color32FromARGBf(1, 0, 0.4f, 0); m_ColSeparator = m_ColValTextRO; m_ColStaticText = m_ColHelpText; } /* void CTwBar::UpdateColors() { float a, r, g, b, h, l, s; Color32ToARGBf(m_Color, &a, &r, &g, &b); ColorRGBToHLSf(r, g, b, &h, &l, &s); bool lightText = !m_DarkText; // (l<=0.45f); l = 0.2f + 0.6f*l; ColorHLSToRGBf(h, l, s, &r, &g, &b); m_ColBg = Color32FromARGBf(a, r, g, b); ColorHLSToRGBf(h, l-0.1f, s, &r, &g, &b); m_ColBg1 = Color32FromARGBf(a, r, g, b); ColorHLSToRGBf(h, l-0.2f, s, &r, &g, &b); m_ColBg2 = Color32FromARGBf(a, r, g, b); ColorHLSToRGBf(h, l+0.1f, s, &r, &g, &b); m_ColHighBg = Color32FromARGBf(0.4f, r, g, b); //m_ColHighBg = Color32FromARGBf(a, 0.95f, 0.95f, 0.2f); m_ColLabelText = lightText ? COLOR32_WHITE : COLOR32_BLACK; m_ColStructText = lightText ? 0xffefef00 : 0xff505000; m_ColValText = lightText ? 0xffb7b7ff : 0xff000080; m_ColValTextRO = lightText ? 0xffb7b7b7 : 0xff505050; m_ColValMin = lightText ? 0xff9797ff : 0xff0000f0; m_ColValMax = m_ColValMin; m_ColValTextNE = lightText ? 0xff97f797 : 0xff006000; ColorHLSToRGBf(h, lightText ? (min(l+0.2f, 0.3f)) : (max(l-0.2f, 0.6f)), s, &r, &g, &b); m_ColValBg = Color32FromARGBf(0.4f*a, 0, 0, 0); m_ColStructBg = Color32FromARGBf(0.4f*a, 0, 0, 0); ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b); m_ColTitleBg = Color32FromARGBf(a+0.4f, r, g, b); m_ColTitleText = lightText ? COLOR32_WHITE : COLOR32_BLACK; m_ColTitleShadow = lightText ? 0x80000000 : 0x80ffffff; ColorHLSToRGBf(h, 0.3f, s, &r, &g, &b); m_ColTitleHighBg = Color32FromARGBf(a+0.4f, r, g, b); ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b); m_ColTitleUnactiveBg = Color32FromARGBf(a+0.2f, r, g, b); ColorHLSToRGBf(h, 0.8f, s, &r, &g, &b); m_ColLine = Color32FromARGBf(0.6f, r, g, b); // 0xfff0f0f0; m_ColLineShadow = Color32FromARGBf(0.6f, 0, 0, 0); //COLOR32_BLACK; m_ColUnderline = lightText ? 0xffd0d0d0 : 0xff202000; ColorHLSToRGBf(h, 0.7f, s, &r, &g, &b); m_ColBtn = Color32FromARGBf(0.6f, r, g, b); ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b); m_ColHighBtn = Color32FromARGBf(0.6f, r, g, b); ColorHLSToRGBf(h, 0.6f, s, &r, &g, &b); m_ColFold = Color32FromARGBf(0.3f*a, r, g, b); ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b); m_ColHighFold = Color32FromARGBf(0.3f, r, g, b); ColorHLSToRGBf(h, lightText ? l+0.2f : l-0.2f, s, &r, &g, &b); m_ColGrpBg = Color32FromARGBf(0.5f*a, r, g, b); m_ColGrpText = lightText ? 0xffffff80 : 0xff404000; ColorHLSToRGBf(h, 0.75f, s, &r, &g, &b); m_ColHelpBg = Color32FromARGBf(a, r, g, b); m_ColHelpText = Color32FromARGBf(1, 0, 0.4f, 0); ColorHLSToRGBf(h, 0.45f, s, &r, &g, &b); m_ColHierBg = Color32FromARGBf(0.75f*a, r, g, b); m_ColShortcutText = lightText ? 0xffff8040 : 0xff802000; //0xfff0f0f0; m_ColShortcutBg = Color32FromARGBf(0.4f*a, 0.2f, 0.2f, 0.2f); m_ColInfoText = Color32FromARGBf(1.0f, 0.7f, 0.7f, 0.7f); m_ColRoto = Color32FromARGBf(1, 0.75f, 0.75f, 0.75f); m_ColRotoVal = Color32FromARGBf(1, 1.0f, 0.2f, 0.2f); m_ColRotoBound = Color32FromARGBf(1, 0.4f, 0.4f, 0.4f); m_ColEditText = lightText ? COLOR32_WHITE : COLOR32_BLACK; m_ColEditBg = lightText ? 0xb7575757 : 0xb7c7c7c7; m_ColEditSelText = lightText ? COLOR32_BLACK : COLOR32_WHITE; m_ColEditSelBg = lightText ? 0xffc7c7c7 : 0xff575757; m_ColSeparator = m_ColValTextRO; m_ColStaticText = m_ColHelpText; } */ // --------------------------------------------------------------------------- CTwVarGroup::~CTwVarGroup() { for( vector::iterator it= m_Vars.begin(); it!=m_Vars.end(); ++it ) if( *it != NULL ) { CTwVar *Var = *it; delete Var; *it = NULL; } } // --------------------------------------------------------------------------- static inline int IncrBtnWidth(int _CharHeight) { return ((2*_CharHeight)/3+2)&0xfffe; // force even value } // --------------------------------------------------------------------------- void CTwBar::BrowseHierarchy(int *_CurrLine, int _CurrLevel, const CTwVar *_Var, int _First, int _Last) { assert(_Var!=NULL); if( !_Var->m_IsRoot ) { if( (*_CurrLine)>=_First && (*_CurrLine)<=_Last ) { CHierTag Tag; Tag.m_Level = _CurrLevel; Tag.m_Var = const_cast(_Var); Tag.m_Closing = false; m_HierTags.push_back(Tag); } *_CurrLine += 1; } else { *_CurrLine = 0; _CurrLevel = -1; m_HierTags.resize(0); } if( _Var->IsGroup() ) { const CTwVarGroup *Grp = static_cast(_Var); if( Grp->m_Open ) for( vector::const_iterator it=Grp->m_Vars.begin(); it!=Grp->m_Vars.end(); ++it ) if( (*it)->m_Visible ) BrowseHierarchy(_CurrLine, _CurrLevel+1, *it, _First, _Last); if( m_HierTags.size()>0 ) m_HierTags[m_HierTags.size()-1].m_Closing = true; } } // --------------------------------------------------------------------------- void CTwBar::ListLabels(vector& _Labels, vector& _Colors, vector& _BgColors, bool *_HasBgColors, const CTexFont *_Font, int _AtomWidthMax, int _GroupWidthMax) { const int NbEtc = 2; string ValStr; int Len, i, x, Etc, s; const unsigned char *Text; unsigned char ch; int WidthMax; int Space = _Font->m_CharWidth[(int)' ']; int LevelSpace = max(_Font->m_CharHeight-6, 4); // space used by DrawHierHandles int nh = (int)m_HierTags.size(); for( int h=0; hm_Label.length(); if( Len>0 ) Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Label.c_str()); else { Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Name.c_str()); Len = (int)m_HierTags[h].m_Var->m_Name.length(); } x = 0; Etc = 0; _Labels.push_back(""); // add a new text line if( !m_HierTags[h].m_Var->IsGroup() && static_cast(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON && static_cast(m_HierTags[h].m_Var)->m_ReadOnly && static_cast(m_HierTags[h].m_Var)->m_Val.m_Button.m_Callback!=NULL ) _Colors.push_back(m_ColValTextRO); // special case for read-only buttons else _Colors.push_back(m_HierTags[h].m_Var->m_ColorPtr!=NULL ? *(m_HierTags[h].m_Var->m_ColorPtr) : COLOR32_WHITE); color32 bg = m_HierTags[h].m_Var->m_BgColorPtr!=NULL ? *(m_HierTags[h].m_Var->m_BgColorPtr) : 0; _BgColors.push_back(bg); if( _HasBgColors!=NULL && bg!=0 ) *_HasBgColors = true; bool IsCustom = m_HierTags[h].m_Var->IsCustom(); // !m_HierTags[h].m_Var->IsGroup() && (static_cast(m_HierTags[h].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast(m_HierTags[h].m_Var)->m_Typem_Customs.size()); if( !IsCustom ) { string& CurrentLabel = _Labels[_Labels.size()-1]; if( m_HierTags[h].m_Var->IsGroup() && static_cast(m_HierTags[h].m_Var)->m_SummaryCallback==NULL ) WidthMax = _GroupWidthMax; else if( !m_HierTags[h].m_Var->IsGroup() && static_cast(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON ) { if( static_cast(m_HierTags[h].m_Var)->m_Val.m_Button.m_Callback==NULL ) WidthMax = _GroupWidthMax; else if( m_ButtonAlign == BUTTON_ALIGN_RIGHT ) WidthMax = _GroupWidthMax - 2*IncrBtnWidth(m_Font->m_CharHeight); else WidthMax = _AtomWidthMax; } //else if( m_HighlightedLine==h && m_DrawRotoBtn ) // WidthMax = _AtomWidthMax - IncrBtnWidth(m_Font->m_CharHeight); else WidthMax = _AtomWidthMax; if( Space>0 ) for( s=0; sm_CharWidth[(int)'.']m_DontClip) for( i=0; im_CharWidth[(int)ch]; if( Etc>0 ) { ++Etc; if( Etc>NbEtc ) break; } else if( im_CharWidth[(int)'.']>=WidthMax && !(m_HierTags[h].m_Var->m_DontClip)) Etc = 1; } } } } // --------------------------------------------------------------------------- void CTwBar::ListValues(vector& _Values, vector& _Colors, vector& _BgColors, const CTexFont *_Font, int _WidthMax) { CTwFPU fpu; // force fpu precision const int NbEtc = 2; const CTwVarAtom *Atom = NULL; string ValStr; int Len, i, x, Etc; const unsigned char *Text; unsigned char ch; bool ReadOnly; bool IsMax; bool IsMin; bool IsROText; bool HasBgColor; bool AcceptEdit; size_t SummaryMaxLength = max(_WidthMax/_Font->m_CharWidth[(int)'I'], 4); static vector Summary; Summary.resize(SummaryMaxLength+32); int nh = (int)m_HierTags.size(); for( int h=0; hIsGroup() || m_IsHelpBar || (m_HierTags[h].m_Var->IsGroup() && static_cast(m_HierTags[h].m_Var)->m_SummaryCallback!=NULL) ) { ReadOnly = true; IsMax = false; IsMin = false; IsROText = false; HasBgColor = true; AcceptEdit = false; if( !m_HierTags[h].m_Var->IsGroup() ) { Atom = static_cast(m_HierTags[h].m_Var); Atom->ValueToString(&ValStr); if( !m_IsHelpBar || (Atom->m_Type==TW_TYPE_SHORTCUT && (Atom->m_Val.m_Shortcut.m_Incr[0]>0 || Atom->m_Val.m_Shortcut.m_Decr[0]>0)) ) ReadOnly = Atom->m_ReadOnly; if( !Atom->m_NoSlider ) { double v, vmin, vmax; v = Atom->ValueToDouble(); Atom->MinMaxStepToDouble(&vmin, &vmax, NULL); IsMax = (v>=vmax); IsMin = (v<=vmin); } if( Atom->m_Type==TW_TYPE_BOOLCPP || Atom->m_Type==TW_TYPE_BOOL8 || Atom->m_Type==TW_TYPE_BOOL16 || Atom->m_Type==TW_TYPE_BOOL32 ) { if (ValStr=="1") ValStr = "\x7f"; // check sign else if (ValStr=="0") ValStr = " -"; //"\x97"; // uncheck sign } if( (Atom->m_Type==TW_TYPE_CDSTRING && Atom->m_SetCallback==NULL && g_TwMgr->m_CopyCDStringToClient==NULL) || (Atom->m_Type==TW_TYPE_CDSTDSTRING && Atom->m_SetCallback==NULL) || (Atom->m_Type==TW_TYPE_STDSTRING && Atom->m_SetCallback==NULL && g_TwMgr->m_CopyStdStringToClient==NULL) ) IsROText = true; if( Atom->m_Type==TW_TYPE_HELP_ATOM || Atom->m_Type==TW_TYPE_HELP_GRP || Atom->m_Type==TW_TYPE_BUTTON || Atom->IsCustom() ) // (Atom->m_Type>=TW_TYPE_CUSTOM_BASE && Atom->m_Typem_Customs.size()) ) HasBgColor = false; AcceptEdit = EditInPlaceAcceptVar(Atom) || (Atom->m_Type==TW_TYPE_SHORTCUT); } else if(m_HierTags[h].m_Var->IsGroup() && static_cast(m_HierTags[h].m_Var)->m_SummaryCallback!=NULL) { const CTwVarGroup *Grp = static_cast(m_HierTags[h].m_Var); // force internal value update for( size_t v=0; vm_Vars.size(); v++ ) if( Grp->m_Vars[v]!=NULL && !Grp->m_Vars[v]->IsGroup() && Grp->m_Vars[v]->m_Visible ) static_cast(Grp->m_Vars[v])->ValueToDouble(); Summary[0] = '\0'; if( Grp->m_SummaryCallback==CTwMgr::CStruct::DefaultSummary ) Grp->m_SummaryCallback(&Summary[0], SummaryMaxLength, Grp, Grp->m_SummaryClientData); else Grp->m_SummaryCallback(&Summary[0], SummaryMaxLength, Grp->m_StructValuePtr, Grp->m_SummaryClientData); ValStr = (const char *)(&Summary[0]); } else { ValStr = ""; // is a group in the help bar HasBgColor = false; } Len = (int)ValStr.length(); Text = (const unsigned char *)(ValStr.c_str()); x = 0; Etc = 0; _Values.push_back(""); // add a new text line if( ReadOnly || (IsMin && IsMax) || IsROText ) _Colors.push_back(m_ColValTextRO); else if( IsMin ) _Colors.push_back(m_ColValMin); else if( IsMax ) _Colors.push_back(m_ColValMax); else if( !AcceptEdit ) _Colors.push_back(m_ColValTextNE); else _Colors.push_back(m_ColValText); if( !HasBgColor ) _BgColors.push_back(0x00000000); else if( m_HierTags[h].m_Var->IsGroup() ) { const CTwVarGroup *Grp = static_cast(m_HierTags[h].m_Var); // if typecolor set bgcolor if( Grp->m_SummaryCallback==CColorExt::SummaryCB ) _BgColors.push_back(0xff000000); else _BgColors.push_back(m_ColStructBg); } else _BgColors.push_back(m_ColValBg); string& CurrentValue = _Values[_Values.size()-1]; int wmax = _WidthMax; if( m_HighlightedLine==h && m_DrawRotoBtn ) wmax -= 3*IncrBtnWidth(m_Font->m_CharHeight); else if( m_HighlightedLine==h && m_DrawIncrDecrBtn ) wmax -= 2*IncrBtnWidth(m_Font->m_CharHeight); else if( m_HighlightedLine==h && m_DrawListBtn ) wmax -= 1*IncrBtnWidth(m_Font->m_CharHeight); else if( m_HighlightedLine==h && m_DrawBoolBtn ) wmax -= 1*IncrBtnWidth(m_Font->m_CharHeight); for( i=0; im_CharWidth[(int)ch]; if( Etc>0 ) { ++Etc; if( Etc>NbEtc ) break; } else if( im_CharWidth[(int)'.'])>=wmax ) Etc = 1; } } else { _Values.push_back(""); // add a new empty line _Colors.push_back(COLOR32_BLACK); _BgColors.push_back(0x00000000); } } // --------------------------------------------------------------------------- int CTwBar::ComputeLabelsWidth(const CTexFont *_Font) { int Len, i, x, s; const unsigned char *Text; int LabelsWidth = 0; int Space = _Font->m_CharWidth[(int)' ']; int LevelSpace = max(_Font->m_CharHeight-6, 4); // space used by DrawHierHandles int nh = (int)m_HierTags.size(); for( int h=0; hm_Label.length(); if( Len>0 ) Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Label.c_str()); else { Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Name.c_str()); Len = (int)m_HierTags[h].m_Var->m_Name.length(); } x = 0; bool IsCustom = m_HierTags[h].m_Var->IsCustom(); // !m_HierTags[h].m_Var->IsGroup() && (static_cast(m_HierTags[h].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast(m_HierTags[h].m_Var)->m_Typem_Customs.size()); if( !IsCustom ) { if( Space>0 ) for( s=0; sm_CharWidth[(int)Text[i]]; x += 3*Space; // add little margin } if (x > LabelsWidth) LabelsWidth = x; } return LabelsWidth; } int CTwBar::ComputeValuesWidth(const CTexFont *_Font) { CTwFPU fpu; // force fpu precision const CTwVarAtom *Atom = NULL; string ValStr; int Len, i, x; int Space = _Font->m_CharWidth[(int)' ']; const unsigned char *Text; int ValuesWidth = 0; int nh = (int)m_HierTags.size(); for( int h=0; hIsGroup() ) { Atom = static_cast(m_HierTags[h].m_Var); Atom->ValueToString(&ValStr); Len = (int)ValStr.length(); Text = (const unsigned char *)(ValStr.c_str()); x = 0; for( i=0; im_CharWidth[(int)Text[i]]; x += 2*Space; // add little margin if (x > ValuesWidth) ValuesWidth = x; } return ValuesWidth; } // --------------------------------------------------------------------------- static int ClampText(string& _Text, const CTexFont *_Font, int _WidthMax) { int Len = (int)_Text.length(); unsigned char ch; int Width = 0; int i; for( i=0; im_CharWidth[(int)'.']>=_WidthMax ) break; Width += _Font->m_CharWidth[ch]; } if( im_CharWidth[(int)'.']; } return Width; } // --------------------------------------------------------------------------- void CTwBar::Update() { assert(m_UpToDate==false); assert(m_Font); ITwGraph *Gr = g_TwMgr->m_Graph; bool DoEndDraw = false; if( !Gr->IsDrawing() ) { Gr->BeginDraw(g_TwMgr->m_WndWidth, g_TwMgr->m_WndHeight); DoEndDraw = true; } bool ValuesWidthFit = false; if( m_ValuesWidth==VALUES_WIDTH_FIT ) { ValuesWidthFit = true; m_ValuesWidth = 0; } int PrevPosY = m_PosY; int vpx, vpy, vpw, vph; vpx = 0; vpy = 0; vpw = g_TwMgr->m_WndWidth; vph = g_TwMgr->m_WndHeight; if( !m_IsMinimized && vpw>0 && vph>0 ) { bool Modif = false; if( m_Resizable ) { if( m_Width>vpw && m_Contained ) { m_Width = vpw; Modif = true; } if( m_Width<8*m_Font->m_CharHeight ) { m_Width = 8*m_Font->m_CharHeight; Modif = true; } if( m_Height>vph && m_Contained ) { m_Height = vph; Modif = true; } if( m_Height<5*m_Font->m_CharHeight ) { m_Height = 5*m_Font->m_CharHeight; Modif = true; } } if( m_Movable && m_Contained ) { if( m_PosX+m_Width>vpx+vpw ) m_PosX = vpx+vpw-m_Width; if( m_PosXvpy+vph ) m_PosY = vpy+vph-m_Height; if( m_PosYm_CharHeight ) { m_ValuesWidth = 2*m_Font->m_CharHeight; Modif = true; } if( m_ValuesWidth>m_Width-4*m_Font->m_CharHeight ) { m_ValuesWidth = m_Width-4*m_Font->m_CharHeight; Modif = true; } if (ValuesWidthFit) Modif = true; if( Modif && m_IsHelpBar ) { g_TwMgr->m_HelpBarNotUpToDate = true; g_TwMgr->m_KeyPressedBuildText = true; g_TwMgr->m_InfoBuildText = true; } } UpdateColors(); // update geometry relatively to (m_PosX, m_PosY) if( !m_IsPopupList ) { //m_VarX0 = 2*m_Font->m_CharHeight+m_Sep; m_VarX0 = m_Font->m_CharHeight+m_Sep; //m_VarX2 = m_Width - 4; m_VarX2 = m_Width - m_Font->m_CharHeight - m_Sep-2; m_VarX1 = m_VarX2 - m_ValuesWidth; } else { //m_VarX0 = m_Font->m_CharHeight+6+m_Sep; m_VarX0 = 2; //m_VarX2 = m_Width - 4; m_VarX2 = m_Width - m_Font->m_CharHeight - m_Sep-2; m_VarX1 = m_VarX2; } if( m_VarX1m_VarX2 ) m_VarX1 = m_VarX2; if( !m_IsPopupList ) { m_VarY0 = m_Font->m_CharHeight+2+m_Sep+6; m_VarY1 = m_Height-m_Font->m_CharHeight-2-m_Sep; m_VarY2 = m_Height-1; } else { m_VarY0 = 4; m_VarY1 = m_Height-2-m_Sep; m_VarY2 = m_Height-1; } int NbLines = (m_VarY1-m_VarY0+1)/(m_Font->m_CharHeight+m_Sep); if( NbLines<= 0 ) NbLines = 1; if( !m_IsMinimized ) { int LineNum = 0; BrowseHierarchy(&LineNum, 0, &m_VarRoot, m_FirstLine, m_FirstLine+NbLines); // add a dummy tag at the end to avoid wrong 'tag-closing' problems if( (int)m_HierTags.size()>NbLines ) m_HierTags.resize(NbLines); // remove the last dummy tag m_NbHierLines = LineNum; m_NbDisplayedLines = (int)m_HierTags.size(); if( ValuesWidthFit ) { m_ValuesWidth = ComputeValuesWidth(m_Font); if( m_ValuesWidth<2*m_Font->m_CharHeight ) m_ValuesWidth = 2*m_Font->m_CharHeight; // enough to draw buttons if( m_ValuesWidth>m_VarX2 - m_VarX0 ) m_ValuesWidth = max(m_VarX2 - m_VarX0 - m_Font->m_CharHeight, 0); m_VarX1 = m_VarX2 - m_ValuesWidth; if( m_VarX1m_VarX2 ) m_VarX1 = m_VarX2; m_ValuesWidth = m_VarX2 - m_VarX1; } } // scroll bar int y0 = m_PosY+m_VarY0; int y1 = m_PosY+m_VarY1; int x0 = m_PosX+2; int x1 = m_PosX+m_Font->m_CharHeight-2; if( ((x0+x1)&1)==1 ) x1 += 1; int w = x1-x0+1; int h = y1-y0-2*w; int hscr = (m_NbHierLines>0) ? ((h*m_NbDisplayedLines)/m_NbHierLines) : h; if( hscr<=4 ) hscr = 4; if( hscr>h ) hscr = h; int yscr = (m_NbHierLines>0) ? ((h*m_FirstLine)/m_NbHierLines) : 0; if( yscr<=0 ) yscr = 0; if( yscr>h-4 ) yscr = h-4; if( yscr+hscr>h ) hscr = h-yscr; if( hscr>h ) hscr = h; if( hscr<=4 ) hscr = 4; m_ScrollYW = w; m_ScrollYH = h; m_ScrollY0 = y0+w+yscr; m_ScrollY1 = y0+w+yscr+hscr; // Build title string Title; if( m_Label.size()>0 ) Title = m_Label; else Title = m_Name; m_TitleWidth = ClampText(Title, m_Font, (!m_IsMinimized)?(m_Width-5*m_Font->m_CharHeight):(16*m_Font->m_CharHeight)); Gr->BuildText(m_TitleTextObj, &Title, NULL, NULL, 1, m_Font, 0, 0); if( !m_IsMinimized ) { // Build labels vector Labels; vector Colors; vector BgColors; bool HasBgColors = false; ListLabels(Labels, Colors, BgColors, &HasBgColors, m_Font, m_VarX1-m_VarX0, m_VarX2-m_VarX0); assert( Labels.size()==Colors.size() && Labels.size()==BgColors.size() ); if( Labels.size()>0 ) Gr->BuildText(m_LabelsTextObj, &(Labels[0]), &(Colors[0]), &(BgColors[0]), (int)Labels.size(), m_Font, 1, HasBgColors ? m_VarX1-m_VarX0-m_Font->m_CharHeight+2 : 0); else Gr->BuildText(m_LabelsTextObj, NULL, NULL, NULL, 0, m_Font, 1, 0); // Should draw click button? m_DrawClickBtn = ( m_VarX2-m_VarX1>4*IncrBtnWidth(m_Font->m_CharHeight) && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && ( static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BUTTON )); // || static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOLCPP // || static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL8 // || static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL16 // || static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL32 )); // Should draw [-/+] button? m_DrawIncrDecrBtn = ( m_VarX2-m_VarX1>5*IncrBtnWidth(m_Font->m_CharHeight) && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type!=TW_TYPE_BUTTON && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider && !(m_EditInPlace.m_Active && m_EditInPlace.m_Var==m_HierTags[m_HighlightedLine].m_Var) ); // Should draw [v] button (list)? m_DrawListBtn = ( m_VarX2-m_VarX1>2*IncrBtnWidth(m_Font->m_CharHeight) && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && IsEnumType(static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type) && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly ); // Should draw [<>] button (bool)? m_DrawBoolBtn = ( m_VarX2-m_VarX1>4*IncrBtnWidth(m_Font->m_CharHeight) && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && ( static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOLCPP || static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL8 || static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL16 || static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL32 )); // Should draw [o] button? m_DrawRotoBtn = m_DrawIncrDecrBtn; /* m_DrawRotoBtn = ( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type!=TW_TYPE_BUTTON && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider ); */ // Build values vector& Values = Labels; // reuse Values.resize(0); Colors.resize(0); BgColors.resize(0); ListValues(Values, Colors, BgColors, m_Font, m_VarX2-m_VarX1); assert( BgColors.size()==Values.size() && Colors.size()==Values.size() ); if( Values.size()>0 ) Gr->BuildText(m_ValuesTextObj, &(Values[0]), &(Colors[0]), &(BgColors[0]), (int)Values.size(), m_Font, 1, m_VarX2-m_VarX1); else Gr->BuildText(m_ValuesTextObj, NULL, NULL, NULL, 0, m_Font, 1, m_VarX2-m_VarX1); // Build key shortcut text string Shortcut; m_ShortcutLine = -1; if( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { const CTwVarAtom *Atom = static_cast(m_HierTags[m_HighlightedLine].m_Var); if( Atom->m_KeyIncr[0]>0 || Atom->m_KeyDecr[0]>0 ) { if( Atom->m_KeyIncr[0]>0 && Atom->m_KeyDecr[0]>0 ) Shortcut = "Keys: "; else Shortcut = "Key: "; if( Atom->m_KeyIncr[0]>0 ) TwGetKeyString(&Shortcut, Atom->m_KeyIncr[0], Atom->m_KeyIncr[1]); else Shortcut += "(none)"; if( Atom->m_KeyDecr[0]>0 ) { Shortcut += " "; TwGetKeyString(&Shortcut, Atom->m_KeyDecr[0], Atom->m_KeyDecr[1]); } m_ShortcutLine = m_HighlightedLine; } } ClampText(Shortcut, m_Font, m_Width-3*m_Font->m_CharHeight); Gr->BuildText(m_ShortcutTextObj, &Shortcut, NULL, NULL, 1, m_Font, 0, 0); // build headers text if (m_HighlightLabelsHeader || m_HighlightValuesHeader) { std::string HeadersText = "Fit column content"; ClampText(HeadersText, m_Font, m_Width-3*m_Font->m_CharHeight); Gr->BuildText(m_HeadersTextObj, &HeadersText, NULL, NULL, 1, m_Font, 0, 0); } } if( DoEndDraw ) Gr->EndDraw(); m_UpToDate = true; m_LastUpdateTime = float(g_BarTimer.GetTime()); } // --------------------------------------------------------------------------- void CTwBar::DrawHierHandle() { assert(m_Font); ITwGraph *Gr = g_TwMgr->m_Graph; //int x0 = m_PosX+m_Font->m_CharHeight+1; int x0 = m_PosX+3; //int x2 = m_PosX+m_VarX0-5; //int x2 = m_PosX+3*m_Font->m_CharWidth[(int)' ']-2; int x2 = m_PosX+m_Font->m_CharHeight-3; if( x2-x0<4 ) x2 = x0+4; if( (x2-x0)&1 ) --x2; int x1 = (x0+x2)/2; int w = x2-x0+1; int y0 = m_PosY+m_VarY0 +1; int y1; int dh0 = (m_Font->m_CharHeight+m_Sep-1-w)/2; if( dh0<0 ) dh0 = 0; int dh1 = dh0+w-1; int i, h=0; if( !m_IsPopupList ) { CTwVarGroup *Grp; int nh = (int)m_HierTags.size(); for( h=0; hm_CharHeight+m_Sep-1; if( m_HierTags[h].m_Var->IsGroup() ) Grp = static_cast(m_HierTags[h].m_Var); else Grp = NULL; int dx = m_HierTags[h].m_Level * (x2-x0); if( Grp ) { if( m_ColGrpBg!=0 && Grp->m_StructValuePtr==NULL ) { color32 cb = (Grp->m_StructType==TW_TYPE_HELP_STRUCT) ? m_ColStructBg : m_ColGrpBg; //Gr->DrawRect(x0+dx-1, y0, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, cb); Gr->DrawRect(x2+dx+3, y0, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, cb); } if( m_DrawHandles ) { Gr->DrawLine(dx+x2+1,y0+dh0+1, dx+x2+1,y0+dh1+1, m_ColLineShadow); Gr->DrawLine(dx+x0+1,y0+dh1+1, dx+x2+2,y0+dh1+1, m_ColLineShadow); } //Gr->DrawRect(x0+1,y0+dh0+1,x2-1,y0+dh1-1, (h==m_HighlightedLine) ? m_ColHighBtn : m_ColBtn); Gr->DrawRect(dx+x0,y0+dh0, dx+x2,y0+dh1, (h==m_HighlightedLine) ? m_ColHighFold : m_ColFold); if( m_DrawHandles ) { Gr->DrawLine(dx+x0,y0+dh0, dx+x2,y0+dh0, m_ColLine); Gr->DrawLine(dx+x2,y0+dh0, dx+x2,y0+dh1+1, m_ColLine); Gr->DrawLine(dx+x2,y0+dh1, dx+x0,y0+dh1, m_ColLine); Gr->DrawLine(dx+x0,y0+dh1, dx+x0,y0+dh0, m_ColLine); } Gr->DrawLine(dx+x0+2,y0+dh0+w/2, dx+x2-1,y0+dh0+w/2, m_ColTitleText); if( !Grp->m_Open ) Gr->DrawLine(dx+x1,y0+dh0+2, dx+x1,y0+dh1-1, m_ColTitleText); /* if( m_ColGrpBg!=0 && Grp->m_StructValuePtr==NULL ) { color32 cb = (Grp->m_StructType==TW_TYPE_HELP_STRUCT) ? m_ColStructBg : m_ColGrpBg; //int decal = m_Font->m_CharHeight/2-2+2*m_HierTags[h].m_Level; //if( decal>m_Font->m_CharHeight-3 ) // decal = m_Font->m_CharHeight-3; int margin = dx; //m_Font->m_CharWidth[(int)' ']*m_HierTags[h].m_Level; //Gr->DrawRect(m_PosX+m_VarX0+margin, y0+decal, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, cb); Gr->DrawRect(m_PosX+m_VarX0+margin-1, y0+1, m_PosX+m_VarX2, y0+m_Font->m_CharHeight, cb);// m_ColHierBg); //Gr->DrawRect(m_PosX+m_VarX0-4, y0+m_Font->m_CharHeight/2-1, m_PosX+m_VarX0+margin-2, y0+m_Font->m_CharHeight/2, m_ColHierBg); } */ } else if( static_cast(m_HierTags[h].m_Var)->m_Type==TW_TYPE_HELP_GRP && m_ColHelpBg!=0 ) Gr->DrawRect(m_PosX+m_VarX0+m_HierTags[h].m_Var->m_LeftMargin, y0+m_HierTags[h].m_Var->m_TopMargin, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, m_ColHelpBg); //else if( static_cast(m_HierTags[h].m_Var)->m_Type==TW_TYPE_HELP_HEADER && m_ColHelpBg!=0 ) // Gr->DrawRect(m_PosX+m_VarX0+m_HierTags[h].m_Var->m_LeftMargin, y0+m_HierTags[h].m_Var->m_TopMargin, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, m_ColHelpBg); /* else if( static_cast(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON && m_ColBtn!=0 ) { // draw button int cbx0 = m_PosX+m_VarX2-2*bw+bw/2, cby0 = y0+2, cbx1 = m_PosX+m_VarX2-2-bw/2, cby1 = y0+m_Font->m_CharHeight-4; if( m_HighlightClickBtn ) { Gr->DrawRect(cbx0+2, cby0+2, cbx1+2, cby1+2, m_ColBtn); Gr->DrawLine(cbx0+3, cby1+3, cbx1+4, cby1+3, 0x7F000000); Gr->DrawLine(cbx1+3, cby0+3, cbx1+3, cby1+3, 0x7F000000); } else { Gr->DrawRect(cbx0+3, cby1+1, cbx1+3, cby1+3, 0x7F000000); Gr->DrawRect(cbx1+1, cby0+3, cbx1+3, cby1, 0x7F000000); Gr->DrawRect(cbx0, cby0, cbx1, cby1, m_ColBtn); } } */ y0 = y1+1; } } if( m_NbDisplayedLinesm_CharHeight-2; x0 = m_PosX + m_VarX2+4; x1 = x0 + m_Font->m_CharHeight-4; if( ((x0+x1)&1)==1 ) x1 += 1; w = m_ScrollYW; h = m_ScrollYH; Gr->DrawRect(x0+2,y0+w, x1-2,y1-1-w, (m_ColBg&0xffffff)|0x11000000); if( m_DrawHandles || m_IsPopupList ) { // scroll handle shadow lines Gr->DrawLine(x1-1,m_ScrollY0+1, x1-1,m_ScrollY1+1, m_ColLineShadow); Gr->DrawLine(x0+2,m_ScrollY1+1, x1,m_ScrollY1+1, m_ColLineShadow); // up & down arrow for( i=0; i<(x1-x0-2)/2; ++i ) { Gr->DrawLine(x0+2+i,y0+w-2*i, x1-i,y0+w-2*i, m_ColLineShadow); Gr->DrawLine(x0+1+i,y0+w-1-2*i, x1-1-i,y0+w-1-2*i, m_HighlightUpScroll?((m_ColLine&0xffffff)|0x4f000000):m_ColLine); Gr->DrawLine(x0+2+i,y1-w+2+2*i, x1-i,y1-w+2+2*i, m_ColLineShadow); Gr->DrawLine(x0+1+i,y1-w+1+2*i, x1-1-i,y1-w+1+2*i, m_HighlightDnScroll?((m_ColLine&0xffffff)|0x4f000000):m_ColLine); } // middle lines Gr->DrawLine((x0+x1)/2-1,y0+w, (x0+x1)/2-1,m_ScrollY0, m_ColLine); Gr->DrawLine((x0+x1)/2,y0+w, (x0+x1)/2,m_ScrollY0, m_ColLine); Gr->DrawLine((x0+x1)/2+1,y0+w, (x0+x1)/2+1,m_ScrollY0, m_ColLineShadow); Gr->DrawLine((x0+x1)/2-1,m_ScrollY1, (x0+x1)/2-1,y1-w+1, m_ColLine); Gr->DrawLine((x0+x1)/2,m_ScrollY1, (x0+x1)/2,y1-w+1, m_ColLine); Gr->DrawLine((x0+x1)/2+1,m_ScrollY1, (x0+x1)/2+1,y1-w+1, m_ColLineShadow); // scroll handle lines Gr->DrawRect(x0+2,m_ScrollY0+1, x1-3,m_ScrollY1-1, m_HighlightScroll?m_ColHighBtn:m_ColBtn); Gr->DrawLine(x1-2,m_ScrollY0, x1-2,m_ScrollY1, m_ColLine); Gr->DrawLine(x0+1,m_ScrollY0, x0+1,m_ScrollY1, m_ColLine); Gr->DrawLine(x0+1,m_ScrollY1, x1-1,m_ScrollY1, m_ColLine); Gr->DrawLine(x0+1,m_ScrollY0, x1-2,m_ScrollY0, m_ColLine); } else Gr->DrawRect(x0+3,m_ScrollY0+1, x1-3,m_ScrollY1-1, m_ColBtn); } if( m_DrawHandles && !m_IsPopupList ) { if( m_Resizable ) // Draw resize handles { // lower-left Gr->DrawLine(m_PosX+3, m_PosY+m_Height-m_Font->m_CharHeight+3, m_PosX+3, m_PosY+m_Height-4, m_ColLine); Gr->DrawLine(m_PosX+4, m_PosY+m_Height-m_Font->m_CharHeight+4, m_PosX+4, m_PosY+m_Height-3, m_ColLineShadow); Gr->DrawLine(m_PosX+3, m_PosY+m_Height-4, m_PosX+m_Font->m_CharHeight-4, m_PosY+m_Height-4, m_ColLine); Gr->DrawLine(m_PosX+4, m_PosY+m_Height-3, m_PosX+m_Font->m_CharHeight-3, m_PosY+m_Height-3, m_ColLineShadow); // lower-right Gr->DrawLine(m_PosX+m_Width-4, m_PosY+m_Height-m_Font->m_CharHeight+3, m_PosX+m_Width-4, m_PosY+m_Height-4, m_ColLine); Gr->DrawLine(m_PosX+m_Width-3, m_PosY+m_Height-m_Font->m_CharHeight+4, m_PosX+m_Width-3, m_PosY+m_Height-3, m_ColLineShadow); Gr->DrawLine(m_PosX+m_Width-4, m_PosY+m_Height-4, m_PosX+m_Width-m_Font->m_CharHeight+3, m_PosY+m_Height-4, m_ColLine); Gr->DrawLine(m_PosX+m_Width-3, m_PosY+m_Height-3, m_PosX+m_Width-m_Font->m_CharHeight+4, m_PosY+m_Height-3, m_ColLineShadow); // upper-left Gr->DrawLine(m_PosX+3, m_PosY+m_Font->m_CharHeight-4, m_PosX+3, m_PosY+3, m_ColLine); Gr->DrawLine(m_PosX+4, m_PosY+m_Font->m_CharHeight-3, m_PosX+4, m_PosY+4, m_ColLineShadow); Gr->DrawLine(m_PosX+3, m_PosY+3, m_PosX+m_Font->m_CharHeight-4, m_PosY+3, m_ColLine); Gr->DrawLine(m_PosX+4, m_PosY+4, m_PosX+m_Font->m_CharHeight-3, m_PosY+4, m_ColLineShadow); // upper-right Gr->DrawLine(m_PosX+m_Width-4, m_PosY+3, m_PosX+m_Width-m_Font->m_CharHeight+3, m_PosY+3, m_ColLine); Gr->DrawLine(m_PosX+m_Width-3, m_PosY+4, m_PosX+m_Width-m_Font->m_CharHeight+4, m_PosY+4, m_ColLineShadow); Gr->DrawLine(m_PosX+m_Width-4, m_PosY+m_Font->m_CharHeight-4, m_PosX+m_Width-4, m_PosY+3, m_ColLine); Gr->DrawLine(m_PosX+m_Width-3, m_PosY+m_Font->m_CharHeight-3, m_PosX+m_Width-3, m_PosY+4, m_ColLineShadow); } int xm = m_PosX+m_Width-2*m_Font->m_CharHeight, wm=m_Font->m_CharHeight-6; wm = (wm<6) ? 6 : wm; if( m_Iconifiable ) // Draw minimize button { Gr->DrawRect(xm+1, m_PosY+4, xm+wm-1, m_PosY+3+wm, m_HighlightMinimize?m_ColHighBtn:((m_ColBtn&0xffffff)|0x4f000000)); Gr->DrawLine(xm, m_PosY+3, xm+wm, m_PosY+3, m_ColLine); Gr->DrawLine(xm+wm, m_PosY+3, xm+wm, m_PosY+3+wm, m_ColLine); Gr->DrawLine(xm+wm, m_PosY+3+wm, xm, m_PosY+3+wm, m_ColLine); Gr->DrawLine(xm, m_PosY+3+wm, xm, m_PosY+3, m_ColLine); Gr->DrawLine(xm+wm+1, m_PosY+4, xm+wm+1, m_PosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm+1, m_PosY+4+wm, xm, m_PosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm/3+((wm<9)?1:0)-1, m_PosY+4+wm/3-((wm<9)?0:1), xm+wm/2, m_PosY+2+wm-1, m_ColTitleText, true); Gr->DrawLine(xm+wm-wm/3+((wm<9)?0:1), m_PosY+4+wm/3-((wm<9)?0:1), xm+wm/2, m_PosY+2+wm-1, m_ColTitleText, true); } if( g_TwMgr->m_FontResizable ) // Draw font button { xm = m_PosX+m_Font->m_CharHeight+2; Gr->DrawRect(xm+1, m_PosY+4, xm+wm-1, m_PosY+3+wm, m_HighlightFont?m_ColHighBtn:((m_ColBtn&0xffffff)|0x4f000000)); Gr->DrawLine(xm, m_PosY+3, xm+wm, m_PosY+3, m_ColLine); Gr->DrawLine(xm+wm, m_PosY+3, xm+wm, m_PosY+3+wm, m_ColLine); Gr->DrawLine(xm+wm, m_PosY+3+wm, xm, m_PosY+3+wm, m_ColLine); Gr->DrawLine(xm, m_PosY+3+wm, xm, m_PosY+3, m_ColLine); Gr->DrawLine(xm+wm+1, m_PosY+4, xm+wm+1, m_PosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm+1, m_PosY+4+wm, xm, m_PosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm/2-wm/6, m_PosY+3+wm/3, xm+wm/2+wm/6+1, m_PosY+3+wm/3, m_ColTitleText); Gr->DrawLine(xm+wm/2-wm/6, m_PosY+3+wm/3, xm+wm/2-wm/6, m_PosY+4+wm-wm/3+(wm>11?1:0), m_ColTitleText); Gr->DrawLine(xm+wm/2-wm/6, m_PosY+3+wm/2+(wm>11?1:0), xm+wm/2+wm/6, m_PosY+3+wm/2+(wm>11?1:0), m_ColTitleText); } } } // --------------------------------------------------------------------------- void CTwBar::Draw(int _DrawPart) { PERF( PerfTimer Timer; double DT; ) assert(m_Font); ITwGraph *Gr = g_TwMgr->m_Graph; m_CustomRecords.clear(); if( float(g_BarTimer.GetTime())>m_LastUpdateTime+m_UpdatePeriod ) NotUpToDate(); if( m_HighlightedLine!=m_HighlightedLinePrev ) { m_HighlightedLinePrev = m_HighlightedLine; NotUpToDate(); } if( m_IsHelpBar && g_TwMgr->m_HelpBarNotUpToDate ) g_TwMgr->UpdateHelpBar(); if( !m_UpToDate ) Update(); if( !m_IsMinimized ) { int y = m_PosY+1; int LevelSpace = max(m_Font->m_CharHeight-6, 4); // space used by DrawHierHandles color32 colBg = m_ColBg, colBg1 = m_ColBg1, colBg2 = m_ColBg2; if( m_DrawHandles || m_IsPopupList ) { unsigned int alphaMin = 0x70; if( m_IsPopupList ) alphaMin = 0xa0; if( (colBg>>24)>24)>24)DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, (m_HighlightTitle||m_MouseDragTitle) ? m_ColTitleHighBg : (m_DrawHandles ? m_ColTitleBg : m_ColTitleUnactiveBg)); if( m_HighlightTitle || m_MouseDragTitle ) Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, m_ColTitleHighBg); else if (m_DrawHandles) Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, m_ColTitleBg, m_ColTitleBg, colBg2, colBg1); else Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, m_ColTitleBg, m_ColTitleBg, colBg2, colBg1); } if( _DrawPart&DRAW_CONTENT ) { const color32 COL0 = 0x50ffffff; const color32 COL1 = 0x501f1f1f; Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, y, COL0, COL0, COL1, COL1); if( m_ColTitleShadow!=0 ) Gr->DrawText(m_TitleTextObj, m_PosX+(m_Width-m_TitleWidth)/2+1, m_PosY+1, m_ColTitleShadow, 0); Gr->DrawText(m_TitleTextObj, m_PosX+(m_Width-m_TitleWidth)/2, m_PosY, m_ColTitleText, 0); } y = m_PosY+m_Font->m_CharHeight+1; if( _DrawPart&DRAW_CONTENT && m_DrawHandles ) Gr->DrawLine(m_PosX, y, m_PosX+m_Width-1, y, 0x30ffffff); // 0x80afafaf); y++; PERF( DT = Timer.GetTime(); printf("Title=%.4fms ", 1000.0*DT); ) } // Draw background PERF( Timer.Reset(); ) if( _DrawPart&DRAW_BG ) { Gr->DrawRect(m_PosX, y, m_PosX+m_Width-1, m_PosY+m_Height-1, colBg2, colBg1, colBg1, colBg); //Gr->DrawRect(m_PosX, y, m_PosX+m_VarX0-5, m_PosY+m_Height-1, m_ColHierBg); Gr->DrawRect(m_PosX+m_VarX2+3, y, m_PosX+m_Width-1, m_PosY+m_Height-1, m_ColHierBg); } if( _DrawPart&DRAW_CONTENT ) { // Draw highlighted line if( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && (m_HierTags[m_HighlightedLine].m_Var->IsGroup() || (!static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && !m_IsHelpBar && !m_HierTags[m_HighlightedLine].m_Var->IsCustom() ) ) ) // !(static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Typem_Customs.size()))) ) { int y0 = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_Sep); Gr->DrawRect(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+1, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, m_ColHighBg0, m_ColHighBg0, m_ColHighBg1, m_ColHighBg1); int eps = (g_TwMgr->m_GraphAPI==TW_OPENGL || g_TwMgr->m_GraphAPI==TW_OPENGL_CORE) ? 1 : 0; if( !m_EditInPlace.m_Active ) Gr->DrawLine(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+m_Font->m_CharHeight+eps, m_PosX+m_VarX2, y0+m_Font->m_CharHeight+eps, m_ColUnderline); } else if( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { int y0 = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_Sep); color32 col = ColorBlend(m_ColHighBg0, m_ColHighBg1, 0.5f); CTwVarAtom *Atom = static_cast(m_HierTags[m_HighlightedLine].m_Var); if( !Atom->IsCustom() // !(Atom->m_Type>=TW_TYPE_CUSTOM_BASE && Atom->m_Typem_Customs.size()) && !(Atom->m_Type==TW_TYPE_BUTTON && Atom->m_Val.m_Button.m_Callback==NULL) ) Gr->DrawRect(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+1, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, col); else Gr->DrawRect(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+1, m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level+4, y0+m_Font->m_CharHeight-1, col); } color32 clight = 0x5FFFFFFF; // bar contour Gr->DrawLine(m_PosX, m_PosY, m_PosX, m_PosY+m_Height, clight); Gr->DrawLine(m_PosX, m_PosY, m_PosX+m_Width, m_PosY, clight); Gr->DrawLine(m_PosX+m_Width, m_PosY, m_PosX+m_Width, m_PosY+m_Height, clight); Gr->DrawLine(m_PosX, m_PosY+m_Height, m_PosX+m_Width, m_PosY+m_Height, clight); int dshad = 3; // bar shadows color32 cshad = (((m_Color>>24)/2)<<24) & 0xFF000000; Gr->DrawRect(m_PosX, m_PosY+m_Height, m_PosX+dshad, m_PosY+m_Height+dshad, 0, cshad, 0, 0); Gr->DrawRect(m_PosX+dshad+1, m_PosY+m_Height, m_PosX+m_Width-1, m_PosY+m_Height+dshad, cshad, cshad, 0, 0); Gr->DrawRect(m_PosX+m_Width, m_PosY+m_Height, m_PosX+m_Width+dshad, m_PosY+m_Height+dshad, cshad, 0, 0, 0); Gr->DrawRect(m_PosX+m_Width, m_PosY, m_PosX+m_Width+dshad, m_PosY+dshad, 0, 0, cshad, 0); Gr->DrawRect(m_PosX+m_Width, m_PosY+dshad+1, m_PosX+m_Width+dshad, m_PosY+m_Height-1, cshad, 0, cshad, 0); PERF( DT = Timer.GetTime(); printf("Bg=%.4fms ", 1000.0*DT); ) // Draw hierarchy handle PERF( Timer.Reset(); ) DrawHierHandle(); PERF( DT = Timer.GetTime(); printf("Handles=%.4fms ", 1000.0*DT); ) // Draw labels PERF( Timer.Reset(); ) Gr->DrawText(m_LabelsTextObj, m_PosX+LevelSpace+6, m_PosY+m_VarY0, 0 /*m_ColLabelText*/, 0); PERF( DT = Timer.GetTime(); printf("Labels=%.4fms ", 1000.0*DT); ) // Draw values if( !m_IsPopupList ) { PERF( Timer.Reset(); ) Gr->DrawText(m_ValuesTextObj, m_PosX+m_VarX1, m_PosY+m_VarY0, 0 /*m_ColValText*/, 0 /*m_ColValBg*/); PERF( DT = Timer.GetTime(); printf("Values=%.4fms ", 1000.0*DT); ) } // Draw preview for color values and draw buttons and custom types int h, nh = (int)m_HierTags.size(); int yh = m_PosY+m_VarY0; int bw = IncrBtnWidth(m_Font->m_CharHeight); for( h=0; hIsGroup() ) { const CTwVarGroup * Grp = static_cast(m_HierTags[h].m_Var); if( Grp->m_SummaryCallback==CColorExt::SummaryCB && Grp->m_StructValuePtr!=NULL ) { // draw color value if( Grp->m_Vars.size()>0 && Grp->m_Vars[0]!=NULL && !Grp->m_Vars[0]->IsGroup() ) static_cast(Grp->m_Vars[0])->ValueToDouble(); // force ext update int ydecal = (g_TwMgr->m_GraphAPI==TW_OPENGL || g_TwMgr->m_GraphAPI==TW_OPENGL_CORE) ? 1 : 0; const int checker = 8; for( int c=0; cDrawRect(m_PosX+m_VarX1+(c*(m_VarX2-m_VarX1))/checker, yh+1+ydecal+((c%2)*(m_Font->m_CharHeight-2))/2, m_PosX+m_VarX1-1+((c+1)*(m_VarX2-m_VarX1))/checker, yh+ydecal+(((c%2)+1)*(m_Font->m_CharHeight-2))/2, 0xffffffff); Gr->DrawRect(m_PosX+m_VarX1, yh+1+ydecal, m_PosX+m_VarX2-1, yh+ydecal+m_Font->m_CharHeight-2, 0xbfffffff); const CColorExt *colExt = static_cast(Grp->m_StructValuePtr); color32 col = Color32FromARGBi((colExt->m_HasAlpha ? colExt->A : 255), colExt->R, colExt->G, colExt->B); if( col!=0 ) Gr->DrawRect(m_PosX+m_VarX1, yh+1+ydecal, m_PosX+m_VarX2-1, yh+ydecal+m_Font->m_CharHeight-2, col); /* Gr->DrawLine(m_PosX+m_VarX1-1, yh, m_PosX+m_VarX2+1, yh, 0xff000000); Gr->DrawLine(m_PosX+m_VarX1-1, yh+m_Font->m_CharHeight, m_PosX+m_VarX2+1, yh+m_Font->m_CharHeight, 0xff000000); Gr->DrawLine(m_PosX+m_VarX1-1, yh, m_PosX+m_VarX1-1, yh+m_Font->m_CharHeight, 0xff000000); Gr->DrawLine(m_PosX+m_VarX2, yh, m_PosX+m_VarX2, yh+m_Font->m_CharHeight, 0xff000000); */ } //else if( Grp->m_SummaryCallback==CustomTypeSummaryCB && Grp->m_StructValuePtr!=NULL ) //{ //} } else if( static_cast(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON && !m_IsPopupList ) { // draw button int cbx0, cbx1; if( m_ButtonAlign == BUTTON_ALIGN_LEFT ) { cbx0 = m_PosX+m_VarX1+2; cbx1 = m_PosX+m_VarX1+bw; } else if( m_ButtonAlign == BUTTON_ALIGN_CENTER ) { cbx0 = m_PosX+(m_VarX1+m_VarX2)/2-bw/2+1; cbx1 = m_PosX+(m_VarX1+m_VarX2)/2+bw/2-1; } else { cbx0 = m_PosX+m_VarX2-2*bw+bw/2; cbx1 = m_PosX+m_VarX2-2-bw/2; } int cby0 = yh+3; int cby1 = yh+m_Font->m_CharHeight-3; if( !static_cast(m_HierTags[h].m_Var)->m_ReadOnly ) { double BtnAutoDelta = g_TwMgr->m_Timer.GetTime() - m_HighlightClickBtnAuto; if( (m_HighlightClickBtn || (BtnAutoDelta>=0 && BtnAutoDelta<0.1)) && h==m_HighlightedLine ) { cbx0--; cby0--; cbx1--; cby1--; Gr->DrawRect(cbx0+2, cby0+2, cbx1+2, cby1+2, m_ColHighBtn); Gr->DrawLine(cbx0+3, cby1+3, cbx1+4, cby1+3, 0xAF000000); Gr->DrawLine(cbx1+3, cby0+3, cbx1+3, cby1+3, 0xAF000000); Gr->DrawLine(cbx0+2, cby0+2, cbx0+2, cby1+2, m_ColLine); Gr->DrawLine(cbx0+2, cby1+2, cbx1+2, cby1+2, m_ColLine); Gr->DrawLine(cbx1+2, cby1+2, cbx1+2, cby0+2, m_ColLine); Gr->DrawLine(cbx1+2, cby0+2, cbx0+2, cby0+2, m_ColLine); } else { Gr->DrawRect(cbx0+2, cby1+1, cbx1+2, cby1+2, (h==m_HighlightedLine)?0xAF000000:0x7F000000); Gr->DrawRect(cbx1+1, cby0+2, cbx1+2, cby1, (h==m_HighlightedLine)?0xAF000000:0x7F000000); Gr->DrawRect(cbx0, cby0, cbx1, cby1, (h==m_HighlightedLine)?m_ColHighBtn:m_ColBtn); Gr->DrawLine(cbx0, cby0, cbx0, cby1, m_ColLine); Gr->DrawLine(cbx0, cby1, cbx1, cby1, m_ColLine); Gr->DrawLine(cbx1, cby1, cbx1, cby0, m_ColLine); Gr->DrawLine(cbx1, cby0, cbx0, cby0, m_ColLine); } } else if( static_cast(m_HierTags[h].m_Var)->m_Val.m_Button.m_Callback!=NULL ) { Gr->DrawRect(cbx0+1, cby0+1, cbx1+1, cby1+1, m_ColBtn); } else if( static_cast(m_HierTags[h].m_Var)->m_Val.m_Button.m_Separator==1 ) { int LevelSpace = max(m_Font->m_CharHeight-6, 4); // space used by DrawHierHandles Gr->DrawLine(m_PosX+m_VarX0+m_HierTags[h].m_Level*LevelSpace, yh+m_Font->m_CharHeight/2, m_PosX+m_VarX2, yh+m_Font->m_CharHeight/2, m_ColSeparator ); } } else if( m_HierTags[h].m_Var->IsCustom() ) //static_cast(m_HierTags[h].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast(m_HierTags[h].m_Var)->m_Typem_Customs.size() ) { // record custom types CTwMgr::CMemberProxy *mProxy = static_cast(m_HierTags[h].m_Var)->m_Val.m_Custom.m_MemberProxy; if( mProxy!=NULL && mProxy->m_StructProxy!=NULL ) { CustomMap::iterator it = m_CustomRecords.find(mProxy->m_StructProxy); int xMin = m_PosX + m_VarX0 + m_HierTags[h].m_Level*LevelSpace; int xMax = m_PosX + m_VarX2 - 2; int yMin = yh + 1; int yMax = yh + m_Font->m_CharHeight; if( it==m_CustomRecords.end() ) { std::pair pr; pr.first = mProxy->m_StructProxy; pr.second.m_IndexMin = pr.second.m_IndexMax = mProxy->m_MemberIndex; pr.second.m_XMin = xMin; pr.second.m_XMax = xMax; pr.second.m_YMin = yMin; pr.second.m_YMax = yMax; pr.second.m_Y0 = 0; // will be filled by the draw loop below pr.second.m_Y1 = 0; // will be filled by the draw loop below pr.second.m_Var = mProxy->m_VarParent; m_CustomRecords.insert(pr); } else { it->second.m_IndexMin = min(it->second.m_IndexMin, mProxy->m_MemberIndex); it->second.m_IndexMax = min(it->second.m_IndexMax, mProxy->m_MemberIndex); it->second.m_XMin = min(it->second.m_XMin, xMin); it->second.m_XMax = max(it->second.m_XMax, xMax); it->second.m_YMin = min(it->second.m_YMin, yMin); it->second.m_YMax = max(it->second.m_YMax, yMax); it->second.m_Y0 = 0; it->second.m_Y1 = 0; assert( it->second.m_Var==mProxy->m_VarParent ); } } } yh += m_Font->m_CharHeight+m_Sep; } // Draw custom types for( CustomMap::iterator it = m_CustomRecords.begin(); it!=m_CustomRecords.end(); ++it ) { CTwMgr::CStructProxy *sProxy = it->first; assert( sProxy!=NULL ); CCustomRecord& r = it->second; if( sProxy->m_CustomDrawCallback!=NULL ) { int y0 = r.m_YMin - max(r.m_IndexMin - sProxy->m_CustomIndexFirst, 0)*(m_Font->m_CharHeight + m_Sep); int y1 = y0 + max(sProxy->m_CustomIndexLast - sProxy->m_CustomIndexFirst + 1, 0)*(m_Font->m_CharHeight + m_Sep) - 2; if( y0ChangeViewport(r.m_XMin, r.m_YMin, r.m_XMax-r.m_XMin+1, r.m_YMax-r.m_YMin+1, 0, y0-r.m_YMin+1); sProxy->m_CustomDrawCallback(r.m_XMax-r.m_XMin, y1-y0, sProxy->m_StructExtData, sProxy->m_StructClientData, this, r.m_Var); Gr->RestoreViewport(); } } } if( m_DrawHandles && !m_IsPopupList ) { // Draw -/+/o/click/v buttons if( (m_DrawIncrDecrBtn || m_DrawClickBtn || m_DrawListBtn || m_DrawBoolBtn || m_DrawRotoBtn) && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() ) { int y0 = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_Sep); if( m_DrawIncrDecrBtn ) { bool IsMin = false; bool IsMax = false; if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { const CTwVarAtom *Atom = static_cast(m_HierTags[m_HighlightedLine].m_Var); double v, vmin, vmax; v = Atom->ValueToDouble(); Atom->MinMaxStepToDouble(&vmin, &vmax, NULL); IsMax = (v>=vmax); IsMin = (v<=vmin); } /* Gr->DrawRect(m_PosX+m_VarX2-2*bw+1, y0+1, m_PosX+m_VarX2-bw-1, y0+m_Font->m_CharHeight-2, (m_HighlightDecrBtn && !IsMin)?m_ColHighBtn:m_ColBtn); Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, (m_HighlightIncrBtn && !IsMax)?m_ColHighBtn:m_ColBtn); // [-] Gr->DrawLine(m_PosX+m_VarX2-2*bw+3+(bw>8?1:0), y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw-2-(bw>8?1:0), y0+m_Font->m_CharHeight/2, IsMin?m_ColValTextRO:m_ColTitleText); // [+] Gr->DrawLine(m_PosX+m_VarX2-bw+3, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-2, y0+m_Font->m_CharHeight/2, IsMax?m_ColValTextRO:m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX2-bw/2, y0+m_Font->m_CharHeight/2-bw/2+2, m_PosX+m_VarX2-bw/2, y0+m_Font->m_CharHeight/2+bw/2-1, IsMax?m_ColValTextRO:m_ColTitleText); */ Gr->DrawRect(m_PosX+m_VarX2-3*bw+1, y0+1, m_PosX+m_VarX2-2*bw-1, y0+m_Font->m_CharHeight-2, (m_HighlightDecrBtn && !IsMin)?m_ColHighBtn:m_ColBtn); Gr->DrawRect(m_PosX+m_VarX2-2*bw+1, y0+1, m_PosX+m_VarX2-bw-1, y0+m_Font->m_CharHeight-2, (m_HighlightIncrBtn && !IsMax)?m_ColHighBtn:m_ColBtn); // [-] Gr->DrawLine(m_PosX+m_VarX2-3*bw+3+(bw>8?1:0), y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-2*bw-2-(bw>8?1:0), y0+m_Font->m_CharHeight/2, IsMin?m_ColValTextRO:m_ColTitleText); // [+] Gr->DrawLine(m_PosX+m_VarX2-2*bw+3, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw-2, y0+m_Font->m_CharHeight/2, IsMax?m_ColValTextRO:m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX2-bw-bw/2, y0+m_Font->m_CharHeight/2-bw/2+2, m_PosX+m_VarX2-bw-bw/2, y0+m_Font->m_CharHeight/2+bw/2-1, IsMax?m_ColValTextRO:m_ColTitleText); } else if( m_DrawListBtn ) { // [v] int eps = 1; int dx = -1; Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, m_HighlightListBtn?m_ColHighBtn:m_ColBtn); Gr->DrawLine(m_PosX+m_VarX2-bw+4+dx, y0+m_Font->m_CharHeight/2-eps, m_PosX+m_VarX2-bw/2+1+dx, y0+m_Font->m_CharHeight-4, m_ColTitleText, true); Gr->DrawLine(m_PosX+m_VarX2-bw/2+1+dx, y0+m_Font->m_CharHeight-4, m_PosX+m_VarX2-2+dx, y0+m_Font->m_CharHeight/2-1, m_ColTitleText, true); } else if( m_DrawBoolBtn ) { Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, m_HighlightBoolBtn?m_ColHighBtn:m_ColBtn); // [x] //Gr->DrawLine(m_PosX+m_VarX2-bw/2-bw/6, y0+m_Font->m_CharHeight/2-bw/6, m_PosX+m_VarX2-bw/2+bw/6, y0+m_Font->m_CharHeight/2+bw/6, m_ColTitleText, true); //Gr->DrawLine(m_PosX+m_VarX2-bw/2-bw/6, y0+m_Font->m_CharHeight/2+bw/6, m_PosX+m_VarX2-bw/2+bw/6, y0+m_Font->m_CharHeight/2-bw/6, m_ColTitleText, true); // [<>] int s = bw/4; int eps = 1; Gr->DrawLine(m_PosX+m_VarX2-bw/2-1, y0+m_Font->m_CharHeight/2-s, m_PosX+m_VarX2-bw/2-s-1, y0+m_Font->m_CharHeight/2, m_ColTitleText, true); Gr->DrawLine(m_PosX+m_VarX2-bw/2-s-1, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw/2-eps, y0+m_Font->m_CharHeight/2+s+1-eps, m_ColTitleText, true); //Gr->DrawLine(m_PosX+m_VarX2-bw/2+1, y0+m_Font->m_CharHeight/2+s, m_PosX+m_VarX2-bw/2+s+1, y0+m_Font->m_CharHeight/2, m_ColTitleText, true); //Gr->DrawLine(m_PosX+m_VarX2-bw/2+s+1, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw/2+1, y0+m_Font->m_CharHeight/2-s, m_ColTitleText, true); Gr->DrawLine(m_PosX+m_VarX2-bw/2+2, y0+m_Font->m_CharHeight/2-s, m_PosX+m_VarX2-bw/2+s+2, y0+m_Font->m_CharHeight/2, m_ColTitleText, true); Gr->DrawLine(m_PosX+m_VarX2-bw/2+s+2, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw/2+1+eps, y0+m_Font->m_CharHeight/2+s+1-eps, m_ColTitleText, true); } if( m_DrawRotoBtn ) { // [o] rotoslider button /* Gr->DrawRect(m_PosX+m_VarX1-bw-1, y0+1, m_PosX+m_VarX1-3, y0+m_Font->m_CharHeight-2, m_HighlightRotoBtn?m_ColHighBtn:m_ColBtn); Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-2, y0+m_Font->m_CharHeight/2-1, m_PosX+m_VarX1-bw+bw/2-1, y0+m_Font->m_CharHeight/2-1, m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-3, y0+m_Font->m_CharHeight/2+0, m_PosX+m_VarX1-bw+bw/2+0, y0+m_Font->m_CharHeight/2+0, m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-3, y0+m_Font->m_CharHeight/2+1, m_PosX+m_VarX1-bw+bw/2+0, y0+m_Font->m_CharHeight/2+1, m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-2, y0+m_Font->m_CharHeight/2+2, m_PosX+m_VarX1-bw+bw/2-1, y0+m_Font->m_CharHeight/2+2, m_ColTitleText); */ /* Gr->DrawRect(m_PosX+m_VarX2-3*bw+1, y0+1, m_PosX+m_VarX2-2*bw-1, y0+m_Font->m_CharHeight-2, m_HighlightRotoBtn?m_ColHighBtn:m_ColBtn); Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2+0, y0+m_Font->m_CharHeight/2-1, m_PosX+m_VarX2-3*bw+bw/2+1, y0+m_Font->m_CharHeight/2-1, m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2-1, y0+m_Font->m_CharHeight/2+0, m_PosX+m_VarX2-3*bw+bw/2+2, y0+m_Font->m_CharHeight/2+0, m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2-1, y0+m_Font->m_CharHeight/2+1, m_PosX+m_VarX2-3*bw+bw/2+2, y0+m_Font->m_CharHeight/2+1, m_ColTitleText); Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2+0, y0+m_Font->m_CharHeight/2+2, m_PosX+m_VarX2-3*bw+bw/2+1, y0+m_Font->m_CharHeight/2+2, m_ColTitleText); */ int dy = 0; Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, m_HighlightRotoBtn?m_ColHighBtn:m_ColBtn); Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2+0, y0+m_Font->m_CharHeight/2-1+dy, m_PosX+m_VarX2-bw+bw/2+1, y0+m_Font->m_CharHeight/2-1+dy, m_ColTitleText, true); Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2-1, y0+m_Font->m_CharHeight/2+0+dy, m_PosX+m_VarX2-bw+bw/2+2, y0+m_Font->m_CharHeight/2+0+dy, m_ColTitleText, true); Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2-1, y0+m_Font->m_CharHeight/2+1+dy, m_PosX+m_VarX2-bw+bw/2+2, y0+m_Font->m_CharHeight/2+1+dy, m_ColTitleText, true); Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2+0, y0+m_Font->m_CharHeight/2+2+dy, m_PosX+m_VarX2-bw+bw/2+1, y0+m_Font->m_CharHeight/2+2+dy, m_ColTitleText, true); } } // Draw value width slider if( !m_HighlightValWidth ) { color32 col = m_DarkText ? COLOR32_WHITE : m_ColTitleText; Gr->DrawRect(m_PosX+m_VarX1-2, m_PosY+m_VarY0-8, m_PosX+m_VarX1-1, m_PosY+m_VarY0-4, col); Gr->DrawLine(m_PosX+m_VarX1-1, m_PosY+m_VarY0-3, m_PosX+m_VarX1, m_PosY+m_VarY0-3, m_ColLineShadow); Gr->DrawLine(m_PosX+m_VarX1, m_PosY+m_VarY0-3, m_PosX+m_VarX1, m_PosY+m_VarY0-8, m_ColLineShadow); } else { color32 col = m_DarkText ? COLOR32_WHITE : m_ColTitleText; Gr->DrawRect(m_PosX+m_VarX1-2, m_PosY+m_VarY0-8, m_PosX+m_VarX1-1, m_PosY+m_VarY1, col); Gr->DrawLine(m_PosX+m_VarX1-1, m_PosY+m_VarY1+1, m_PosX+m_VarX1, m_PosY+m_VarY1+1, m_ColLineShadow); Gr->DrawLine(m_PosX+m_VarX1, m_PosY+m_VarY1+1, m_PosX+m_VarX1, m_PosY+m_VarY0-8, m_ColLineShadow); } // Draw labels & values headers if (m_HighlightLabelsHeader) { Gr->DrawRect(m_PosX+m_VarX0, m_PosY+m_Font->m_CharHeight+2, m_PosX+m_VarX1-4, m_PosY+m_VarY0-1, m_ColHighBg0, m_ColHighBg0, m_ColHighBg1, m_ColHighBg1); } if (m_HighlightValuesHeader) { Gr->DrawRect(m_PosX+m_VarX1+2, m_PosY+m_Font->m_CharHeight+2, m_PosX+m_VarX2, m_PosY+m_VarY0-1, m_ColHighBg0, m_ColHighBg0, m_ColHighBg1, m_ColHighBg1); } } // Draw key shortcut text if( m_HighlightedLine>=0 && m_HighlightedLine==m_ShortcutLine && !m_IsPopupList && !m_EditInPlace.m_Active ) { PERF( Timer.Reset(); ) Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg); Gr->DrawText(m_ShortcutTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColShortcutText, 0); PERF( DT = Timer.GetTime(); printf("Shortcut=%.4fms ", 1000.0*DT); ) } else if( (m_HighlightLabelsHeader || m_HighlightValuesHeader) && !m_IsPopupList && !m_EditInPlace.m_Active ) { Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg); Gr->DrawText(m_HeadersTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColShortcutText, 0); } else if( m_IsHelpBar ) { if( g_TwMgr->m_KeyPressedTextObj && g_TwMgr->m_KeyPressedStr.size()>0 ) // Draw key pressed { if( g_TwMgr->m_KeyPressedBuildText ) { string Str = g_TwMgr->m_KeyPressedStr; ClampText(Str, m_Font, m_Width-2*m_Font->m_CharHeight); g_TwMgr->m_Graph->BuildText(g_TwMgr->m_KeyPressedTextObj, &Str, NULL, NULL, 1, g_TwMgr->m_HelpBar->m_Font, 0, 0); g_TwMgr->m_KeyPressedBuildText = false; g_TwMgr->m_KeyPressedTime = (float)g_BarTimer.GetTime(); } if( (float)g_BarTimer.GetTime()>g_TwMgr->m_KeyPressedTime+1.0f ) // draw key pressed at least 1 second g_TwMgr->m_KeyPressedStr = ""; PERF( Timer.Reset(); ) Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg); Gr->DrawText(g_TwMgr->m_KeyPressedTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColShortcutText, 0); PERF( DT = Timer.GetTime(); printf("KeyPressed=%.4fms ", 1000.0*DT); ) } else { if( g_TwMgr->m_InfoBuildText ) { string Info = "> AntTweakBar"; char Ver[64]; sprintf(Ver, " (v%d.%02d)", TW_VERSION/100, TW_VERSION%100); Info += Ver; ClampText(Info, m_Font, m_Width-2*m_Font->m_CharHeight); g_TwMgr->m_Graph->BuildText(g_TwMgr->m_InfoTextObj, &Info, NULL, NULL, 1, g_TwMgr->m_HelpBar->m_Font, 0, 0); g_TwMgr->m_InfoBuildText = false; } PERF( Timer.Reset(); ) Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg); Gr->DrawText(g_TwMgr->m_InfoTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColInfoText, 0); PERF( DT = Timer.GetTime(); printf("Info=%.4fms ", 1000.0*DT); ) } } if( !m_IsPopupList ) { // Draw RotoSlider RotoDraw(); // Draw EditInPlace EditInPlaceDraw(); } if( g_TwMgr->m_PopupBar!=NULL && this!=g_TwMgr->m_PopupBar ) { // darken bar if a popup bar is displayed Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Height-1, 0x1F000000); } } } else // minimized { int vpx, vpy, vpw, vph; vpx = 0; vpy = 0; vpw = g_TwMgr->m_WndWidth; vph = g_TwMgr->m_WndHeight; if( g_TwMgr->m_IconMarginX>0 ) { vpx = min(g_TwMgr->m_IconMarginX, vpw/3); vpw -= 2 * vpx; } if( g_TwMgr->m_IconMarginY>0 ) { vpy = min(g_TwMgr->m_IconMarginY, vph/3); vph -= 2 * vpy; } int MinXOffset = 0, MinYOffset = 0; if( g_TwMgr->m_IconPos==3 ) // top-right { if( g_TwMgr->m_IconAlign==1 ) // horizontal { int n = max(1, vpw/m_Font->m_CharHeight-1); m_MinPosX = vpx + vpw-((m_MinNumber%n)+1)*m_Font->m_CharHeight; m_MinPosY = vpy + (m_MinNumber/n)*m_Font->m_CharHeight; MinYOffset = m_Font->m_CharHeight; MinXOffset = -m_TitleWidth; } else // vertical { int n = max(1, vph/m_Font->m_CharHeight-1); m_MinPosY = vpy + (m_MinNumber%n)*m_Font->m_CharHeight; m_MinPosX = vpx + vpw-((m_MinNumber/n)+1)*m_Font->m_CharHeight; MinXOffset = -m_TitleWidth-m_Font->m_CharHeight; } } else if( g_TwMgr->m_IconPos==2 ) // top-left { if( g_TwMgr->m_IconAlign==1 ) // horizontal { int n = max(1, vpw/m_Font->m_CharHeight-1); m_MinPosX = vpx + (m_MinNumber%n)*m_Font->m_CharHeight; m_MinPosY = vpy + (m_MinNumber/n)*m_Font->m_CharHeight; MinYOffset = m_Font->m_CharHeight; } else // vertical { int n = max(1, vph/m_Font->m_CharHeight-1); m_MinPosY = vpy + (m_MinNumber%n)*m_Font->m_CharHeight; m_MinPosX = vpx + (m_MinNumber/n)*m_Font->m_CharHeight; MinXOffset = m_Font->m_CharHeight; } } else if( g_TwMgr->m_IconPos==1 ) // bottom-right { if( g_TwMgr->m_IconAlign==1 ) // horizontal { int n = max(1, vpw/m_Font->m_CharHeight-1); m_MinPosX = vpx + vpw-((m_MinNumber%n)+1)*m_Font->m_CharHeight; m_MinPosY = vpy + vph-((m_MinNumber/n)+1)*m_Font->m_CharHeight; MinYOffset = -m_Font->m_CharHeight; MinXOffset = -m_TitleWidth; } else // vertical { int n = max(1, vph/m_Font->m_CharHeight-1); m_MinPosY = vpy + vph-((m_MinNumber%n)+1)*m_Font->m_CharHeight; m_MinPosX = vpx + vpw-((m_MinNumber/n)+1)*m_Font->m_CharHeight; MinXOffset = -m_TitleWidth-m_Font->m_CharHeight; } } else // bottom-left { if( g_TwMgr->m_IconAlign==1 ) // horizontal { int n = max(1, vpw/m_Font->m_CharHeight-1); m_MinPosX = vpx + (m_MinNumber%n)*m_Font->m_CharHeight; m_MinPosY = vpy + vph-((m_MinNumber/n)+1)*m_Font->m_CharHeight; MinYOffset = -m_Font->m_CharHeight; } else // vertical { int n = max(1, vph/m_Font->m_CharHeight-1); m_MinPosY = vpy + vph-((m_MinNumber%n)+1)*m_Font->m_CharHeight; m_MinPosX = vpx + (m_MinNumber/n)*m_Font->m_CharHeight; MinXOffset = m_Font->m_CharHeight; } } if( m_HighlightMaximize ) { // Draw title if( _DrawPart&DRAW_BG ) { Gr->DrawRect(m_MinPosX, m_MinPosY, m_MinPosX+m_Font->m_CharHeight, m_MinPosY+m_Font->m_CharHeight, m_ColTitleUnactiveBg); Gr->DrawRect(m_MinPosX+MinXOffset, m_MinPosY+MinYOffset, m_MinPosX+MinXOffset+m_TitleWidth+m_Font->m_CharHeight, m_MinPosY+MinYOffset+m_Font->m_CharHeight, m_ColTitleUnactiveBg); } if( _DrawPart&DRAW_CONTENT ) { if( m_ColTitleShadow!=0 ) Gr->DrawText(m_TitleTextObj, m_MinPosX+MinXOffset+m_Font->m_CharHeight/2, m_MinPosY+1+MinYOffset, m_ColTitleShadow, 0); Gr->DrawText(m_TitleTextObj, m_MinPosX+MinXOffset+m_Font->m_CharHeight/2, m_MinPosY+MinYOffset, m_ColTitleText, 0); } } if( !m_IsHelpBar ) { // Draw maximize button int xm = m_MinPosX+2, wm=m_Font->m_CharHeight-6; wm = (wm<6) ? 6 : wm; if( _DrawPart&DRAW_BG ) Gr->DrawRect(xm+1, m_MinPosY+4, xm+wm-1, m_MinPosY+3+wm, m_HighlightMaximize?m_ColHighBtn:m_ColBtn); if( _DrawPart&DRAW_CONTENT ) { Gr->DrawLine(xm, m_MinPosY+3, xm+wm, m_MinPosY+3, m_ColLine); Gr->DrawLine(xm+wm, m_MinPosY+3, xm+wm, m_MinPosY+3+wm, m_ColLine); Gr->DrawLine(xm+wm, m_MinPosY+3+wm, xm, m_MinPosY+3+wm, m_ColLine); Gr->DrawLine(xm, m_MinPosY+3+wm, xm, m_MinPosY+3, m_ColLine); Gr->DrawLine(xm+wm+1, m_MinPosY+4, xm+wm+1, m_MinPosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm+1, m_MinPosY+4+wm, xm, m_MinPosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm/3-1, m_MinPosY+3+wm-wm/3, xm+wm/2, m_MinPosY+6, m_ColTitleText, true); Gr->DrawLine(xm+wm-wm/3+1, m_MinPosY+3+wm-wm/3, xm+wm/2, m_MinPosY+6, m_ColTitleText, true); } } else { // Draw help button int xm = m_MinPosX+2, wm=m_Font->m_CharHeight-6; wm = (wm<6) ? 6 : wm; if( _DrawPart&DRAW_BG ) Gr->DrawRect(xm+1, m_MinPosY+4, xm+wm-1, m_MinPosY+3+wm, m_HighlightMaximize?m_ColHighBtn:m_ColBtn); if( _DrawPart&DRAW_CONTENT ) { Gr->DrawLine(xm, m_MinPosY+3, xm+wm, m_MinPosY+3, m_ColLine); Gr->DrawLine(xm+wm, m_MinPosY+3, xm+wm, m_MinPosY+3+wm, m_ColLine); Gr->DrawLine(xm+wm, m_MinPosY+3+wm, xm, m_MinPosY+3+wm, m_ColLine); Gr->DrawLine(xm, m_MinPosY+3+wm, xm, m_MinPosY+3, m_ColLine); Gr->DrawLine(xm+wm+1, m_MinPosY+4, xm+wm+1, m_MinPosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm+1, m_MinPosY+4+wm, xm, m_MinPosY+4+wm, m_ColLineShadow); Gr->DrawLine(xm+wm/2-wm/6, m_MinPosY+3+wm/4, xm+wm-wm/3, m_MinPosY+3+wm/4, m_ColTitleText); Gr->DrawLine(xm+wm-wm/3, m_MinPosY+3+wm/4, xm+wm-wm/3, m_MinPosY+3+wm/2, m_ColTitleText); Gr->DrawLine(xm+wm-wm/3, m_MinPosY+3+wm/2, xm+wm/2, m_MinPosY+3+wm/2, m_ColTitleText); Gr->DrawLine(xm+wm/2, m_MinPosY+3+wm/2, xm+wm/2, m_MinPosY+3+wm-wm/4, m_ColTitleText); Gr->DrawLine(xm+wm/2, m_MinPosY+3+wm-wm/4+1, xm+wm/2, m_MinPosY+3+wm-wm/4+2, m_ColTitleText); } } } } // --------------------------------------------------------------------------- bool CTwBar::MouseMotion(int _X, int _Y) { assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0); if( !m_UpToDate ) Update(); bool Handled = false; bool CustomArea = false; if( !m_IsMinimized ) { bool InBar = (_X>=m_PosX && _X=m_PosY && _Ym_Bars.size(); ++ib ) if( g_TwMgr->m_Bars[ib]!=NULL ) { g_TwMgr->m_Bars[ib]->m_DrawHandles = false; g_TwMgr->m_Bars[ib]->m_HighlightTitle = false; } m_DrawHandles = InBar; const int ContainedMargin = 32; if( !m_MouseDrag ) { Handled = InBar; m_HighlightedLine = -1; m_HighlightIncrBtn = false; m_HighlightDecrBtn = false; m_HighlightRotoBtn = false; if( abs(m_MouseOriginX-_X)>6 || abs(m_MouseOriginY-_Y)>6 ) m_HighlightClickBtn = false; m_HighlightListBtn = false; m_HighlightTitle = false; m_HighlightScroll = false; m_HighlightUpScroll = false; m_HighlightDnScroll = false; m_HighlightMinimize = false; m_HighlightFont = false; m_HighlightValWidth = false; m_HighlightLabelsHeader = false; m_HighlightValuesHeader = false; //if( InBar && _X>m_PosX+m_Font->m_CharHeight+1 && _X=m_PosY+m_VarY0 && _Ym_PosX+2 && _X=m_PosY+m_VarY0 && _Ym_CharHeight+m_Sep); if( m_HighlightedLine>=(int)m_HierTags.size() ) m_HighlightedLine = -1; else if(m_HighlightedLine>=0) m_HighlightedLineLastValid = m_HighlightedLine; if( m_HighlightedLine<0 || m_HierTags[m_HighlightedLine].m_Var==NULL || m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) ANT_SET_CURSOR(Arrow); else { if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider ) { if( static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && !m_IsHelpBar && !(static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BUTTON && static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_Val.m_Button.m_Callback==NULL) ) ANT_SET_CURSOR(No); //(Arrow); else { ANT_SET_CURSOR(Arrow); CustomArea = true; } if( m_DrawListBtn ) { m_HighlightListBtn = true; CustomArea = false; } if( m_DrawBoolBtn ) { m_HighlightBoolBtn = true; CustomArea = false; } } else if( m_DrawRotoBtn && ( _X>=m_PosX+m_VarX2-IncrBtnWidth(m_Font->m_CharHeight) || _X=m_PosX+m_VarX2-2*IncrBtnWidth(m_Font->m_CharHeight) ) // [+] button { m_HighlightIncrBtn = true; ANT_SET_CURSOR(Arrow); } else if( m_DrawIncrDecrBtn && _X>=m_PosX+m_VarX2-3*IncrBtnWidth(m_Font->m_CharHeight) ) // [-] button { m_HighlightDecrBtn = true; ANT_SET_CURSOR(Arrow); } else if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly ) { if( !m_IsHelpBar ) ANT_SET_CURSOR(No); else ANT_SET_CURSOR(Arrow); } else //ANT_SET_CURSOR(Point); ANT_SET_CURSOR(IBeam); } } else if( InBar && m_Movable && !m_IsPopupList && _X>=m_PosX+2*m_Font->m_CharHeight && _Xm_CharHeight && _Ym_CharHeight ) { // mouse over title m_HighlightTitle = true; ANT_SET_CURSOR(Move); } else if ( InBar && !m_IsPopupList && _X>=m_PosX+m_VarX1-5 && _Xm_PosY+m_Font->m_CharHeight && _Y=m_PosX+m_VarX0 && _Xm_PosY+m_Font->m_CharHeight && _Y=m_PosX+m_VarX1+5 && _Xm_PosY+m_Font->m_CharHeight && _Y=m_PosX && _Xm_CharHeight && _Y>=m_ScrollY0 && _Y=m_PosX+m_VarX2+2 && _X=m_ScrollY0 && _Y=m_PosX+m_VarX2+2 && _X=m_PosY+m_VarY0 && _Y=m_PosX+m_VarX2+2 && _X=m_ScrollY1 && _Y=m_PosX && _Xm_CharHeight && _Y>=m_PosY && _Ym_CharHeight ) ANT_SET_CURSOR(TopLeft); else if( InBar && !m_IsPopupList && _X>=m_PosX && _Xm_CharHeight && _Y>=m_PosY+m_Height-m_Font->m_CharHeight && _Y=m_PosX+m_Width-m_Font->m_CharHeight && _X=m_PosY && _Ym_CharHeight ) ANT_SET_CURSOR(TopRight); else if( InBar && m_Resizable && !m_IsPopupList && _X>=m_PosX+m_Width-m_Font->m_CharHeight && _X=m_PosY+m_Height-m_Font->m_CharHeight && _Ym_FontResizable && !m_IsPopupList && _X>=m_PosX+m_Font->m_CharHeight && _Xm_CharHeight && _Ym_CharHeight ) { m_HighlightFont = true; ANT_SET_CURSOR(Arrow); } else if( InBar && m_Iconifiable && !m_IsPopupList && _X>=m_PosX+m_Width-2*m_Font->m_CharHeight && _Xm_CharHeight && _Ym_CharHeight ) { m_HighlightMinimize = true; ANT_SET_CURSOR(Arrow); } else if( m_IsHelpBar && InBar && _X>=m_PosX+m_VarX0 && _Xm_CharHeight && _Y>m_PosY+m_Height-m_Font->m_CharHeight && _Y=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { /* CTwVarAtom *Var = static_cast(m_HierTags[m_HighlightedLine].m_Var); int Delta = _X-m_MouseOriginX; if( Delta!=0 ) { if( !Var->m_NoSlider && !Var->m_ReadOnly ) { Var->Increment(Delta); NotUpToDate(); } m_VarHasBeenIncr = true; } m_MouseOriginX = _X; m_MouseOriginY = _Y; if( !Var->m_NoSlider && !Var->m_ReadOnly ) ANT_SET_CURSOR(Center); //ANT_SET_CURSOR(WE); else ANT_SET_CURSOR(Arrow); Handled = true; */ // move rotoslider if( !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider ) RotoOnMouseMove(_X, _Y); if( static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly ) ANT_SET_CURSOR(No); else if( static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider ) { ANT_SET_CURSOR(Arrow); CustomArea = true; } m_VarHasBeenIncr = true; Handled = true; m_DrawHandles = true; } else if( m_MouseDragTitle ) { int y = m_PosY; m_PosX += _X-m_MouseOriginX; m_PosY += _Y-m_MouseOriginY; m_MouseOriginX = _X; m_MouseOriginY = _Y; int vpx, vpy, vpw, vph; vpx = 0; vpy = 0; vpw = g_TwMgr->m_WndWidth; vph = g_TwMgr->m_WndHeight; if( m_Contained ) { if( m_PosX+m_Width>vpx+vpw ) m_PosX = vpx+vpw-m_Width; if( m_PosXvpy+vph ) m_PosY = vpy+vph-m_Height; if( m_PosYvpx+vpw ) m_PosX = vpx+vpw-ContainedMargin; if( m_PosX+m_Widthvpy+vph ) m_PosY = vpy+vph-ContainedMargin; if( m_PosY+m_Heightm_HelpBarNotUpToDate = true; ANT_SET_CURSOR(WE); Handled = true; m_DrawHandles = true; } else if( m_MouseDragScroll ) { if( m_ScrollYH>0 ) { int dl = ((_Y-m_MouseOriginY)*m_NbHierLines)/m_ScrollYH; if( m_FirstLine0+dl<0 ) m_FirstLine = 0; else if( m_FirstLine0+dl+m_NbDisplayedLines>m_NbHierLines ) m_FirstLine = m_NbHierLines-m_NbDisplayedLines; else m_FirstLine = m_FirstLine0+dl; NotUpToDate(); } #ifdef ANT_WINDOWS ANT_SET_CURSOR(NS); #else ANT_SET_CURSOR(Arrow); #endif Handled = true; m_DrawHandles = true; } else if( m_MouseDragResizeUL ) { int w = m_Width; int h = m_Height; m_PosX += _X-m_MouseOriginX; m_PosY += _Y-m_MouseOriginY; m_Width -= _X-m_MouseOriginX; m_Height -= _Y-m_MouseOriginY; m_MouseOriginX = _X; m_MouseOriginY = _Y; int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight; if( !m_Contained ) { if( m_PosX+ContainedMargin>vpx+vpw ) m_PosX = vpx+vpw-ContainedMargin; if( m_PosX+m_Widthvpy+vph ) m_PosY = vpy+vph-ContainedMargin; if( m_PosY+m_Height 0) m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5); ANT_SET_CURSOR(TopLeft); NotUpToDate(); if( m_IsHelpBar ) { g_TwMgr->m_HelpBarNotUpToDate = true; g_TwMgr->m_HelpBarUpdateNow = true; } g_TwMgr->m_KeyPressedBuildText = true; g_TwMgr->m_InfoBuildText = true; Handled = true; m_DrawHandles = true; } else if( m_MouseDragResizeUR ) { int h = m_Height; m_PosY += _Y-m_MouseOriginY; m_Width += _X-m_MouseOriginX; m_Height -= _Y-m_MouseOriginY; m_MouseOriginX = _X; m_MouseOriginY = _Y; int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight; if( !m_Contained ) { if( m_PosX+ContainedMargin>vpx+vpw ) m_PosX = vpx+vpw-ContainedMargin; if( m_PosX+m_Widthvpy+vph ) m_PosY = vpy+vph-ContainedMargin; if( m_PosY+m_Heightvpx+vpw ) m_Width = vpx+vpw-m_PosX; if( m_PosY 0) m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5); ANT_SET_CURSOR(TopRight); NotUpToDate(); if( m_IsHelpBar ) { g_TwMgr->m_HelpBarNotUpToDate = true; g_TwMgr->m_HelpBarUpdateNow = true; } g_TwMgr->m_KeyPressedBuildText = true; g_TwMgr->m_InfoBuildText = true; Handled = true; m_DrawHandles = true; } else if( m_MouseDragResizeLL ) { int w = m_Width; m_PosX += _X-m_MouseOriginX; m_Width -= _X-m_MouseOriginX; m_Height += _Y-m_MouseOriginY; m_MouseOriginX = _X; m_MouseOriginY = _Y; int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight; if( !m_Contained ) { if( m_PosX+ContainedMargin>vpx+vpw ) m_PosX = vpx+vpw-ContainedMargin; if( m_PosX+m_Widthvpy+vph ) m_PosY = vpy+vph-ContainedMargin; if( m_PosY+m_Heightvpy+vph ) m_Height = vpy+vph-m_PosY; if( m_PosX 0) m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5); ANT_SET_CURSOR(BottomLeft); NotUpToDate(); if( m_IsHelpBar ) { g_TwMgr->m_HelpBarNotUpToDate = true; g_TwMgr->m_HelpBarUpdateNow = true; } g_TwMgr->m_KeyPressedBuildText = true; g_TwMgr->m_InfoBuildText = true; Handled = true; m_DrawHandles = true; } else if( m_MouseDragResizeLR ) { m_Width += _X-m_MouseOriginX; m_Height += _Y-m_MouseOriginY; m_MouseOriginX = _X; m_MouseOriginY = _Y; int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight; if( !m_Contained ) { if( m_PosX+ContainedMargin>vpx+vpw ) m_PosX = vpx+vpw-ContainedMargin; if( m_PosX+m_Widthvpy+vph ) m_PosY = vpy+vph-ContainedMargin; if( m_PosY+m_Heightvpx+vpw ) m_Width = vpx+vpw-m_PosX; if( m_PosY+m_Height>vpy+vph ) m_Height = vpy+vph-m_PosY; } if (m_ValuesWidthRatio > 0) m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5); ANT_SET_CURSOR(BottomRight); NotUpToDate(); if( m_IsHelpBar ) { g_TwMgr->m_HelpBarNotUpToDate = true; g_TwMgr->m_HelpBarUpdateNow = true; } g_TwMgr->m_KeyPressedBuildText = true; g_TwMgr->m_InfoBuildText = true; Handled = true; m_DrawHandles = true; } else if( m_EditInPlace.m_Active ) { EditInPlaceMouseMove(_X, _Y, true); ANT_SET_CURSOR(IBeam); Handled = true; } //else if( InBar ) // ANT_SET_CURSOR(Arrow); } } else // minimized { if( m_Iconifiable && _X>=m_MinPosX+2 && _Xm_CharHeight && _Y>m_MinPosY && _Ym_CharHeight-2 ) { m_HighlightMaximize = true; if( !m_IsHelpBar ) ANT_SET_CURSOR(Arrow); else #ifdef ANT_WINDOWS ANT_SET_CURSOR(Help); #else ANT_SET_CURSOR(Arrow); #endif Handled = true; } else m_HighlightMaximize = false; } // Handled by a custom widget? CTwMgr::CStructProxy *currentCustomActiveStructProxy = NULL; if( g_TwMgr!=NULL && (!Handled || CustomArea) && !m_IsMinimized && m_CustomRecords.size()>0 ) { bool CustomHandled = false; for( int s=0; s<2; ++s ) // 2 iterations: first for custom widget having focus, second for others if no focused widget. for( CustomMap::iterator it=m_CustomRecords.begin(); it!=m_CustomRecords.end(); ++it ) { CTwMgr::CStructProxy *sProxy = it->first; const CCustomRecord& r = it->second; if( (s==1 || sProxy->m_CustomCaptureFocus) && !CustomHandled && sProxy!=NULL && sProxy->m_CustomMouseMotionCallback!=NULL && r.m_XMin=r.m_Y0 && r.m_YMax<=r.m_Y1 ) { if( sProxy->m_CustomCaptureFocus || (_X>=r.m_XMin && _X=r.m_YMin && _Ym_CustomMouseMotionCallback(_X-r.m_XMin, _Y-r.m_Y0, r.m_XMax-r.m_XMin, r.m_Y1-r.m_Y0, sProxy->m_StructExtData, sProxy->m_StructClientData, this, r.m_Var); currentCustomActiveStructProxy = sProxy; s = 2; // force s-loop exit } } else if( sProxy!=NULL ) { sProxy->m_CustomCaptureFocus = false; // force free focus, just in case. ANT_SET_CURSOR(Arrow); } } if( CustomHandled ) Handled = true; } // If needed, send a 'MouseLeave' message to previously active custom struct if( g_TwMgr!=NULL && m_CustomActiveStructProxy!=NULL && m_CustomActiveStructProxy!=currentCustomActiveStructProxy ) { bool found = false; for( list::iterator it=g_TwMgr->m_StructProxies.begin(); it!=g_TwMgr->m_StructProxies.end() && !found; ++it ) found = (&(*it)==m_CustomActiveStructProxy); if( found && m_CustomActiveStructProxy->m_CustomMouseLeaveCallback!=NULL ) m_CustomActiveStructProxy->m_CustomMouseLeaveCallback(m_CustomActiveStructProxy->m_StructExtData, m_CustomActiveStructProxy->m_StructClientData, this); } m_CustomActiveStructProxy = currentCustomActiveStructProxy; return Handled; } // --------------------------------------------------------------------------- #ifdef ANT_WINDOWS # pragma optimize("", off) // disable optimizations because the conversion of Enum from unsigned int to double is not always exact if optimized and GraphAPI=DirectX ! #endif static void ANT_CALL PopupCallback(void *_ClientData) { CTwFPU fpu; // force fpu precision if( g_TwMgr!=NULL && g_TwMgr->m_PopupBar!=NULL ) { unsigned int Enum = *(unsigned int *)&_ClientData; CTwVarAtom *Var = g_TwMgr->m_PopupBar->m_VarEnumLinkedToPopupList; CTwBar *Bar = g_TwMgr->m_PopupBar->m_BarLinkedToPopupList; if( Bar!=NULL && Var!=NULL && !Var->m_ReadOnly && IsEnumType(Var->m_Type) ) { Var->ValueFromDouble(Enum); //Bar->UnHighlightLine(); Bar->HaveFocus(true); Bar->NotUpToDate(); } TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } } #ifdef ANT_WINDOWS # pragma optimize("", on) #endif // --------------------------------------------------------------------------- bool CTwBar::MouseButton(ETwMouseButtonID _Button, bool _Pressed, int _X, int _Y) { assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0); bool Handled = false; if( !m_UpToDate ) Update(); bool EditInPlaceActive = false; bool CustomArea = false; if( !m_IsMinimized ) { Handled = (_X>=m_PosX && _X=m_PosY && _Y=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var ) { if( m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { if( _Pressed && !g_TwMgr->m_IsRepeatingMousePressed ) { CTwVarGroup *Grp = static_cast(m_HierTags[m_HighlightedLine].m_Var); Grp->m_Open = !Grp->m_Open; NotUpToDate(); ANT_SET_CURSOR(Arrow); } } else if( _Pressed && m_HighlightIncrBtn ) { static_cast(m_HierTags[m_HighlightedLine].m_Var)->Increment(1); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; NotUpToDate(); } else if( _Pressed && m_HighlightDecrBtn ) { static_cast(m_HierTags[m_HighlightedLine].m_Var)->Increment(-1); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; NotUpToDate(); } else if( _Pressed && !m_MouseDrag ) { m_MouseDrag = true; m_MouseDragVar = true; m_MouseOriginX = _X; m_MouseOriginY = _Y; m_VarHasBeenIncr = false; CTwVarAtom * Var = static_cast(m_HierTags[m_HighlightedLine].m_Var); if( !Var->m_NoSlider && !Var->m_ReadOnly && m_HighlightRotoBtn ) { // begin rotoslider if( _X>m_PosX+m_VarX1 ) RotoOnLButtonDown(m_PosX+m_VarX2-(1*IncrBtnWidth(m_Font->m_CharHeight))/2, _Y); else RotoOnLButtonDown(_X, _Y); m_MouseDrag = true; m_MouseDragVar = true; } else if( (Var->m_Type==TW_TYPE_BOOL8 || Var->m_Type==TW_TYPE_BOOL16 || Var->m_Type==TW_TYPE_BOOL32 || Var->m_Type==TW_TYPE_BOOLCPP) && !Var->m_ReadOnly ) { Var->Increment(1); //m_HighlightClickBtn = true; m_VarHasBeenIncr = true; m_MouseDragVar = false; m_MouseDrag = false; NotUpToDate(); } else if( Var->m_Type==TW_TYPE_BUTTON && !Var->m_ReadOnly ) { m_HighlightClickBtn = true; m_MouseDragVar = false; m_MouseDrag = false; } //else if( (Var->m_Type==TW_TYPE_ENUM8 || Var->m_Type==TW_TYPE_ENUM16 || Var->m_Type==TW_TYPE_ENUM32) && !Var->m_ReadOnly ) else if( IsEnumType(Var->m_Type) && !Var->m_ReadOnly && !g_TwMgr->m_IsRepeatingMousePressed ) { m_MouseDragVar = false; m_MouseDrag = false; if( g_TwMgr->m_PopupBar!=NULL ) { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } // popup list CTwMgr::CEnum& e = g_TwMgr->m_Enums[Var->m_Type-TW_TYPE_ENUM_BASE]; g_TwMgr->m_PopupBar = TwNewBar("~ Enum Popup ~"); g_TwMgr->m_PopupBar->m_IsPopupList = true; g_TwMgr->m_PopupBar->m_Color = m_Color; g_TwMgr->m_PopupBar->m_DarkText = m_DarkText; g_TwMgr->m_PopupBar->m_PosX = m_PosX + m_VarX1 - 2; g_TwMgr->m_PopupBar->m_PosY = m_PosY + m_VarY0 + (m_HighlightedLine+1)*(m_Font->m_CharHeight+m_Sep); g_TwMgr->m_PopupBar->m_Width = m_Width - 2*m_Font->m_CharHeight; int popHeight0 = (int)e.m_Entries.size()*(m_Font->m_CharHeight+m_Sep) + m_Font->m_CharHeight/2+2; int popHeight = popHeight0; if( g_TwMgr->m_PopupBar->m_PosY+popHeight+2 > g_TwMgr->m_WndHeight ) popHeight = g_TwMgr->m_WndHeight-g_TwMgr->m_PopupBar->m_PosY-2; if( popHeightm_WndHeight/2 ) popHeight = min(popHeight0, g_TwMgr->m_WndHeight/2); if( popHeight<3*(m_Font->m_CharHeight+m_Sep) ) popHeight = 3*(m_Font->m_CharHeight+m_Sep); g_TwMgr->m_PopupBar->m_Height = popHeight; g_TwMgr->m_PopupBar->m_VarEnumLinkedToPopupList = Var; g_TwMgr->m_PopupBar->m_BarLinkedToPopupList = this; unsigned int CurrentEnumValue = (unsigned int)((int)Var->ValueToDouble()); for( CTwMgr::CEnum::CEntries::iterator It=e.m_Entries.begin(); It!=e.m_Entries.end(); ++It ) { char ID[64]; sprintf(ID, "%u", It->first); //ultoa(It->first, ID, 10); TwAddButton(g_TwMgr->m_PopupBar, ID, PopupCallback, *(void**)&(It->first), NULL); CTwVar *Btn = g_TwMgr->m_PopupBar->Find(ID); if( Btn!=NULL ) { Btn->m_Label = It->second.c_str(); if( It->first==CurrentEnumValue ) { Btn->m_ColorPtr = &m_ColValTextNE; Btn->m_BgColorPtr = &m_ColGrpBg; } } } g_TwMgr->m_HelpBarNotUpToDate = false; } else if( (Var->m_ReadOnly && (Var->m_Type==TW_TYPE_CDSTRING || Var->m_Type==TW_TYPE_CDSTDSTRING || Var->m_Type==TW_TYPE_STDSTRING || IsCSStringType(Var->m_Type)) && EditInPlaceAcceptVar(Var)) || (!Var->m_ReadOnly && EditInPlaceAcceptVar(Var)) ) { int dw = 0; //if( m_DrawIncrDecrBtn ) // dw = 2*IncrBtnWidth(m_Font->m_CharHeight); if( !m_EditInPlace.m_Active || m_EditInPlace.m_Var!=Var ) { EditInPlaceStart(Var, m_VarX1, m_VarY0+(m_HighlightedLine)*(m_Font->m_CharHeight+m_Sep), m_VarX2-m_VarX1-dw-1); if( EditInPlaceIsReadOnly() ) EditInPlaceMouseMove(_X, _Y, false); m_MouseDrag = false; m_MouseDragVar = false; } else { EditInPlaceMouseMove(_X, _Y, false); m_MouseDrag = true; m_MouseDragVar = false; } EditInPlaceActive = m_EditInPlace.m_Active; if( Var->m_ReadOnly ) ANT_SET_CURSOR(No); else ANT_SET_CURSOR(IBeam); } else if( Var->m_ReadOnly ) ANT_SET_CURSOR(No); else { ANT_SET_CURSOR(Arrow); CustomArea = true; } } else if ( !_Pressed && m_MouseDragVar ) { m_MouseDrag = false; m_MouseDragVar = false; if( !Handled ) m_DrawHandles = false; Handled = true; // end rotoslider RotoOnLButtonUp(_X, _Y); /* Incr/decr on right or left click if( !m_VarHasBeenIncr && !static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly ) { if( _Button==TW_MOUSE_LEFT ) static_cast(m_HierTags[m_HighlightedLine].m_Var)->Increment(-1); else if( _Button==TW_MOUSE_RIGHT ) static_cast(m_HierTags[m_HighlightedLine].m_Var)->Increment(1); NotUpToDate(); } */ if( static_cast(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly ) ANT_SET_CURSOR(No); else { ANT_SET_CURSOR(Arrow); CustomArea = true; } } else if( !_Pressed && m_HighlightClickBtn ) // a button variable is activated { m_HighlightClickBtn = false; m_MouseDragVar = false; m_MouseDrag = false; Handled = true; NotUpToDate(); if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { CTwVarAtom * Var = static_cast(m_HierTags[m_HighlightedLine].m_Var); if( !Var->m_ReadOnly && Var->m_Type==TW_TYPE_BUTTON && Var->m_Val.m_Button.m_Callback!=NULL ) { Var->m_Val.m_Button.m_Callback(Var->m_ClientData); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; } } } else if( !_Pressed ) { m_MouseDragVar = false; m_MouseDrag = false; CustomArea = true; } } else if( _Pressed && !m_MouseDrag && m_Movable && !m_IsPopupList && ( (_Button==TW_MOUSE_LEFT && _X>=m_PosX+2*m_Font->m_CharHeight && _Xm_CharHeight && _Y>=m_PosY && _Ym_CharHeight) || (_Button==TW_MOUSE_MIDDLE && _X>=m_PosX && _X=m_PosY && _Y=m_PosX+m_VarX1-3 && _Xm_PosY+m_Font->m_CharHeight && _Y=m_PosX+m_VarX2+2 && _X=m_ScrollY0 && _Y=m_PosX+m_VarX2+2 && _X=m_PosY+m_VarY0 && _Y0 ) { --m_FirstLine; NotUpToDate(); } } else if( _Pressed && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_VarX2+2 && _X=m_ScrollY1 && _Y=m_PosX && _Xm_CharHeight && _Y>=m_PosY && _Ym_CharHeight ) { m_MouseDrag = true; m_MouseDragResizeUL = true; m_MouseOriginX = _X; m_MouseOriginY = _Y; m_ValuesWidthRatio = (m_Width>0) ? (double)m_ValuesWidth/m_Width : 0; ANT_SET_CURSOR(TopLeft); } else if( !_Pressed && m_MouseDragResizeUL ) { m_MouseDrag = false; m_MouseDragResizeUL = false; ANT_SET_CURSOR(Arrow); } else if( _Pressed && !m_MouseDrag && m_Resizable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_Width-m_Font->m_CharHeight && _X=m_PosY && _Ym_CharHeight ) { m_MouseDrag = true; m_MouseDragResizeUR = true; m_MouseOriginX = _X; m_MouseOriginY = _Y; m_ValuesWidthRatio = (m_Width>0) ? (double)m_ValuesWidth/m_Width : 0; ANT_SET_CURSOR(TopRight); } else if( !_Pressed && m_MouseDragResizeUR ) { m_MouseDrag = false; m_MouseDragResizeUR = false; ANT_SET_CURSOR(Arrow); } else if( _Pressed && !m_MouseDrag && m_Resizable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX && _Xm_CharHeight && _Y>=m_PosY+m_Height-m_Font->m_CharHeight && _Y0) ? (double)m_ValuesWidth/m_Width : 0; ANT_SET_CURSOR(BottomLeft); } else if( !_Pressed && m_MouseDragResizeLL ) { m_MouseDrag = false; m_MouseDragResizeLL = false; ANT_SET_CURSOR(Arrow); } else if( _Pressed && !m_MouseDrag && m_Resizable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_Width-m_Font->m_CharHeight && _X=m_PosY+m_Height-m_Font->m_CharHeight && _Y0) ? (double)m_ValuesWidth/m_Width : 0; ANT_SET_CURSOR(BottomRight); } else if( !_Pressed && m_MouseDragResizeLR ) { m_MouseDrag = false; m_MouseDragResizeLR = false; ANT_SET_CURSOR(Arrow); } else if( _Pressed && !m_IsPopupList && _Button==TW_MOUSE_LEFT && m_HighlightLabelsHeader ) { int w = ComputeLabelsWidth(m_Font); if( wm_CharHeight ) w = m_Font->m_CharHeight; m_ValuesWidth = m_VarX2 - m_VarX0 - w; if( m_ValuesWidthm_CharHeight ) m_ValuesWidth = m_Font->m_CharHeight; if( m_ValuesWidth>m_VarX2 - m_VarX0 ) m_ValuesWidth = max(m_VarX2 - m_VarX0 - m_Font->m_CharHeight, 0); NotUpToDate(); ANT_SET_CURSOR(Arrow); } else if( _Pressed && !m_IsPopupList && _Button==TW_MOUSE_LEFT && m_HighlightValuesHeader ) { int w = ComputeValuesWidth(m_Font); if( w<2*m_Font->m_CharHeight ) w = 2*m_Font->m_CharHeight; // enough to draw a button m_ValuesWidth = w; if( m_ValuesWidth>m_VarX2 - m_VarX0 ) m_ValuesWidth = max(m_VarX2 - m_VarX0 - m_Font->m_CharHeight, 0); NotUpToDate(); ANT_SET_CURSOR(Arrow); } else if( _Pressed && g_TwMgr->m_FontResizable && !m_IsPopupList && _X>=m_PosX+m_Font->m_CharHeight && _Xm_CharHeight && _Y>m_PosY && _Ym_CharHeight ) { // change font if( _Button==TW_MOUSE_LEFT ) { if( m_Font==g_DefaultSmallFont ) g_TwMgr->SetFont(g_DefaultNormalFont, true); else if( m_Font==g_DefaultNormalFont ) g_TwMgr->SetFont(g_DefaultLargeFont, true); else if( m_Font==g_DefaultLargeFont ) g_TwMgr->SetFont(g_DefaultSmallFont, true); else g_TwMgr->SetFont(g_DefaultNormalFont, true); } else if( _Button==TW_MOUSE_RIGHT ) { if( m_Font==g_DefaultSmallFont ) g_TwMgr->SetFont(g_DefaultLargeFont, true); else if( m_Font==g_DefaultNormalFont ) g_TwMgr->SetFont(g_DefaultSmallFont, true); else if( m_Font==g_DefaultLargeFont ) g_TwMgr->SetFont(g_DefaultNormalFont, true); else g_TwMgr->SetFont(g_DefaultNormalFont, true); } ANT_SET_CURSOR(Arrow); } else if( _Pressed && m_Iconifiable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_Width-2*m_Font->m_CharHeight && _Xm_CharHeight && _Y>m_PosY && _Ym_CharHeight ) { // minimize g_TwMgr->Minimize(this); ANT_SET_CURSOR(Arrow); } else if( m_IsHelpBar && _Pressed && !g_TwMgr->m_IsRepeatingMousePressed && _X>=m_PosX+m_VarX0 && _Xm_CharHeight && _Y>m_PosY+m_Height-m_Font->m_CharHeight && _Y& null &", browser, WebPage); if( system(cmd) ) {} // avoiding warn_unused_result browser = strtok(NULL, ","); // grab the next browser } #elif defined ANT_OSX char cmd[256]; snprintf(cmd, sizeof(cmd), "open \"%s\" 1>& null &", WebPage); if( system(cmd) ) {} // avoiding warn_unused_result #endif ANT_SET_CURSOR(Hand); */ } else { CustomArea = true; } } else // minimized { if( _Pressed && m_HighlightMaximize ) { m_HighlightMaximize = false; g_TwMgr->Maximize(this); ANT_SET_CURSOR(Arrow); Handled = true; } } if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call if( _Pressed && !EditInPlaceActive && m_EditInPlace.m_Active ) EditInPlaceEnd(true); // Handled by a custom widget? if( g_TwMgr!=NULL && (!Handled || CustomArea) && !m_IsMinimized && m_CustomRecords.size()>0 ) { bool CustomHandled = false; for( int s=0; s<2; ++s ) // 2 iterations: first for custom widget having focus, second for others if no focused widget. for( CustomMap::iterator it=m_CustomRecords.begin(); it!=m_CustomRecords.end(); ++it ) { CTwMgr::CStructProxy *sProxy = it->first; const CCustomRecord& r = it->second; if( (s==1 || sProxy->m_CustomCaptureFocus) && !CustomHandled && sProxy!=NULL && sProxy->m_CustomMouseButtonCallback!=NULL && r.m_XMin=r.m_Y0 && r.m_YMax<=r.m_Y1 ) { if( sProxy->m_CustomCaptureFocus || (_X>=r.m_XMin && _X=r.m_YMin && _Ym_CustomCaptureFocus = _Pressed; CustomHandled = sProxy->m_CustomMouseButtonCallback(_Button, _Pressed, _X-r.m_XMin, _Y-r.m_Y0, r.m_XMax-r.m_XMin, r.m_Y1-r.m_Y0, sProxy->m_StructExtData, sProxy->m_StructClientData, this, r.m_Var); s = 2; // force s-loop exit } } else if( sProxy!=NULL ) { sProxy->m_CustomCaptureFocus = false; // force free focus, just in case. ANT_SET_CURSOR(Arrow); } } if( CustomHandled ) Handled = true; } return Handled; } // --------------------------------------------------------------------------- bool CTwBar::MouseWheel(int _Pos, int _PrevPos, int _MouseX, int _MouseY) { assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0); if( !m_UpToDate ) Update(); bool Handled = false; if( !m_IsMinimized && _MouseX>=m_PosX && _MouseX=m_PosY && _MouseY_PrevPos && m_FirstLine>0 ) { --m_FirstLine; NotUpToDate(); } else if( _Pos<_PrevPos && m_FirstLine' ' && _Key<256 ) // don't test SHIFT if _Key is a common key Mask &= ~TW_KMOD_SHIFT; // don't test KMOD_NUM and KMOD_CAPS modifiers coming from SDL Mask &= ~(0x1000); // 0x1000 is the KMOD_NUM value defined in SDL_keysym.h Mask &= ~(0x2000); // 0x2000 is the KMOD_CAPS value defined in SDL_keysym.h // complete partial modifiers comming from SDL if( _Modifiers & TW_KMOD_SHIFT ) _Modifiers |= TW_KMOD_SHIFT; if( _Modifiers & TW_KMOD_CTRL ) _Modifiers |= TW_KMOD_CTRL; if( _Modifiers & TW_KMOD_ALT ) _Modifiers |= TW_KMOD_ALT; if( _Modifiers & TW_KMOD_META ) _Modifiers |= TW_KMOD_META; for(size_t i=0; iIsGroup() ) { Atom = static_cast(m_Vars[i])->FindShortcut(_Key, _Modifiers, _DoIncr); if( Atom!=NULL ) return Atom; } else { Atom = static_cast(m_Vars[i]); if( Atom->m_KeyIncr[0]==_Key && (Atom->m_KeyIncr[1]&Mask)==(_Modifiers&Mask) ) { if( _DoIncr!=NULL ) *_DoIncr = true; return Atom; } else if( Atom->m_KeyDecr[0]==_Key && (Atom->m_KeyDecr[1]&Mask)==(_Modifiers&Mask) ) { if( _DoIncr!=NULL ) *_DoIncr = false; return Atom; } } } return NULL; } bool CTwBar::KeyPressed(int _Key, int _Modifiers) { assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0); bool Handled = false; if( !m_UpToDate ) Update(); if( _Key>0 && _Key0 && _Key<32 ) _Key += 'a'-1; // PAD translation (for SDL keysym) if( _Key>=256 && _Key<=272 ) // 256=SDLK_KP0 ... 272=SDLK_KP_EQUALS { bool Num = ((_Modifiers&TW_KMOD_SHIFT) && !(_Modifiers&0x1000)) || (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM _Modifiers &= ~TW_KMOD_SHIFT; // remove shift modifier if( _Key==266 ) // SDLK_KP_PERIOD _Key = Num ? '.' : TW_KEY_DELETE; else if( _Key==267 ) // SDLK_KP_DIVIDE _Key = '/'; else if( _Key==268 ) // SDLK_KP_MULTIPLY _Key = '*'; else if( _Key==269 ) // SDLK_KP_MINUS _Key = '-'; else if( _Key==270 ) // SDLK_KP_PLUS _Key = '+'; else if( _Key==271 ) // SDLK_KP_ENTER _Key = TW_KEY_RETURN; else if( _Key==272 ) // SDLK_KP_EQUALS _Key = '='; else if( Num ) // num SDLK_KP0..9 _Key += '0' - 256; else if( _Key==256 ) // non-num SDLK_KP01 _Key = TW_KEY_INSERT; else if( _Key==257 ) // non-num SDLK_KP1 _Key = TW_KEY_END; else if( _Key==258 ) // non-num SDLK_KP2 _Key = TW_KEY_DOWN; else if( _Key==259 ) // non-num SDLK_KP3 _Key = TW_KEY_PAGE_DOWN; else if( _Key==260 ) // non-num SDLK_KP4 _Key = TW_KEY_LEFT; else if( _Key==262 ) // non-num SDLK_KP6 _Key = TW_KEY_RIGHT; else if( _Key==263 ) // non-num SDLK_KP7 _Key = TW_KEY_HOME; else if( _Key==264 ) // non-num SDLK_KP8 _Key = TW_KEY_UP; else if( _Key==265 ) // non-num SDLK_KP9 _Key = TW_KEY_PAGE_UP; } */ /* string Str; TwGetKeyString(&Str, _Key, _Modifiers); printf("key: %d 0x%04xd %s\n", _Key, _Modifiers, Str.c_str()); */ if( m_EditInPlace.m_Active ) { Handled = EditInPlaceKeyPressed(_Key, _Modifiers); } else { bool BarActive = (m_DrawHandles || m_IsPopupList) && !m_IsMinimized; bool DoIncr = true; CTwVarAtom *Atom = m_VarRoot.FindShortcut(_Key, _Modifiers, &DoIncr); if( Atom!=NULL && Atom->m_Visible ) { if( !Atom->m_ReadOnly ) { Atom->Increment( DoIncr ? +1 : -1 ); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime(); } NotUpToDate(); Show(Atom); Handled = true; } else if( BarActive && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var ) { if( _Key==TW_KEY_RIGHT ) { if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { CTwVarAtom *Atom = static_cast(m_HierTags[m_HighlightedLine].m_Var); bool Accept = !Atom->m_NoSlider || Atom->m_Type==TW_TYPE_BUTTON || Atom->m_Type==TW_TYPE_BOOL8 || Atom->m_Type==TW_TYPE_BOOL16 || Atom->m_Type==TW_TYPE_BOOL32 || Atom->m_Type==TW_TYPE_BOOLCPP || IsEnumType(Atom->m_Type); if( !Atom->IsReadOnly() && !m_IsPopupList && Accept ) { Atom->Increment(+1); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime(); NotUpToDate(); } } else { CTwVarGroup *Grp = static_cast(m_HierTags[m_HighlightedLine].m_Var); if( !Grp->m_Open ) { Grp->m_Open = true; NotUpToDate(); } } Handled = true; } else if( _Key==TW_KEY_LEFT ) { if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { CTwVarAtom *Atom = static_cast(m_HierTags[m_HighlightedLine].m_Var); bool Accept = !Atom->m_NoSlider || Atom->m_Type==TW_TYPE_BUTTON || Atom->m_Type==TW_TYPE_BOOL8 || Atom->m_Type==TW_TYPE_BOOL16 || Atom->m_Type==TW_TYPE_BOOL32 || Atom->m_Type==TW_TYPE_BOOLCPP || IsEnumType(Atom->m_Type); if( !Atom->IsReadOnly() && Accept && !m_IsPopupList ) { Atom->Increment(-1); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime(); NotUpToDate(); } } else { CTwVarGroup *Grp = static_cast(m_HierTags[m_HighlightedLine].m_Var); if( Grp->m_Open ) { Grp->m_Open = false; NotUpToDate(); } } Handled = true; } else if( _Key==TW_KEY_RETURN ) { if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { CTwVarAtom *Atom = static_cast(m_HierTags[m_HighlightedLine].m_Var); if( !Atom->IsReadOnly() ) { if( Atom->m_Type==TW_TYPE_BUTTON || Atom->m_Type==TW_TYPE_BOOLCPP || Atom->m_Type==TW_TYPE_BOOL8 || Atom->m_Type==TW_TYPE_BOOL16 || Atom->m_Type==TW_TYPE_BOOL32 ) { bool isPopup = m_IsPopupList; Atom->Increment(+1); if( g_TwMgr==NULL // Mgr might have been destroyed by the client inside a callback call || isPopup ) // A popup destroys itself return 1; m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime(); NotUpToDate(); } else // if( IsEnumType(Atom->m_Type) ) { // simulate a mouse click int y = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_Sep) + m_Font->m_CharHeight/2; int x = m_PosX + m_VarX1 + 2; if( x>m_PosX+m_VarX2-2 ) x = m_PosX + m_VarX2 - 2; MouseMotion(x, y); MouseButton(TW_MOUSE_LEFT, true, x, y); } } } else { CTwVarGroup *Grp = static_cast(m_HierTags[m_HighlightedLine].m_Var); Grp->m_Open = !Grp->m_Open; NotUpToDate(); } Handled = true; } else if( _Key==TW_KEY_UP ) { --m_HighlightedLine; if( m_HighlightedLine<0 ) { m_HighlightedLine = 0; if( m_FirstLine>0 ) { --m_FirstLine; NotUpToDate(); } } m_HighlightedLineLastValid = m_HighlightedLine; Handled = true; } else if( _Key==TW_KEY_DOWN ) { ++m_HighlightedLine; if( m_HighlightedLine>=(int)m_HierTags.size() ) { m_HighlightedLine = (int)m_HierTags.size() - 1; if( m_FirstLinem_PopupBar = NULL; if( LinkedBar!=NULL ) LinkedBar->m_DrawHandles = true; return true; // this bar has been destroyed } } else if( BarActive ) { if( _Key==TW_KEY_UP || _Key==TW_KEY_DOWN || _Key==TW_KEY_LEFT || _Key==TW_KEY_RIGHT || _Key==TW_KEY_RETURN ) { if( m_HighlightedLineLastValid>=0 && m_HighlightedLineLastValid<(int)m_HierTags.size() ) m_HighlightedLine = m_HighlightedLineLastValid; else if( m_HierTags.size()>0 ) { if( _Key==TW_KEY_UP ) m_HighlightedLine = (int)m_HierTags.size()-1; else m_HighlightedLine = 0; } Handled = true; } else if( _Key==TW_KEY_ESCAPE && m_IsPopupList ) { Handled = true; CTwBar *LinkedBar = m_BarLinkedToPopupList; TwDeleteBar(this); g_TwMgr->m_PopupBar = NULL; if( LinkedBar!=NULL ) LinkedBar->m_DrawHandles = true; return true; // this bar has been destroyed } } } } return Handled; } // --------------------------------------------------------------------------- bool CTwBar::KeyTest(int _Key, int _Modifiers) { assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0); bool Handled = false; if( !m_UpToDate ) Update(); if( _Key>0 && _Keym_Visible ) Handled = true; else if( BarActive && ( _Key==TW_KEY_RIGHT || _Key==TW_KEY_LEFT || _Key==TW_KEY_UP || _Key==TW_KEY_DOWN || _Key==TW_KEY_RETURN || (_Key==TW_KEY_ESCAPE && m_IsPopupList) ) ) Handled = true; } } return Handled; } // --------------------------------------------------------------------------- bool CTwBar::Show(CTwVar *_Var) { if( _Var==NULL || !_Var->m_Visible ) return false; if( !m_UpToDate ) Update(); if( OpenHier(&m_VarRoot, _Var) ) { if( !m_UpToDate ) Update(); int l = LineInHier(&m_VarRoot, _Var); if( l>=0 ) { int NbLines = (m_VarY1-m_VarY0+1)/(m_Font->m_CharHeight+m_Sep); if( NbLines<= 0 ) NbLines = 1; if( l=m_FirstLine+NbLines ) { m_FirstLine = l-NbLines/2; if( m_FirstLine<0 ) m_FirstLine = 0; NotUpToDate(); Update(); if( m_NbDisplayedLinesm_Vars.size(); ++i) if( _Root->m_Vars[i]!=NULL ) { if( _Var==_Root->m_Vars[i] || (_Root->m_Vars[i]->IsGroup() && OpenHier(static_cast(_Root->m_Vars[i]), _Var)) ) { _Root->m_Open = true; NotUpToDate(); return true; } } return false; } // --------------------------------------------------------------------------- int CTwBar::LineInHier(CTwVarGroup *_Root, CTwVar *_Var) { assert( _Root!=NULL ); int l = 0; for(size_t i=0; i<_Root->m_Vars.size(); ++i) if( _Root->m_Vars[i]!=NULL && _Root->m_Vars[i]->m_Visible ) { if( _Var==_Root->m_Vars[i] ) return l; else if( _Root->m_Vars[i]->IsGroup() && static_cast(_Root->m_Vars[i])->m_Open ) { ++l; int ll = LineInHier(static_cast(_Root->m_Vars[i]), _Var); if( ll>=0 ) return l+ll; else l += -ll-2; } ++l; } return -l-1; } // --------------------------------------------------------------------------- void DrawArc(int _X, int _Y, int _Radius, float _StartAngleDeg, float _EndAngleDeg, color32 _Color) // angles in degree { ITwGraph *Gr = g_TwMgr->m_Graph; if( Gr==NULL || !Gr->IsDrawing() || _Radius==0 || _StartAngleDeg==_EndAngleDeg ) return; float startAngle = (float)M_PI*_StartAngleDeg/180; float endAngle = (float)M_PI*_EndAngleDeg/180; //float stepAngle = 8/(float)_Radius; // segment length = 8 pixels float stepAngle = 4/(float)_Radius; // segment length = 4 pixels if( stepAngle>(float)M_PI/4 ) stepAngle = (float)M_PI/4; bool fullCircle = fabsf(endAngle-startAngle)>=2.0f*(float)M_PI+fabsf(stepAngle); int numSteps; if( fullCircle ) { numSteps = int((2.0f*(float)M_PI)/stepAngle); startAngle = 0; endAngle = 2.0f*(float)M_PI; } else numSteps = int(fabsf(endAngle-startAngle)/stepAngle); if( startAngle>endAngle ) stepAngle = -stepAngle; int x0 = int(_X + _Radius * cosf(startAngle) + 0.5f); int y0 = int(_Y - _Radius * sinf(startAngle) + 0.5f); int x1, y1; float angle = startAngle+stepAngle; for( int i=0; iDrawLine(x0, y0, x1, y1, _Color, true); x0 = x1; y0 = y1; } if( fullCircle ) { x1 = int(_X + _Radius * cosf(startAngle) + 0.5f); y1 = int(_Y - _Radius * sinf(startAngle) + 0.5f); } else { x1 = int(_X + _Radius * cosf(endAngle) + 0.5f); y1 = int(_Y - _Radius * sinf(endAngle) + 0.5f); } Gr->DrawLine(x0, y0, x1, y1, _Color, true); } // --------------------------------------------------------------------------- CTwBar::CRotoSlider::CRotoSlider() { m_Var = NULL; m_Active = false; m_ActiveMiddle = false; m_Subdiv = 256; // will be recalculated in RotoOnLButtonDown } void CTwBar::RotoDraw() { ITwGraph *Gr = g_TwMgr->m_Graph; if( Gr==NULL || !Gr->IsDrawing() ) return; if( m_Roto.m_Active ) { DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y, 32, 0, 360, m_ColRoto); DrawArc(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, 32, 0, 360, m_ColRoto); DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, 32, 0, 360, m_ColRoto); if( m_Roto.m_HasPrevious ) { double varMax = RotoGetMax(); double varMin = RotoGetMin(); double varStep = RotoGetStep(); if( varMax-DOUBLE_MAX && fabs(varStep)>DOUBLE_EPS && m_Roto.m_Subdiv>0 ) { double dtMax = 360.0*(varMax-m_Roto.m_ValueAngle0)/((double)m_Roto.m_Subdiv*varStep);//+2; double dtMin = 360.0*(varMin-m_Roto.m_ValueAngle0)/((double)m_Roto.m_Subdiv*varStep);//-2; if( dtMax>=0 && dtMax<360 && dtMin<=0 && dtMin>-360 && fabs(dtMax-dtMin)<=360 ) { int x1, y1, x2, y2; double da = 2.0*M_PI/m_Roto.m_Subdiv; x1 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMax)/180-da)); y1 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMax)/180-da)+0.5); x2 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMax-10)/180-da)); y2 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMax-10)/180-da)+0.5); Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y, x1, y1, m_ColRotoBound, true); Gr->DrawLine(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, x1+1, y1, m_ColRotoBound, true); Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, x1, y1+1, m_ColRotoBound, true); Gr->DrawLine(x1, y1, x2, y2, m_ColRotoBound, true); Gr->DrawLine(x1+1, y1, x2+1, y2, m_ColRotoBound, true); Gr->DrawLine(x1, y1+1, x2, y2+1, m_ColRotoBound, true); x1 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMin)/180+da)); y1 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMin)/180+da)+0.5); x2 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMin+10)/180+da)); y2 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMin+10)/180+da)+0.5); Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y, x1, y1, m_ColRotoBound, true); Gr->DrawLine(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, x1+1, y1, m_ColRotoBound, true); Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, x1, y1+1, m_ColRotoBound, true); Gr->DrawLine(x1, y1, x2, y2, m_ColRotoBound, true); Gr->DrawLine(x1+1, y1, x2+1, y2, m_ColRotoBound, true); Gr->DrawLine(x1, y1+1, x2, y2+1, m_ColRotoBound, true); } } } Gr->DrawLine(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, m_Roto.m_Current.x+1, m_Roto.m_Current.y, m_ColRotoVal, true); Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, m_Roto.m_Current.x, m_Roto.m_Current.y+1, m_ColRotoVal, true); Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y, m_Roto.m_Current.x, m_Roto.m_Current.y, m_ColRotoVal, true); if( fabs(m_Roto.m_AngleDT)>=1 ) { DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y, 32, float(m_Roto.m_Angle0), float(m_Roto.m_Angle0+m_Roto.m_AngleDT-1), m_ColRotoVal); DrawArc(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, 32, float(m_Roto.m_Angle0), float(m_Roto.m_Angle0+m_Roto.m_AngleDT-1), m_ColRotoVal); DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, 32, float(m_Roto.m_Angle0), float(m_Roto.m_Angle0+m_Roto.m_AngleDT-1), m_ColRotoVal); } } } double CTwBar::RotoGetValue() const { assert(m_Roto.m_Var!=NULL); return m_Roto.m_Var->ValueToDouble(); } void CTwBar::RotoSetValue(double _Val) { assert(m_Roto.m_Var!=NULL); if( _Val!=m_Roto.m_CurrentValue ) { m_Roto.m_CurrentValue = _Val; m_Roto.m_Var->ValueFromDouble(_Val); NotUpToDate(); } } double CTwBar::RotoGetMin() const { assert(m_Roto.m_Var!=NULL); double min = -DOUBLE_MAX; m_Roto.m_Var->MinMaxStepToDouble(&min, NULL, NULL); return min; } double CTwBar::RotoGetMax() const { assert(m_Roto.m_Var!=NULL); double max = DOUBLE_MAX; m_Roto.m_Var->MinMaxStepToDouble(NULL, &max, NULL); return max; } double CTwBar::RotoGetStep() const { assert(m_Roto.m_Var!=NULL); double step = 1; m_Roto.m_Var->MinMaxStepToDouble(NULL, NULL, &step); return step; } double CTwBar::RotoGetSteppedValue() const { double d = m_Roto.m_PreciseValue-m_Roto.m_Value0; double n = int(d/RotoGetStep()); return m_Roto.m_Value0 + RotoGetStep()*n; } void CTwBar::RotoOnMouseMove(int _X, int _Y) { CPoint p(_X, _Y); if( m_Roto.m_Active ) { m_Roto.m_Current = p; RotoSetValue(RotoGetSteppedValue()); //DrawManip(); int ti = -1; double t = 0; float r = sqrtf(float( (m_Roto.m_Current.x-m_Roto.m_Origin.x)*(m_Roto.m_Current.x-m_Roto.m_Origin.x) + (m_Roto.m_Current.y-m_Roto.m_Origin.y)*(m_Roto.m_Current.y-m_Roto.m_Origin.y))); if( r>m_RotoMinRadius ) { t = - atan2(double(m_Roto.m_Current.y-m_Roto.m_Origin.y), double(m_Roto.m_Current.x-m_Roto.m_Origin.x)); ti = (int((t/(2.0*M_PI)+1.0)*NB_ROTO_CURSORS+0.5)) % NB_ROTO_CURSORS; if( m_Roto.m_HasPrevious ) { CPoint v0 = m_Roto.m_Previous-m_Roto.m_Origin; CPoint v1 = m_Roto.m_Current-m_Roto.m_Origin; double l0 = sqrt(double(v0.x*v0.x+v0.y*v0.y)); double l1 = sqrt(double(v1.x*v1.x+v1.y*v1.y)); double dt = acos(max(-1+1.0e-30,min(1-1.0e-30,double(v0.x*v1.x+v0.y*v1.y)/(l0*l1)))); if( v0.x*v1.y-v0.y*v1.x>0 ) dt = - dt; double preciseInc = double(m_Roto.m_Subdiv) * dt/(2.0*M_PI) * RotoGetStep(); if( preciseInc>RotoGetStep() || preciseInc<-RotoGetStep() ) { m_Roto.m_PreciseValue += preciseInc; if( m_Roto.m_PreciseValue>RotoGetMax() ) { m_Roto.m_PreciseValue = RotoGetMax(); m_Roto.m_Value0 = RotoGetMax(); double da = 360*(RotoGetMax()-m_Roto.m_ValueAngle0)/(double(m_Roto.m_Subdiv)*RotoGetStep()); m_Roto.m_Angle0 = ((int((t/(2.0*M_PI)+1.0)*360.0+0.5)) % 360) - da; m_Roto.m_AngleDT = da; } else if( m_Roto.m_PreciseValue=0 && ti=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) { m_Roto.m_Var = static_cast(m_HierTags[m_HighlightedLine].m_Var); int y = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_Sep) + m_Font->m_CharHeight/2; m_Roto.m_Origin = CPoint(p.x, y); //r.CenterPoint().y); m_Roto.m_Current = p; m_Roto.m_Active = true; m_Roto.m_HasPrevious = false; m_Roto.m_Angle0 = 0; m_Roto.m_AngleDT = 0; //SetCapture(); m_Roto.m_Value0 = RotoGetValue(); m_Roto.m_CurrentValue = m_Roto.m_Value0; m_Roto.m_ValueAngle0 = m_Roto.m_Value0; m_Roto.m_PreciseValue = m_Roto.m_Value0; //RotoSetValue(RotoGetSteppedValue()); Not here //DrawManip(); m_Roto.m_Subdiv = m_RotoNbSubdiv; // re-adjust m_Subdiv if needed: double min=-DOUBLE_MAX, max=DOUBLE_MAX, step=1; m_Roto.m_Var->MinMaxStepToDouble(&min, &max, &step); if( fabs(step)>0 && min>-DOUBLE_MAX && maxm_Graph!=NULL ); m_Var = NULL; m_Active = false; m_EditTextObj = g_TwMgr->m_Graph->NewTextObj(); m_EditSelTextObj = g_TwMgr->m_Graph->NewTextObj(); m_X = m_Y = m_Width = 0; } CTwBar::CEditInPlace::~CEditInPlace() { assert( g_TwMgr!=NULL && g_TwMgr->m_Graph!=NULL ); if( m_EditTextObj ) g_TwMgr->m_Graph->DeleteTextObj(m_EditTextObj); if( m_EditSelTextObj ) g_TwMgr->m_Graph->DeleteTextObj(m_EditSelTextObj); } bool CTwBar::EditInPlaceIsReadOnly() { if( m_EditInPlace.m_Var==NULL ) return true; else if( m_EditInPlace.m_Var->m_ReadOnly ) return true; else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTRING && ((m_EditInPlace.m_Var->m_Ptr==NULL && m_EditInPlace.m_Var->m_SetCallback==NULL) || (m_EditInPlace.m_Var->m_Ptr!=NULL && g_TwMgr->m_CopyCDStringToClient==NULL)) ) return true; else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTDSTRING && m_EditInPlace.m_Var->m_SetCallback==NULL ) return true; else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_STDSTRING && ((m_EditInPlace.m_Var->m_Ptr==NULL && m_EditInPlace.m_Var->m_SetCallback==NULL) || (m_EditInPlace.m_Var->m_Ptr!=NULL && g_TwMgr->m_CopyStdStringToClient==NULL)) ) return true; else return false; } void CTwBar::EditInPlaceDraw() { if( !m_EditInPlace.m_Active || m_EditInPlace.m_Var==NULL || m_EditInPlace.m_Width<=0 ) return; // adjust m_FirstChar to see the caret, and extract the visible sub-string int i, StringLen = (int)m_EditInPlace.m_String.length(); if( m_EditInPlace.m_FirstChar>m_EditInPlace.m_CaretPos ) m_EditInPlace.m_FirstChar = m_EditInPlace.m_CaretPos; int SubstrWidth = 0; for( i=min(m_EditInPlace.m_CaretPos, StringLen-1); i>=0 && SubstrWidthm_CharWidth[u]; } int FirstChar = max(0, i); if( SubstrWidth>=m_EditInPlace.m_Width ) FirstChar += 2; if( m_EditInPlace.m_FirstChar0 ) --m_EditInPlace.m_FirstChar; SubstrWidth = 0; for( i=m_EditInPlace.m_FirstChar; im_CharWidth[u]; } int LastChar = i; if( SubstrWidth>=m_EditInPlace.m_Width ) --LastChar; string Substr = m_EditInPlace.m_String.substr( m_EditInPlace.m_FirstChar, LastChar-m_EditInPlace.m_FirstChar ); // compute caret x pos int CaretX = m_PosX + m_EditInPlace.m_X; for( i=m_EditInPlace.m_FirstChar; im_CharWidth[u]; } // draw edit text color32 ColText = EditInPlaceIsReadOnly() ? m_ColValTextRO : m_ColEditText; color32 ColBg = EditInPlaceIsReadOnly() ? m_ColValBg : m_ColEditBg; g_TwMgr->m_Graph->BuildText(m_EditInPlace.m_EditTextObj, &Substr, NULL, NULL, 1, m_Font, 0, m_EditInPlace.m_Width); g_TwMgr->m_Graph->DrawText(m_EditInPlace.m_EditTextObj, m_PosX+m_EditInPlace.m_X, m_PosY+m_EditInPlace.m_Y, ColText, ColBg); // draw selected text string StrSelected = ""; if( m_EditInPlace.m_CaretPos>m_EditInPlace.m_SelectionStart ) { int FirstSel = max(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_FirstChar); int LastSel = min(m_EditInPlace.m_CaretPos, LastChar); StrSelected = m_EditInPlace.m_String.substr( FirstSel, LastSel-FirstSel ); } else { int FirstSel = max(m_EditInPlace.m_CaretPos, m_EditInPlace.m_FirstChar); int LastSel = min(m_EditInPlace.m_SelectionStart, LastChar); StrSelected = m_EditInPlace.m_String.substr( FirstSel, LastSel-FirstSel ); } int SelWidth = 0; for( i=0; i<(int)StrSelected.length(); ++i ) { unsigned char u = StrSelected.c_str()[i]; SelWidth += m_Font->m_CharWidth[u]; } if( SelWidth>0 && StrSelected.length()>0 ) { color32 ColSelBg = EditInPlaceIsReadOnly() ? m_ColValTextRO : m_ColEditSelBg; g_TwMgr->m_Graph->BuildText(m_EditInPlace.m_EditSelTextObj, &StrSelected, NULL, NULL, 1, m_Font, 0, SelWidth); if ( m_EditInPlace.m_CaretPos>m_EditInPlace.m_SelectionStart ) g_TwMgr->m_Graph->DrawText(m_EditInPlace.m_EditSelTextObj, CaretX-SelWidth, m_PosY+m_EditInPlace.m_Y, m_ColEditSelText, ColSelBg); else g_TwMgr->m_Graph->DrawText(m_EditInPlace.m_EditSelTextObj, CaretX, m_PosY+m_EditInPlace.m_Y, m_ColEditSelText, ColSelBg); } // draw caret if( CaretX<=m_PosX+m_EditInPlace.m_X+m_EditInPlace.m_Width ) g_TwMgr->m_Graph->DrawLine( CaretX, m_PosY+m_EditInPlace.m_Y+1, CaretX, m_PosY+m_EditInPlace.m_Y+m_Font->m_CharHeight, m_ColEditText ); } bool CTwBar::EditInPlaceAcceptVar(const CTwVarAtom* _Var) { if( _Var==NULL ) return false; if( _Var->m_Type>=TW_TYPE_CHAR && _Var->m_Type<=TW_TYPE_DOUBLE ) return true; if( _Var->m_Type==TW_TYPE_CDSTRING || _Var->m_Type==TW_TYPE_CDSTDSTRING || _Var->m_Type==TW_TYPE_STDSTRING ) return true; if( IsCSStringType(_Var->m_Type) ) return true; return false; } void CTwBar::EditInPlaceStart(CTwVarAtom* _Var, int _X, int _Y, int _Width) { if( m_EditInPlace.m_Active ) EditInPlaceEnd(true); m_EditInPlace.m_Active = true; m_EditInPlace.m_Var = _Var; m_EditInPlace.m_X = _X; m_EditInPlace.m_Y = _Y; m_EditInPlace.m_Width = _Width; m_EditInPlace.m_Var->ValueToString(&m_EditInPlace.m_String); if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CHAR ) m_EditInPlace.m_String = m_EditInPlace.m_String.substr(0, 1); m_EditInPlace.m_CaretPos = (int)m_EditInPlace.m_String.length(); if( EditInPlaceIsReadOnly() ) m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; else m_EditInPlace.m_SelectionStart = 0; m_EditInPlace.m_FirstChar = 0; } void CTwBar::EditInPlaceEnd(bool _Commit) { if( _Commit && m_EditInPlace.m_Active && m_EditInPlace.m_Var!=NULL ) { if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTRING || m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTDSTRING ) { if( m_EditInPlace.m_Var->m_SetCallback!=NULL ) { const char *String = m_EditInPlace.m_String.c_str(); m_EditInPlace.m_Var->m_SetCallback(&String, m_EditInPlace.m_Var->m_ClientData); } else if( m_EditInPlace.m_Var->m_Type!=TW_TYPE_CDSTDSTRING ) { char **StringPtr = (char **)m_EditInPlace.m_Var->m_Ptr; if( StringPtr!=NULL && g_TwMgr->m_CopyCDStringToClient!=NULL ) g_TwMgr->m_CopyCDStringToClient(StringPtr, m_EditInPlace.m_String.c_str()); } } else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_STDSTRING ) { // this case should never happened: TW_TYPE_STDSTRING are converted to TW_TYPE_CDSTDSTRING by TwAddVar if( m_EditInPlace.m_Var->m_SetCallback!=NULL ) m_EditInPlace.m_Var->m_SetCallback(&(m_EditInPlace.m_String), m_EditInPlace.m_Var->m_ClientData); else { string *StringPtr = (string *)m_EditInPlace.m_Var->m_Ptr; if( StringPtr!=NULL && g_TwMgr->m_CopyStdStringToClient!=NULL ) g_TwMgr->m_CopyStdStringToClient(*StringPtr, m_EditInPlace.m_String); } } else if( IsCSStringType(m_EditInPlace.m_Var->m_Type) ) { int n = TW_CSSTRING_SIZE(m_EditInPlace.m_Var->m_Type); if( n>0 ) { if( (int)m_EditInPlace.m_String.length()>n-1 ) m_EditInPlace.m_String.resize(n-1); if( m_EditInPlace.m_Var->m_SetCallback!=NULL ) m_EditInPlace.m_Var->m_SetCallback(m_EditInPlace.m_String.c_str(), m_EditInPlace.m_Var->m_ClientData); else if( m_EditInPlace.m_Var->m_Ptr!=NULL ) { if( n>1 ) strncpy((char *)m_EditInPlace.m_Var->m_Ptr, m_EditInPlace.m_String.c_str(), n-1); ((char *)m_EditInPlace.m_Var->m_Ptr)[n-1] = '\0'; } } } else { double Val = 0, Min = 0, Max = 0, Step = 0; int n = 0; if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CHAR ) { unsigned char Char = 0; n = sscanf(m_EditInPlace.m_String.c_str(), "%c", &Char); Val = Char; } else n = sscanf(m_EditInPlace.m_String.c_str(), "%lf", &Val); if( n==1 ) { m_EditInPlace.m_Var->MinMaxStepToDouble(&Min, &Max, &Step); if( ValMax ) Val = Max; m_EditInPlace.m_Var->ValueFromDouble(Val); } } if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call NotUpToDate(); } m_EditInPlace.m_Active = false; m_EditInPlace.m_Var = NULL; } bool CTwBar::EditInPlaceKeyPressed(int _Key, int _Modifiers) { if( !m_EditInPlace.m_Active ) return false; bool Handled = true; // if EditInPlace is active, it catches all key events bool DoCopy = false, DoPaste = false; switch( _Key ) { case TW_KEY_ESCAPE: EditInPlaceEnd(false); break; case TW_KEY_RETURN: EditInPlaceEnd(true); break; case TW_KEY_LEFT: if( _Modifiers==TW_KMOD_SHIFT ) m_EditInPlace.m_CaretPos = max(0, m_EditInPlace.m_CaretPos-1); else { if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos ) m_EditInPlace.m_CaretPos = min(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_CaretPos); else m_EditInPlace.m_CaretPos = max(0, m_EditInPlace.m_CaretPos-1); m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; } break; case TW_KEY_RIGHT: if( _Modifiers==TW_KMOD_SHIFT ) m_EditInPlace.m_CaretPos = min((int)m_EditInPlace.m_String.length(), m_EditInPlace.m_CaretPos+1); else { if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos ) m_EditInPlace.m_CaretPos = max(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_CaretPos); else m_EditInPlace.m_CaretPos = min((int)m_EditInPlace.m_String.length(), m_EditInPlace.m_CaretPos+1); m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; } break; case TW_KEY_BACKSPACE: if( !EditInPlaceIsReadOnly() ) { if( m_EditInPlace.m_SelectionStart==m_EditInPlace.m_CaretPos ) m_EditInPlace.m_SelectionStart = max(0, m_EditInPlace.m_CaretPos-1); EditInPlaceEraseSelect(); } break; case TW_KEY_DELETE: if( !EditInPlaceIsReadOnly() ) { if( m_EditInPlace.m_SelectionStart==m_EditInPlace.m_CaretPos ) m_EditInPlace.m_SelectionStart = min(m_EditInPlace.m_CaretPos+1, (int)m_EditInPlace.m_String.length()); EditInPlaceEraseSelect(); } break; case TW_KEY_HOME: m_EditInPlace.m_CaretPos = 0; if( _Modifiers!=TW_KMOD_SHIFT ) m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; break; case TW_KEY_END: m_EditInPlace.m_CaretPos = (int)m_EditInPlace.m_String.length(); if( _Modifiers!=TW_KMOD_SHIFT ) m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; break; case TW_KEY_INSERT: if( _Modifiers==TW_KMOD_CTRL ) DoCopy = true; else if( _Modifiers==TW_KMOD_SHIFT ) DoPaste = true; break; default: if( _Modifiers==TW_KMOD_CTRL ) { if( _Key=='c' || _Key=='C' ) DoCopy = true; else if( _Key=='v' || _Key=='V' ) DoPaste = true; } else if( _Key>=32 && _Key<=255 ) { if( !EditInPlaceIsReadOnly() && m_EditInPlace.m_CaretPos>=0 && m_EditInPlace.m_CaretPos<=(int)m_EditInPlace.m_String.length() ) { if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos ) EditInPlaceEraseSelect(); string Str(1, (char)_Key); m_EditInPlace.m_String.insert(m_EditInPlace.m_CaretPos, Str); ++m_EditInPlace.m_CaretPos; m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; } } } if( DoPaste && !EditInPlaceIsReadOnly() ) { if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos ) EditInPlaceEraseSelect(); string Str = ""; if( EditInPlaceGetClipboard(&Str) && Str.length()>0 ) { m_EditInPlace.m_String.insert(m_EditInPlace.m_CaretPos, Str); m_EditInPlace.m_CaretPos += (int)Str.length(); m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; } } if( DoCopy ) { string Str = ""; if( m_EditInPlace.m_CaretPos>m_EditInPlace.m_SelectionStart ) Str = m_EditInPlace.m_String.substr(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_CaretPos-m_EditInPlace.m_SelectionStart); else if( m_EditInPlace.m_CaretPosPosMin ) m_EditInPlace.m_FirstChar = PosMin; return true; } else return false; } bool CTwBar::EditInPlaceMouseMove(int _X, int _Y, bool _Select) { if ( !m_EditInPlace.m_Active || _Ym_PosY+m_EditInPlace.m_Y+m_Font->m_CharHeight ) return false; int i, CaretX = m_PosX+m_EditInPlace.m_X; for( i=m_EditInPlace.m_FirstChar; i<(int)m_EditInPlace.m_String.length() && CaretXm_CharWidth[u]; if( _X < CaretX + CharWidth / 2 ) break; CaretX += CharWidth; } if( CaretX>=m_PosX+m_EditInPlace.m_X+m_EditInPlace.m_Width ) i = max(0, i-1); m_EditInPlace.m_CaretPos = i; if( !_Select ) m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos; return true; } bool CTwBar::EditInPlaceGetClipboard(std::string *_OutString) { assert( _OutString!=NULL ); *_OutString = m_EditInPlace.m_Clipboard; // default implementation #if defined ANT_WINDOWS if( !IsClipboardFormatAvailable(CF_TEXT) ) return false; if( !OpenClipboard(NULL) ) return false; HGLOBAL TextHandle = GetClipboardData(CF_TEXT); if( TextHandle!=NULL ) { const char *TextString = static_cast(GlobalLock(TextHandle)); if( TextHandle!=NULL ) { *_OutString = TextString; GlobalUnlock(TextHandle); } } CloseClipboard(); #elif defined ANT_UNIX if( g_TwMgr->m_CurrentXDisplay!=NULL ) { int NbBytes = 0; char *Buffer = XFetchBytes(g_TwMgr->m_CurrentXDisplay, &NbBytes); if( Buffer!=NULL ) { if( NbBytes>0 ) { char *Text = new char[NbBytes+1]; memcpy(Text, Buffer, NbBytes); Text[NbBytes] = '\0'; *_OutString = Text; delete[] Text; } XFree(Buffer); } } #endif return true; } bool CTwBar::EditInPlaceSetClipboard(const std::string& _String) { if( _String.length()<=0 ) return false; // keep last clipboard m_EditInPlace.m_Clipboard = _String; // default implementation #if defined ANT_WINDOWS if( !OpenClipboard(NULL) ) return false; EmptyClipboard(); HGLOBAL TextHandle = GlobalAlloc(GMEM_MOVEABLE, _String.length()+1); if( TextHandle==NULL ) { CloseClipboard(); return false; } char *TextString = static_cast(GlobalLock(TextHandle)); memcpy(TextString, _String.c_str(), _String.length()); TextString[_String.length()] = '\0'; GlobalUnlock(TextHandle); SetClipboardData(CF_TEXT, TextHandle); CloseClipboard(); #elif defined ANT_UNIX if( g_TwMgr->m_CurrentXDisplay!=NULL ) { XSetSelectionOwner(g_TwMgr->m_CurrentXDisplay, XA_PRIMARY, None, CurrentTime); char *Text = new char[_String.length()+1]; memcpy(Text, _String.c_str(), _String.length()); Text[_String.length()] = '\0'; XStoreBytes(g_TwMgr->m_CurrentXDisplay, Text, _String.length()); delete[] Text; } #endif return true; } // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwBar.h0000644000000000000000000004661012635011627023746 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwBar.h // @brief Tweak bar and var classes. // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_BAR_INCLUDED #define ANT_TW_BAR_INCLUDED #include #include "TwColors.h" #define ANT_TWEAK_BAR_DLL "AntTweakBar" // --------------------------------------------------------------------------- bool IsCustomType(int _Type); struct CTwVar { std::string m_Name; std::string m_Label; std::string m_Help; bool m_IsRoot; bool m_DontClip; bool m_Visible; signed short m_LeftMargin; signed short m_TopMargin; const color32 * m_ColorPtr; const color32 * m_BgColorPtr; virtual bool IsGroup() const = 0; virtual bool IsCustom() const { return false; } virtual const CTwVar * Find(const char *_Name, struct CTwVarGroup **_Parent, int *_Index) const = 0; virtual int HasAttrib(const char *_Attrib, bool *_HasValue) const; virtual int SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex); virtual ERetType GetAttrib(int _AttribID, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex, std::vector& outDouble, std::ostringstream& outString) const; virtual void SetReadOnly(bool _ReadOnly) = 0; virtual bool IsReadOnly() const = 0; CTwVar(); virtual ~CTwVar() {} static size_t GetDataSize(TwType _Type); }; struct CTwVarAtom : CTwVar { ETwType m_Type; void * m_Ptr; TwSetVarCallback m_SetCallback; TwGetVarCallback m_GetCallback; void * m_ClientData; bool m_ReadOnly; bool m_NoSlider; int m_KeyIncr[2]; // [0]=key_code [1]=modifiers int m_KeyDecr[2]; // [0]=key_code [1]=modifiers template struct TVal { _T m_Min; _T m_Max; _T m_Step; signed char m_Precision; bool m_Hexa; }; union UVal { TVal m_Char; TVal m_Int8; TVal m_UInt8; TVal m_Int16; TValm_UInt16; TVal m_Int32; TVal m_UInt32; TVal m_Float32; TVal m_Float64; struct CBoolVal { char * m_TrueString; char * m_FalseString; bool m_FreeTrueString; bool m_FreeFalseString; } m_Bool; struct CEnumVal // empty -> enum entries are deduced from m_Type { //typedef std::map CEntries; //CEntries * m_Entries; } m_Enum; struct CShortcutVal { int m_Incr[2]; int m_Decr[2]; } m_Shortcut; struct CHelpStruct { int m_StructType; } m_HelpStruct; struct CButtonVal { TwButtonCallback m_Callback; int m_Separator; } m_Button; struct CCustomVal { CTwMgr::CMemberProxy *m_MemberProxy; } m_Custom; }; UVal m_Val; virtual bool IsGroup() const { return false; } virtual bool IsCustom() const { return IsCustomType(m_Type); } virtual void ValueToString(std::string *_Str) const; virtual double ValueToDouble() const; virtual void ValueFromDouble(double _Val); virtual void MinMaxStepToDouble(double *_Min, double *_Max, double *_Step) const; virtual const CTwVar * Find(const char *_Name, struct CTwVarGroup **_Parent, int *_Index) const; virtual int HasAttrib(const char *_Attrib, bool *_HasValue) const; virtual int SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex); virtual ERetType GetAttrib(int _AttribID, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex, std::vector& outDouble, std::ostringstream& outString) const; virtual void Increment(int _Step); virtual void SetDefaults(); virtual void SetReadOnly(bool _ReadOnly) { m_ReadOnly=_ReadOnly; if( m_Type!=TW_TYPE_BUTTON && m_SetCallback==NULL && m_Ptr==NULL ) m_ReadOnly=true; } virtual bool IsReadOnly() const { if( m_Type!=TW_TYPE_BUTTON && m_SetCallback==NULL && m_Ptr==NULL ) return true; else return m_ReadOnly; } //virtual int DefineEnum(const TwEnumVal *_EnumValues, unsigned int _NbValues); CTwVarAtom(); virtual ~CTwVarAtom(); }; struct CTwVarGroup : CTwVar { std::vector m_Vars; bool m_Open; TwSummaryCallback m_SummaryCallback; void * m_SummaryClientData; void * m_StructValuePtr; TwType m_StructType; virtual bool IsGroup() const { return true; } virtual const CTwVar * Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) const; virtual int HasAttrib(const char *_Attrib, bool *_HasValue) const; virtual int SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex); virtual ERetType GetAttrib(int _AttribID, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex, std::vector& outDouble, std::ostringstream& outString) const; virtual CTwVarAtom * FindShortcut(int _Key, int _Modifiers, bool *_DoIncr); virtual void SetReadOnly(bool _ReadOnly) { for(size_t i=0; iSetReadOnly(_ReadOnly); } virtual bool IsReadOnly() const { for(size_t i=0; iIsReadOnly()) return false; return true; } CTwVarGroup() { m_Open=false; m_StructType=TW_TYPE_UNDEF; m_SummaryCallback=NULL; m_SummaryClientData=NULL; m_StructValuePtr=NULL; } virtual ~CTwVarGroup(); }; // --------------------------------------------------------------------------- struct CTwBar { std::string m_Name; std::string m_Label; std::string m_Help; bool m_Visible; int m_PosX; int m_PosY; int m_Width; int m_Height; color32 m_Color; bool m_DarkText; const CTexFont * m_Font; int m_ValuesWidth; int m_Sep; int m_FirstLine; float m_UpdatePeriod; bool m_IsHelpBar; int m_MinNumber; // accessed by TwDeleteBar bool m_IsPopupList; CTwVarAtom * m_VarEnumLinkedToPopupList; CTwBar * m_BarLinkedToPopupList; bool m_Resizable; bool m_Movable; bool m_Iconifiable; bool m_Contained; CTwVarGroup m_VarRoot; enum EDrawPart { DRAW_BG=(1<<0), DRAW_CONTENT=(1<<1), DRAW_ALL=DRAW_BG|DRAW_CONTENT }; void Draw(int _DrawPart=DRAW_ALL); void NotUpToDate(); const CTwVar * Find(const char *_Name, CTwVarGroup **_Parent=NULL, int *_Index=NULL) const; CTwVar * Find(const char *_Name, CTwVarGroup **_Parent=NULL, int *_Index=NULL); int HasAttrib(const char *_Attrib, bool *_HasValue) const; int SetAttrib(int _AttribID, const char *_Value); ERetType GetAttrib(int _AttribID, std::vector& outDouble, std::ostringstream& outString) const; bool MouseMotion(int _X, int _Y); bool MouseButton(ETwMouseButtonID _Button, bool _Pressed, int _X, int _Y); bool MouseWheel(int _Pos, int _PrevPos, int _MouseX, int _MouseY); bool KeyPressed(int _Key, int _Modifiers); bool KeyTest(int _Key, int _Modifiers); bool IsMinimized() const { return m_IsMinimized; } bool IsDragging() const { return m_MouseDrag; } bool Show(CTwVar *_Var); // display the line associated to _Var bool OpenHier(CTwVarGroup *_Root, CTwVar *_Var); // open a hierarchy if it contains _Var int LineInHier(CTwVarGroup *_Root, CTwVar *_Var); // returns the number of the line associated to _Var void UnHighlightLine() { m_HighlightedLine = -1; NotUpToDate(); } // used by PopupCallback void HaveFocus(bool _Focus) { m_DrawHandles = _Focus; } // used by PopupCallback void StopEditInPlace() { if( m_EditInPlace.m_Active ) EditInPlaceEnd(false); } CTwBar(const char *_Name); ~CTwBar(); color32 m_ColBg, m_ColBg1, m_ColBg2; color32 m_ColHighBg0; color32 m_ColHighBg1; color32 m_ColLabelText; color32 m_ColStructText; color32 m_ColValBg; color32 m_ColValText; color32 m_ColValTextRO; color32 m_ColValTextNE; color32 m_ColValMin; color32 m_ColValMax; color32 m_ColStructBg; color32 m_ColTitleBg; color32 m_ColTitleHighBg; color32 m_ColTitleUnactiveBg; color32 m_ColTitleText; color32 m_ColTitleShadow; color32 m_ColLine; color32 m_ColLineShadow; color32 m_ColUnderline; color32 m_ColBtn; color32 m_ColHighBtn; color32 m_ColFold; color32 m_ColHighFold; color32 m_ColGrpBg; color32 m_ColGrpText; color32 m_ColHierBg; color32 m_ColShortcutText; color32 m_ColShortcutBg; color32 m_ColInfoText; color32 m_ColHelpBg; color32 m_ColHelpText; color32 m_ColRoto; color32 m_ColRotoVal; color32 m_ColRotoBound; color32 m_ColEditBg; color32 m_ColEditText; color32 m_ColEditSelBg; color32 m_ColEditSelText; color32 m_ColSeparator; color32 m_ColStaticText; void UpdateColors(); protected: int m_TitleWidth; int m_VarX0; int m_VarX1; int m_VarX2; int m_VarY0; int m_VarY1; int m_VarY2; int m_ScrollYW; int m_ScrollYH; int m_ScrollY0; int m_ScrollY1; int m_NbHierLines; int m_NbDisplayedLines; bool m_UpToDate; float m_LastUpdateTime; void Update(); bool m_MouseDrag; bool m_MouseDragVar; bool m_MouseDragTitle; bool m_MouseDragScroll; bool m_MouseDragResizeUR; bool m_MouseDragResizeUL; bool m_MouseDragResizeLR; bool m_MouseDragResizeLL; bool m_MouseDragValWidth; int m_MouseOriginX; int m_MouseOriginY; double m_ValuesWidthRatio; bool m_VarHasBeenIncr; int m_FirstLine0; int m_HighlightedLine; int m_HighlightedLinePrev; int m_HighlightedLineLastValid; bool m_HighlightIncrBtn; bool m_HighlightDecrBtn; bool m_HighlightRotoBtn; bool m_HighlightListBtn; bool m_HighlightBoolBtn; bool m_HighlightClickBtn; double m_HighlightClickBtnAuto; bool m_HighlightTitle; bool m_HighlightScroll; bool m_HighlightUpScroll; bool m_HighlightDnScroll; bool m_HighlightMinimize; bool m_HighlightFont; bool m_HighlightValWidth; bool m_HighlightLabelsHeader; bool m_HighlightValuesHeader; bool m_DrawHandles; bool m_IsMinimized; int m_MinPosX; int m_MinPosY; bool m_HighlightMaximize; bool m_DrawIncrDecrBtn; bool m_DrawRotoBtn; bool m_DrawClickBtn; bool m_DrawListBtn; bool m_DrawBoolBtn; EButtonAlign m_ButtonAlign; struct CHierTag { CTwVar * m_Var; int m_Level; bool m_Closing; }; std::vector m_HierTags; void BrowseHierarchy(int *_LineNum, int _CurrLevel, const CTwVar *_Var, int _First, int _Last); void * m_TitleTextObj; void * m_LabelsTextObj; void * m_ValuesTextObj; void * m_ShortcutTextObj; int m_ShortcutLine; void * m_HeadersTextObj; void ListLabels(std::vector& _Labels, std::vector& _Colors, std::vector& _BgColors, bool *_HasBgColors, const CTexFont *_Font, int _AtomWidthMax, int _GroupWidthMax); void ListValues(std::vector& _Values, std::vector& _Colors, std::vector& _BgColors, const CTexFont *_Font, int _WidthMax); int ComputeLabelsWidth(const CTexFont *_Font); int ComputeValuesWidth(const CTexFont *_Font); void DrawHierHandle(); enum EValuesWidthFit { VALUES_WIDTH_FIT = -5555 }; // RotoSlider struct CPoint { int x, y; CPoint() {} CPoint(int _X, int _Y):x(_X), y(_Y) {} const CPoint operator+ (const CPoint& p) const { return CPoint(x+p.x, y+p.y); } const CPoint operator- (const CPoint& p) const { return CPoint(x-p.x, y-p.y); } }; struct CRotoSlider { CRotoSlider(); CTwVarAtom * m_Var; double m_PreciseValue; double m_CurrentValue; double m_Value0; double m_ValueAngle0; bool m_Active; bool m_ActiveMiddle; CPoint m_Origin; CPoint m_Current; bool m_HasPrevious; CPoint m_Previous; double m_Angle0; double m_AngleDT; int m_Subdiv; }; CRotoSlider m_Roto; int m_RotoMinRadius; int m_RotoNbSubdiv; // number of steps for one turn void RotoDraw(); void RotoOnMouseMove(int _X, int _Y); void RotoOnLButtonDown(int _X, int _Y); void RotoOnLButtonUp(int _X, int _Y); void RotoOnMButtonDown(int _X, int _Y); void RotoOnMButtonUp(int _X, int _Y); double RotoGetValue() const; void RotoSetValue(double _Val); double RotoGetMin() const; double RotoGetMax() const; double RotoGetStep() const; double RotoGetSteppedValue() const; // Edit-in-place struct CEditInPlace { CEditInPlace(); ~CEditInPlace(); CTwVarAtom * m_Var; bool m_Active; std::string m_String; void * m_EditTextObj; void * m_EditSelTextObj; int m_CaretPos; int m_SelectionStart; int m_X, m_Y; int m_Width; int m_FirstChar; std::string m_Clipboard; }; CEditInPlace m_EditInPlace; void EditInPlaceDraw(); bool EditInPlaceAcceptVar(const CTwVarAtom* _Var); bool EditInPlaceIsReadOnly(); void EditInPlaceStart(CTwVarAtom* _Var, int _X, int _Y, int _Width); void EditInPlaceEnd(bool _Commit); bool EditInPlaceKeyPressed(int _Key, int _Modifiers); bool EditInPlaceEraseSelect(); bool EditInPlaceMouseMove(int _X, int _Y, bool _Select); bool EditInPlaceSetClipboard(const std::string& _String); bool EditInPlaceGetClipboard(std::string *_OutString); struct CCustomRecord { int m_IndexMin; int m_IndexMax; int m_XMin, m_XMax; int m_YMin, m_YMax; // Y visible range int m_Y0, m_Y1; // Y widget range CTwVarGroup * m_Var; }; typedef std::map CustomMap; CustomMap m_CustomRecords; CTwMgr::CStructProxy * m_CustomActiveStructProxy; friend struct CTwMgr; }; void DrawArc(int _X, int _Y, int _Radius, float _StartAngleDeg, float _EndAngleDeg, color32 _Color); // --------------------------------------------------------------------------- #endif // !defined ANT_TW_BAR_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwColors.cpp0000644000000000000000000001045112635011627025030 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwColors.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "TwColors.h" void ColorRGBToHLSf(float _R, float _G, float _B, float *_Hue, float *_Light, float *_Saturation) { // Compute HLS from RGB. The r,g,b triplet is between [0,1], // hue is between [0,360], light and saturation are [0,1]. float rnorm, gnorm, bnorm, minval, maxval, msum, mdiff, r, g, b; r = g = b = 0; if(_R>0) r = _R; if(r>1) r = 1; if(_G>0) g = _G; if(g>1) g = 1; if(_B>0) b = _B; if(b>1) b = 1; minval = r; if(gmaxval) maxval = g; if(b>maxval) maxval = b; rnorm = gnorm = bnorm = 0; mdiff = maxval - minval; msum = maxval + minval; float l = 0.5f * msum; if(_Light) *_Light = l; if(maxval!=minval) { rnorm = (maxval - r)/mdiff; gnorm = (maxval - g)/mdiff; bnorm = (maxval - b)/mdiff; } else { if(_Saturation) *_Saturation = 0; if(_Hue) *_Hue = 0; return; } if(_Saturation) { if(l<0.5f) *_Saturation = mdiff/msum; else *_Saturation = mdiff/(2.0f - msum); } if(_Hue) { if(r==maxval) *_Hue = 60.0f * (6.0f + bnorm - gnorm); else if(g==maxval) *_Hue = 60.0f * (2.0f + rnorm - bnorm); else *_Hue = 60.0f * (4.0f + gnorm - rnorm); if(*_Hue>360.0f) *_Hue -= 360.0f; } } void ColorRGBToHLSi(int _R, int _G, int _B, int *_Hue, int *_Light, int *_Saturation) { float h, l, s; ColorRGBToHLSf((1.0f/255.0f)*float(_R), (1.0f/255.0f)*float(_G), (1.0f/255.0f)*float(_B), &h, &l, &s); if(_Hue) *_Hue = (int)TClamp(h*(256.0f/360.0f), 0.0f, 255.0f); if(_Light) *_Light = (int)TClamp(l*256.0f, 0.0f, 255.0f); if(_Saturation) *_Saturation= (int)TClamp(s*256.0f, 0.0f, 255.0f); } void ColorHLSToRGBf(float _Hue, float _Light, float _Saturation, float *_R, float *_G, float *_B) { // Compute RGB from HLS. The light and saturation are between [0,1] // and hue is between [0,360]. The returned r,g,b triplet is between [0,1]. // a local auxiliary function struct CLocal { static float HLSToRGB(float _Rn1, float _Rn2, float _Huei) { float hue = _Huei; if(hue>360) hue = hue - 360; if(hue<0) hue = hue + 360; if(hue<60 ) return _Rn1 + (_Rn2-_Rn1)*hue/60; if(hue<180) return _Rn2; if(hue<240) return _Rn1 + (_Rn2-_Rn1)*(240-hue)/60; return _Rn1; } }; float rh, rl, rs, rm1, rm2; rh = rl = rs = 0; if(_Hue>0) rh = _Hue; if(rh>360) rh = 360; if(_Light>0) rl = _Light; if(rl>1) rl = 1; if(_Saturation>0) rs = _Saturation; if(rs>1) rs = 1; if(rl<=0.5f) rm2 = rl*(1.0f + rs); else rm2 = rl + rs - rl*rs; rm1 = 2.0f*rl - rm2; if(!rs) { if(_R) *_R = rl; if(_G) *_G = rl; if(_B) *_B = rl; } else { if(_R) *_R = CLocal::HLSToRGB(rm1, rm2, rh+120); if(_G) *_G = CLocal::HLSToRGB(rm1, rm2, rh); if(_B) *_B = CLocal::HLSToRGB(rm1, rm2, rh-120); } } void ColorHLSToRGBi(int _Hue, int _Light, int _Saturation, int *_R, int *_G, int *_B) { float r, g, b; ColorHLSToRGBf((360.0f/255.0f)*float(_Hue), (1.0f/255.0f)*float(_Light), (1.0f/255.0f)*float(_Saturation), &r, &g, &b); if(_R) *_R = (int)TClamp(r*256.0f, 0.0f, 255.0f); if(_G) *_G = (int)TClamp(g*256.0f, 0.0f, 255.0f); if(_B) *_B = (int)TClamp(b*256.0f, 0.0f, 255.0f); } color32 ColorBlend(color32 _Color1, color32 _Color2, float _S) { float a1, r1, g1, b1, a2, r2, g2, b2; Color32ToARGBf(_Color1, &a1, &r1, &g1, &b1); Color32ToARGBf(_Color2, &a2, &r2, &g2, &b2); float t = 1.0f-_S; return Color32FromARGBf(t*a1+_S*a2, t*r1+_S*r2, t*g1+_S*g2, t*b1+_S*b2); } ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwColors.h0000644000000000000000000000551012635011627024475 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwColors.h // @brief Color conversions // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_COLORS_INCLUDED #define ANT_TW_COLORS_INCLUDED // --------------------------------------------------------------------------- typedef unsigned int color32; const color32 COLOR32_BLACK = 0xff000000; // Black const color32 COLOR32_WHITE = 0xffffffff; // White const color32 COLOR32_ZERO = 0x00000000; // Zero const color32 COLOR32_RED = 0xffff0000; // Red const color32 COLOR32_GREEN = 0xff00ff00; // Green const color32 COLOR32_BLUE = 0xff0000ff; // Blue template inline const _T& TClamp(const _T& _X, const _T& _Limit1, const _T& _Limit2) { if( _Limit1<_Limit2 ) return (_X<=_Limit1) ? _Limit1 : ( (_X>=_Limit2) ? _Limit2 : _X ); else return (_X<=_Limit2) ? _Limit2 : ( (_X>=_Limit1) ? _Limit1 : _X ); } inline color32 Color32FromARGBi(int _A, int _R, int _G, int _B) { return (((color32)TClamp(_A, 0, 255))<<24) | (((color32)TClamp(_R, 0, 255))<<16) | (((color32)TClamp(_G, 0, 255))<<8) | ((color32)TClamp(_B, 0, 255)); } inline color32 Color32FromARGBf(float _A, float _R, float _G, float _B) { return (((color32)TClamp(_A*256.0f, 0.0f, 255.0f))<<24) | (((color32)TClamp(_R*256.0f, 0.0f, 255.0f))<<16) | (((color32)TClamp(_G*256.0f, 0.0f, 255.0f))<<8) | ((color32)TClamp(_B*256.0f, 0.0f, 255.0f)); } inline void Color32ToARGBi(color32 _Color, int *_A, int *_R, int *_G, int *_B) { if(_A) *_A = (_Color>>24)&0xff; if(_R) *_R = (_Color>>16)&0xff; if(_G) *_G = (_Color>>8)&0xff; if(_B) *_B = _Color&0xff; } inline void Color32ToARGBf(color32 _Color, float *_A, float *_R, float *_G, float *_B) { if(_A) *_A = (1.0f/255.0f)*float((_Color>>24)&0xff); if(_R) *_R = (1.0f/255.0f)*float((_Color>>16)&0xff); if(_G) *_G = (1.0f/255.0f)*float((_Color>>8)&0xff); if(_B) *_B = (1.0f/255.0f)*float(_Color&0xff); } void ColorRGBToHLSf(float _R, float _G, float _B, float *_Hue, float *_Light, float *_Saturation); void ColorRGBToHLSi(int _R, int _G, int _B, int *_Hue, int *_Light, int *_Saturation); void ColorHLSToRGBf(float _Hue, float _Light, float _Saturation, float *_R, float *_G, float *_B); void ColorHLSToRGBi(int _Hue, int _Light, int _Saturation, int *_R, int *_G, int *_B); color32 ColorBlend(color32 _Color1, color32 _Color2, float _S); // --------------------------------------------------------------------------- #endif // !defined ANT_TW_COLORS_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwDirect3D10.cpp0000644000000000000000000012547412635011627025345 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwDirect3D10.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "TwDirect3D10.h" #include "TwMgr.h" #include "TwColors.h" #include "d3d10vs2003.h" // Workaround to include D3D10.h with VS2003 #define D3D10_IGNORE_SDK_LAYERS // d3d10sdklayers.h may not exist #include using namespace std; const char *g_ErrCantLoadD3D10 = "Cannot load Direct3D10 library dynamically"; const char *g_ErrCompileFX10 = "Direct3D10 effect compilation failed"; const char *g_ErrCreateFX10 = "Direct3D10 effect creation failed"; const char *g_ErrTechNotFound10 = "Cannot find Direct3D10 technique effect"; const char *g_ErrCreateLayout10 = "Direct3D10 vertex layout creation failed"; const char *g_ErrCreateBuffer10 = "Direct3D10 vertex buffer creation failed"; // --------------------------------------------------------------------------- // Dynamically loaded D3D10 functions (to avoid static linkage with d3d10.lib) HMODULE g_D3D10Module = NULL; typedef HRESULT (WINAPI *D3D10CompileEffectFromMemoryProc)(void *pData, SIZE_T DataLength, LPCSTR pSrcFileName, CONST D3D10_SHADER_MACRO *pDefines, ID3D10Include *pInclude, UINT HLSLFlags, UINT FXFlags, ID3D10Blob **ppCompiledEffect, ID3D10Blob **ppErrors); typedef HRESULT (WINAPI *D3D10CreateEffectFromMemoryProc)(void *pData, SIZE_T DataLength, UINT FXFlags, ID3D10Device *pDevice, ID3D10EffectPool *pEffectPool, ID3D10Effect **ppEffect); typedef HRESULT (WINAPI *D3D10StateBlockMaskEnableAllProc)(D3D10_STATE_BLOCK_MASK *pMask); typedef HRESULT (WINAPI *D3D10CreateStateBlockProc)(ID3D10Device *pDevice, D3D10_STATE_BLOCK_MASK *pStateBlockMask, ID3D10StateBlock **ppStateBlock); D3D10CompileEffectFromMemoryProc _D3D10CompileEffectFromMemory = NULL; D3D10CreateEffectFromMemoryProc _D3D10CreateEffectFromMemory = NULL; D3D10StateBlockMaskEnableAllProc _D3D10StateBlockMaskEnableAll = NULL; D3D10CreateStateBlockProc _D3D10CreateStateBlock = NULL; const RECT FullRect = {0, 0, 16000, 16000}; static bool RectIsFull(const RECT& r) { return r.left==FullRect.left && r.right==FullRect.right && r.top==FullRect.top && r.bottom==FullRect.bottom; } static int LoadDirect3D10() { if( g_D3D10Module!=NULL ) return 1; // Direct3D10 library already loaded g_D3D10Module = LoadLibrary("D3D10.DLL"); if( g_D3D10Module ) { int res = 1; _D3D10CompileEffectFromMemory = reinterpret_cast(GetProcAddress(g_D3D10Module, "D3D10CompileEffectFromMemory")); if( _D3D10CompileEffectFromMemory==NULL ) res = 0; _D3D10CreateEffectFromMemory = reinterpret_cast(GetProcAddress(g_D3D10Module, "D3D10CreateEffectFromMemory")); if( _D3D10CreateEffectFromMemory==NULL ) res = 0; _D3D10StateBlockMaskEnableAll = reinterpret_cast(GetProcAddress(g_D3D10Module, "D3D10StateBlockMaskEnableAll")); if( _D3D10StateBlockMaskEnableAll==NULL ) res = 0; _D3D10CreateStateBlock = reinterpret_cast(GetProcAddress(g_D3D10Module, "D3D10CreateStateBlock")); if( _D3D10CreateStateBlock==NULL ) res = 0; return res; } else return 0; // cannot load DLL } static int UnloadDirect3D10() { _D3D10CompileEffectFromMemory = NULL; _D3D10CreateEffectFromMemory = NULL; _D3D10StateBlockMaskEnableAll = NULL; _D3D10CreateStateBlock = NULL; if( g_D3D10Module==NULL ) return 1; // Direct3D10 library not loaded if( FreeLibrary(g_D3D10Module) ) { g_D3D10Module = NULL; return 1; } else return 0; // cannot unload d3d10.dll } // --------------------------------------------------------------------------- static ID3D10ShaderResourceView *BindFont(ID3D10Device *_Dev, ID3D10EffectShaderResourceVariable *_ResVar, const CTexFont *_Font) { assert(_Font!=NULL); assert(_ResVar!=NULL); int w = _Font->m_TexWidth; int h = _Font->m_TexHeight; color32 *font32 = new color32[w*h]; color32 *p = font32; for( int i=0; im_TexBytes[i]))<<24); D3D10_TEXTURE2D_DESC desc; desc.Width = w; desc.Height = h; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D10_USAGE_IMMUTABLE; desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; D3D10_SUBRESOURCE_DATA data; data.pSysMem = font32; data.SysMemPitch = w*sizeof(color32); data.SysMemSlicePitch = 0; ID3D10Texture2D *tex = NULL; ID3D10ShaderResourceView *texRV = NULL; if( SUCCEEDED(_Dev->CreateTexture2D(&desc, &data, &tex)) ) { if( SUCCEEDED(_Dev->CreateShaderResourceView(tex, NULL, &texRV)) ) if( _ResVar ) _ResVar->SetResource(texRV); tex->Release(); tex = NULL; } delete[] font32; return texRV; } // --------------------------------------------------------------------------- static void UnbindFont(ID3D10Device *_Dev, ID3D10EffectShaderResourceVariable *_ResVar, ID3D10ShaderResourceView *_TexRV) { (void)_Dev; if( _ResVar ) _ResVar->SetResource(NULL); if( _TexRV ) { ULONG rc = _TexRV->Release(); assert( rc==0 ); (void)rc; } } // --------------------------------------------------------------------------- struct CState10 { ID3D10StateBlock * m_StateBlock; void Save(); void Restore(); CState10(ID3D10Device *_Dev); ~CState10(); private: ID3D10Device * m_D3DDev; }; CState10::CState10(ID3D10Device *_Dev) { ZeroMemory(this, sizeof(CState10)); m_D3DDev = _Dev; } CState10::~CState10() { if( m_StateBlock ) { UINT rc = m_StateBlock->Release(); assert( rc==0 ); (void)rc; m_StateBlock = NULL; } } void CState10::Save() { if( !m_StateBlock ) { D3D10_STATE_BLOCK_MASK stateMask; _D3D10StateBlockMaskEnableAll(&stateMask); _D3D10CreateStateBlock(m_D3DDev, &stateMask, &m_StateBlock); } if( m_StateBlock ) m_StateBlock->Capture(); } void CState10::Restore() { if( m_StateBlock ) m_StateBlock->Apply(); } // --------------------------------------------------------------------------- char g_ShaderFX[] = "// AntTweakBar shaders and techniques \n" " float4 g_Offset = 0; float4 g_CstColor = 1; \n" " struct LineRectPSInput { float4 Pos : SV_POSITION; float4 Color : COLOR0; }; \n" " LineRectPSInput LineRectVS(float4 pos : POSITION, float4 color : COLOR, uniform bool useCstColor) { \n" " LineRectPSInput ps; ps.Pos = pos + g_Offset; \n" " ps.Color = useCstColor ? g_CstColor : color; return ps; } \n" " float4 LineRectPS(LineRectPSInput input) : SV_Target { return input.Color; } \n" " technique10 LineRect { pass P0 { \n" " SetVertexShader( CompileShader( vs_4_0, LineRectVS(false) ) ); \n" " SetGeometryShader( NULL ); \n" " SetPixelShader( CompileShader( ps_4_0, LineRectPS() ) ); \n" " } }\n" " technique10 LineRectCstColor { pass P0 { \n" " SetVertexShader( CompileShader( vs_4_0, LineRectVS(true) ) ); \n" " SetGeometryShader( NULL ); \n" " SetPixelShader( CompileShader( ps_4_0, LineRectPS() ) ); \n" " } }\n" " Texture2D Font; \n" " SamplerState FontSampler { Filter = MIN_MAG_MIP_POINT; AddressU = BORDER; AddressV = BORDER; BorderColor=float4(0, 0, 0, 0); }; \n" " struct TextPSInput { float4 Pos : SV_POSITION; float4 Color : COLOR0; float2 Tex : TEXCOORD0; }; \n" " TextPSInput TextVS(float4 pos : POSITION, float4 color : COLOR, float2 tex : TEXCOORD0, uniform bool useCstColor) { \n" " TextPSInput ps; ps.Pos = pos + g_Offset; \n" " ps.Color = useCstColor ? g_CstColor : color; ps.Tex = tex; return ps; } \n" " float4 TextPS(TextPSInput input) : SV_Target { return Font.Sample(FontSampler, input.Tex)*input.Color; } \n" " technique10 Text { pass P0 { \n" " SetVertexShader( CompileShader( vs_4_0, TextVS(false) ) ); \n" " SetGeometryShader( NULL ); \n" " SetPixelShader( CompileShader( ps_4_0, TextPS() ) ); \n" " } }\n" " technique10 TextCstColor { pass P0 { \n" " SetVertexShader( CompileShader( vs_4_0, TextVS(true) ) ); \n" " SetGeometryShader( NULL ); \n" " SetPixelShader( CompileShader( ps_4_0, TextPS() ) ); \n" " } }\n" " // End of AntTweakBar shaders and techniques \n"; // --------------------------------------------------------------------------- int CTwGraphDirect3D10::Init() { assert(g_TwMgr!=NULL); assert(g_TwMgr->m_Device!=NULL); m_D3DDev = static_cast(g_TwMgr->m_Device); m_D3DDevInitialRefCount = m_D3DDev->AddRef() - 1; m_Drawing = false; m_OffsetX = m_OffsetY = 0; m_ViewportInit = new D3D10_VIEWPORT; m_FontTex = NULL; m_FontD3DTexRV = NULL; m_WndWidth = 0; m_WndHeight = 0; m_State = NULL; m_DepthStencilState = NULL; m_BlendState = NULL; m_RasterState = NULL; m_RasterStateAntialiased = NULL; m_RasterStateCullCW = NULL; m_RasterStateCullCCW = NULL; m_Effect = NULL; m_LineRectTech = NULL; m_LineRectCstColorTech = NULL; m_LineRectVertexLayout = NULL; m_LineVertexBuffer = NULL; m_RectVertexBuffer = NULL; m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; m_TextTech = NULL; m_TextCstColorTech = NULL; m_TextVertexLayout = NULL; m_FontD3DResVar = NULL; m_OffsetVar = NULL; m_CstColorVar = NULL; // Load some D3D10 functions if( !LoadDirect3D10() ) { g_TwMgr->SetLastError(g_ErrCantLoadD3D10); Shut(); return 0; } // Allocate state object m_State = new CState10(m_D3DDev); // Compile shaders DWORD shaderFlags = D3D10_SHADER_ENABLE_STRICTNESS; #if defined( DEBUG ) || defined( _DEBUG ) // shaderFlags |= D3D10_SHADER_DEBUG; // no more supported #endif ID3D10Blob *compiledFX = NULL; ID3D10Blob *errors = NULL; HRESULT hr = _D3D10CompileEffectFromMemory(g_ShaderFX, strlen(g_ShaderFX), "AntTweakBarFX", NULL, NULL, shaderFlags, 0, &compiledFX, &errors); if( FAILED(hr) ) { const size_t ERR_MSG_MAX_LEN = 4096; static char s_ErrorMsg[ERR_MSG_MAX_LEN]; // must be static to be sent to SetLastError strncpy(s_ErrorMsg, g_ErrCompileFX10, ERR_MSG_MAX_LEN-1); size_t errOffset = strlen(s_ErrorMsg); size_t errLen = 0; if( errors!=NULL ) { s_ErrorMsg[errOffset++] = ':'; s_ErrorMsg[errOffset++] = '\n'; errLen = min(errors->GetBufferSize(), ERR_MSG_MAX_LEN-errOffset-2); strncpy(s_ErrorMsg+errOffset, static_cast(errors->GetBufferPointer()), errLen); errors->Release(); errors = NULL; } s_ErrorMsg[errOffset+errLen] = '\0'; g_TwMgr->SetLastError(s_ErrorMsg); Shut(); return 0; } hr = _D3D10CreateEffectFromMemory(compiledFX->GetBufferPointer(), compiledFX->GetBufferSize(), 0, m_D3DDev, NULL, &m_Effect); compiledFX->Release(); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateFX10); Shut(); return 0; } // Obtain the techniques m_LineRectTech = m_Effect->GetTechniqueByName("LineRect"); m_LineRectCstColorTech = m_Effect->GetTechniqueByName("LineRectCstColor"); m_TextTech = m_Effect->GetTechniqueByName("Text"); m_TextCstColorTech = m_Effect->GetTechniqueByName("TextCstColor"); if( m_LineRectTech==NULL || m_TextTech==NULL || m_LineRectCstColorTech==NULL || m_TextCstColorTech==NULL ) { g_TwMgr->SetLastError(g_ErrTechNotFound10); Shut(); return 0; } // Create input layout for lines & rect D3D10_INPUT_ELEMENT_DESC lineRectLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(CLineRectVtx, m_Color), D3D10_INPUT_PER_VERTEX_DATA, 0 } }; D3D10_PASS_DESC passDesc; hr = m_LineRectTech->GetPassByIndex(0)->GetDesc(&passDesc); if( SUCCEEDED(hr) ) hr = m_D3DDev->CreateInputLayout(lineRectLayout, sizeof(lineRectLayout)/sizeof(lineRectLayout[0]), passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &m_LineRectVertexLayout); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateLayout10); Shut(); return 0; } // Create line vertex buffer D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DYNAMIC; bd.ByteWidth = 2 * sizeof(CLineRectVtx); bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; hr = m_D3DDev->CreateBuffer(&bd, NULL, &m_LineVertexBuffer); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateBuffer10); Shut(); return 0; } // Create rect vertex buffer bd.ByteWidth = 4 * sizeof(CLineRectVtx); hr = m_D3DDev->CreateBuffer(&bd, NULL, &m_RectVertexBuffer); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateBuffer10); Shut(); return 0; } // Create input layout for text D3D10_INPUT_ELEMENT_DESC textLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(CTextVtx, m_Color), D3D10_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(CTextVtx, m_UV), D3D10_INPUT_PER_VERTEX_DATA, 0 } }; hr = m_TextTech->GetPassByIndex(0)->GetDesc(&passDesc); if( SUCCEEDED(hr) ) hr = m_D3DDev->CreateInputLayout(textLayout, sizeof(textLayout)/sizeof(textLayout[0]), passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &m_TextVertexLayout); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateLayout10); Shut(); return 0; } // Create depth stencil state object D3D10_DEPTH_STENCILOP_DESC od; od.StencilFunc = D3D10_COMPARISON_ALWAYS; od.StencilFailOp = D3D10_STENCIL_OP_KEEP; od.StencilPassOp = D3D10_STENCIL_OP_KEEP; od.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP; D3D10_DEPTH_STENCIL_DESC dsd; dsd.DepthEnable = FALSE; dsd.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ZERO; dsd.DepthFunc = D3D10_COMPARISON_ALWAYS; dsd.StencilEnable = FALSE; dsd.StencilReadMask = D3D10_DEFAULT_STENCIL_READ_MASK; dsd.StencilWriteMask = D3D10_DEFAULT_STENCIL_WRITE_MASK; dsd.FrontFace = od; dsd.BackFace = od; m_D3DDev->CreateDepthStencilState(&dsd, &m_DepthStencilState); // Create blend state object D3D10_BLEND_DESC bsd; bsd.AlphaToCoverageEnable = FALSE; for(int i=0; i<8; ++i) { bsd.BlendEnable[i] = TRUE; bsd.RenderTargetWriteMask[i] = D3D10_COLOR_WRITE_ENABLE_ALL; } bsd.SrcBlend = D3D10_BLEND_SRC_ALPHA; bsd.DestBlend = D3D10_BLEND_INV_SRC_ALPHA; bsd.BlendOp = D3D10_BLEND_OP_ADD; bsd.SrcBlendAlpha = D3D10_BLEND_SRC_ALPHA; bsd.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; bsd.BlendOpAlpha = D3D10_BLEND_OP_ADD; m_D3DDev->CreateBlendState(&bsd, &m_BlendState); // Create rasterizer state object D3D10_RASTERIZER_DESC rd; rd.FillMode = D3D10_FILL_SOLID; rd.CullMode = D3D10_CULL_NONE; rd.FrontCounterClockwise = true; rd.DepthBias = false; rd.DepthBiasClamp = 0; rd.SlopeScaledDepthBias = 0; rd.DepthClipEnable = false; rd.ScissorEnable = true; rd.MultisampleEnable = false; rd.AntialiasedLineEnable = false; m_D3DDev->CreateRasterizerState(&rd, &m_RasterState); rd.AntialiasedLineEnable = true; m_D3DDev->CreateRasterizerState(&rd, &m_RasterStateAntialiased); rd.AntialiasedLineEnable = false; rd.CullMode = D3D10_CULL_BACK; m_D3DDev->CreateRasterizerState(&rd, &m_RasterStateCullCW); rd.CullMode = D3D10_CULL_FRONT; m_D3DDev->CreateRasterizerState(&rd, &m_RasterStateCullCCW); m_ViewportAndScissorRects[0] = FullRect; m_ViewportAndScissorRects[1] = FullRect; m_D3DDev->RSSetScissorRects(1, m_ViewportAndScissorRects); // Get effect globals if( m_Effect->GetVariableByName("Font") ) m_FontD3DResVar = m_Effect->GetVariableByName("Font")->AsShaderResource(); assert( m_FontD3DResVar!=NULL ); if( m_Effect->GetVariableByName("g_Offset") ) m_OffsetVar = m_Effect->GetVariableByName("g_Offset")->AsVector(); assert( m_OffsetVar!=NULL ); if( m_Effect->GetVariableByName("g_CstColor") ) m_CstColorVar = m_Effect->GetVariableByName("g_CstColor")->AsVector(); assert( m_CstColorVar!=NULL ); return 1; } // --------------------------------------------------------------------------- int CTwGraphDirect3D10::Shut() { assert(m_Drawing==false); UnbindFont(m_D3DDev, m_FontD3DResVar, m_FontD3DTexRV); m_FontD3DTexRV = NULL; if( m_State ) { delete m_State; m_State = NULL; } if( m_ViewportInit ) { delete m_ViewportInit; m_ViewportInit = NULL; } if( m_DepthStencilState ) { ULONG rc = m_DepthStencilState->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_DepthStencilState = NULL; } if( m_BlendState ) { ULONG rc = m_BlendState->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_BlendState = NULL; } if( m_RasterState ) { ULONG rc = m_RasterState->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterState = NULL; } if( m_RasterStateAntialiased ) { ULONG rc = m_RasterStateAntialiased->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterStateAntialiased = NULL; } if( m_RasterStateCullCW ) { ULONG rc = m_RasterStateCullCW->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterStateCullCW = NULL; } if( m_RasterStateCullCCW ) { ULONG rc = m_RasterStateCullCCW->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterStateCullCCW = NULL; } m_FontD3DResVar = NULL; m_OffsetVar = NULL; m_CstColorVar = NULL; if( m_LineVertexBuffer ) { ULONG rc = m_LineVertexBuffer->Release(); assert( rc==0 ); (void)rc; m_LineVertexBuffer = NULL; } if( m_RectVertexBuffer ) { ULONG rc = m_RectVertexBuffer->Release(); assert( rc==0 ); (void)rc; m_RectVertexBuffer = NULL; } if( m_TrianglesVertexBuffer ) { ULONG rc = m_TrianglesVertexBuffer->Release(); assert( rc==0 ); (void)rc; m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; } if( m_LineRectVertexLayout ) { ULONG rc = m_LineRectVertexLayout->Release(); assert( rc==0 ); (void)rc; m_LineRectVertexLayout = NULL; } if( m_TextVertexLayout ) { ULONG rc = m_TextVertexLayout->Release(); assert( rc==0 ); (void)rc; m_TextVertexLayout = NULL; } if( m_Effect ) { ULONG rc = m_Effect->Release(); assert( rc==0 ); (void)rc; m_Effect = NULL; } if( m_D3DDev ) { //unsigned int rc = m_D3DDev->Release(); //assert( m_D3DDevInitialRefCount==rc ); (void)rc; m_D3DDev->Release(); m_D3DDev = NULL; } // Unload D3D10 UnloadDirect3D10(); // this is not a problem if it cannot be unloaded return 1; } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::BeginDraw(int _WndWidth, int _WndHeight) { assert(m_Drawing==false && _WndWidth>0 && _WndHeight>0); m_Drawing = true; m_WndWidth = _WndWidth; m_WndHeight = _WndHeight; m_OffsetX = m_OffsetY = 0; // save context m_State->Save(); // Setup the viewport D3D10_VIEWPORT vp; vp.Width = _WndWidth; vp.Height = _WndHeight; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; m_D3DDev->RSSetViewports(1, &vp); *static_cast(m_ViewportInit) = vp; m_D3DDev->RSSetState(m_RasterState); m_D3DDev->OMSetDepthStencilState(m_DepthStencilState, 0); float blendFactors[4] = { 1, 1, 1, 1 }; m_D3DDev->OMSetBlendState(m_BlendState, blendFactors, 0xffffffff); } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::EndDraw() { m_D3DDev->RSSetState(NULL); m_D3DDev->OMSetDepthStencilState(NULL, 0); m_D3DDev->OMSetBlendState(NULL, NULL, 0xffffffff); assert(m_Drawing==true); m_Drawing = false; // restore context m_State->Restore(); } // --------------------------------------------------------------------------- bool CTwGraphDirect3D10::IsDrawing() { return m_Drawing; } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::Restore() { if( m_State ) { if( m_State->m_StateBlock ) { UINT rc = m_State->m_StateBlock->Release(); assert( rc==0 ); (void)rc; m_State->m_StateBlock = NULL; } } UnbindFont(m_D3DDev, m_FontD3DResVar, m_FontD3DTexRV); m_FontD3DTexRV = NULL; m_FontTex = NULL; } // --------------------------------------------------------------------------- static inline float ToNormScreenX(int x, int wndWidth) { return 2.0f*((float)x-0.5f)/wndWidth - 1.0f; } static inline float ToNormScreenY(int y, int wndHeight) { return 1.0f - 2.0f*((float)y-0.5f)/wndHeight; } static inline color32 ToR8G8B8A8(color32 col) { return (col & 0xff00ff00) | ((col>>16) & 0xff) | ((col<<16) & 0xff0000); } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased) { assert(m_Drawing==true); float x0 = ToNormScreenX(_X0 + m_OffsetX, m_WndWidth); float y0 = ToNormScreenY(_Y0 + m_OffsetY, m_WndHeight); float x1 = ToNormScreenX(_X1 + m_OffsetX, m_WndWidth); float y1 = ToNormScreenY(_Y1 + m_OffsetY, m_WndHeight); CLineRectVtx *vertices = NULL; HRESULT hr = m_LineVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void **)&vertices); if( SUCCEEDED(hr) ) { // Fill vertex buffer vertices[0].m_Pos[0] = x0; vertices[0].m_Pos[1] = y0; vertices[0].m_Pos[2] = 0; vertices[0].m_Color = ToR8G8B8A8(_Color0); vertices[1].m_Pos[0] = x1; vertices[1].m_Pos[1] = y1; vertices[1].m_Pos[2] = 0; vertices[1].m_Color = ToR8G8B8A8(_Color1); m_LineVertexBuffer->Unmap(); if( _AntiAliased ) m_D3DDev->RSSetState(m_RasterStateAntialiased); // Reset shader globals float offsetVec[4] = { 0, 0, 0, 0 }; if( m_OffsetVar ) m_OffsetVar->SetFloatVector(offsetVec); float colorVec[4] = { 1, 1, 1, 1 }; if( m_CstColorVar ) m_CstColorVar->SetFloatVector(colorVec); // Set the input layout m_D3DDev->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDev->IASetVertexBuffers(0, 1, &m_LineVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_LINELIST); // Render the line D3D10_TECHNIQUE_DESC techDesc; m_LineRectTech->GetDesc(&techDesc); for(UINT p=0; pGetPassByIndex(p)->Apply(0); m_D3DDev->Draw(2, 0); } if( _AntiAliased ) m_D3DDev->RSSetState(m_RasterState); // restore default raster state } } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11) { assert(m_Drawing==true); // border adjustment if(_X0<_X1) ++_X1; else if(_X0>_X1) ++_X0; if(_Y0<_Y1) ++_Y1; else if(_Y0>_Y1) ++_Y0; float x0 = ToNormScreenX(_X0 + m_OffsetX, m_WndWidth); float y0 = ToNormScreenY(_Y0 + m_OffsetY, m_WndHeight); float x1 = ToNormScreenX(_X1 + m_OffsetX, m_WndWidth); float y1 = ToNormScreenY(_Y1 + m_OffsetY, m_WndHeight); CLineRectVtx *vertices = NULL; HRESULT hr = m_RectVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void **)&vertices); if( SUCCEEDED(hr) ) { // Fill vertex buffer vertices[0].m_Pos[0] = x0; vertices[0].m_Pos[1] = y0; vertices[0].m_Pos[2] = 0; vertices[0].m_Color = ToR8G8B8A8(_Color00); vertices[1].m_Pos[0] = x1; vertices[1].m_Pos[1] = y0; vertices[1].m_Pos[2] = 0; vertices[1].m_Color = ToR8G8B8A8(_Color10); vertices[2].m_Pos[0] = x0; vertices[2].m_Pos[1] = y1; vertices[2].m_Pos[2] = 0; vertices[2].m_Color = ToR8G8B8A8(_Color01); vertices[3].m_Pos[0] = x1; vertices[3].m_Pos[1] = y1; vertices[3].m_Pos[2] = 0; vertices[3].m_Color = ToR8G8B8A8(_Color11); m_RectVertexBuffer->Unmap(); // Reset shader globals float offsetVec[4] = { 0, 0, 0, 0 }; if( m_OffsetVar ) m_OffsetVar->SetFloatVector(offsetVec); float colorVec[4] = { 1, 1, 1, 1 }; if( m_CstColorVar ) m_CstColorVar->SetFloatVector(colorVec); // Set the input layout m_D3DDev->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDev->IASetVertexBuffers(0, 1, &m_RectVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); // Render the rect D3D10_TECHNIQUE_DESC techDesc; m_LineRectTech->GetDesc(&techDesc); for(UINT p=0; pGetPassByIndex(p)->Apply(0); m_D3DDev->Draw(4, 0); } } } // --------------------------------------------------------------------------- void *CTwGraphDirect3D10::NewTextObj() { CTextObj *textObj = new CTextObj; memset(textObj, 0, sizeof(CTextObj)); return textObj; } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::DeleteTextObj(void *_TextObj) { assert(_TextObj!=NULL); CTextObj *textObj = static_cast(_TextObj); if( textObj->m_TextVertexBuffer ) textObj->m_TextVertexBuffer->Release(); if( textObj->m_BgVertexBuffer ) textObj->m_BgVertexBuffer->Release(); memset(textObj, 0, sizeof(CTextObj)); delete textObj; } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth) { assert(m_Drawing==true); assert(_TextObj!=NULL); assert(_Font!=NULL); if( _Font != m_FontTex ) { UnbindFont(m_D3DDev, m_FontD3DResVar, m_FontD3DTexRV); m_FontD3DTexRV = BindFont(m_D3DDev, m_FontD3DResVar, _Font); m_FontTex = _Font; } int nbTextVerts = 0; int line; for( line=0; line<_NbLines; ++line ) nbTextVerts += 6 * (int)_TextLines[line].length(); int nbBgVerts = 0; if( _BgWidth>0 ) nbBgVerts = _NbLines*6; CTextObj *textObj = static_cast(_TextObj); textObj->m_LineColors = (_LineColors!=NULL); textObj->m_LineBgColors = (_LineBgColors!=NULL); // (re)create text vertex buffer if needed, and map it CTextVtx *textVerts = NULL; if( nbTextVerts>0 ) { if( textObj->m_TextVertexBuffer==NULL || textObj->m_TextVertexBufferSizem_TextVertexBuffer!=NULL ) { ULONG rc = textObj->m_TextVertexBuffer->Release(); assert( rc==0 ); (void)rc; textObj->m_TextVertexBuffer = NULL; } textObj->m_TextVertexBufferSize = nbTextVerts + 6*256; // add a reserve of 256 characters D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DYNAMIC; bd.ByteWidth = textObj->m_TextVertexBufferSize * sizeof(CTextVtx); bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; m_D3DDev->CreateBuffer(&bd, NULL, &textObj->m_TextVertexBuffer); } if( textObj->m_TextVertexBuffer!=NULL ) textObj->m_TextVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void **)&textVerts); } // (re)create bg vertex buffer if needed, and map it CLineRectVtx *bgVerts = NULL; if( nbBgVerts>0 ) { if( textObj->m_BgVertexBuffer==NULL || textObj->m_BgVertexBufferSizem_BgVertexBuffer!=NULL ) { ULONG rc = textObj->m_BgVertexBuffer->Release(); assert( rc==0 ); (void)rc; textObj->m_BgVertexBuffer = NULL; } textObj->m_BgVertexBufferSize = nbBgVerts + 6*32; // add a reserve of 32 rects D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DYNAMIC; bd.ByteWidth = textObj->m_BgVertexBufferSize * sizeof(CLineRectVtx); bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; m_D3DDev->CreateBuffer(&bd, NULL, &textObj->m_BgVertexBuffer); } if( textObj->m_BgVertexBuffer!=NULL ) textObj->m_BgVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void **)&bgVerts); } int x, x1, y, y1, i, len; float px, px1, py, py1; unsigned char ch; const unsigned char *text; color32 lineColor = COLOR32_RED; CTextVtx vtx; vtx.m_Pos[2] = 0; CLineRectVtx bgVtx; bgVtx.m_Pos[2] = 0; int textVtxIndex = 0; int bgVtxIndex = 0; for( line=0; line<_NbLines; ++line ) { x = 0; y = line * (_Font->m_CharHeight+_Sep); y1 = y+_Font->m_CharHeight; len = (int)_TextLines[line].length(); text = (const unsigned char *)(_TextLines[line].c_str()); if( _LineColors!=NULL ) lineColor = ToR8G8B8A8(_LineColors[line]); if( textVerts!=NULL ) for( i=0; im_CharWidth[ch]; px = ToNormScreenX(x, m_WndWidth); py = ToNormScreenY(y, m_WndHeight); px1 = ToNormScreenX(x1, m_WndWidth); py1 = ToNormScreenY(y1, m_WndHeight); vtx.m_Color = lineColor; vtx.m_Pos[0] = px; vtx.m_Pos[1] = py; vtx.m_UV [0] = _Font->m_CharU0[ch]; vtx.m_UV [1] = _Font->m_CharV0[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px1; vtx.m_Pos[1] = py; vtx.m_UV [0] = _Font->m_CharU1[ch]; vtx.m_UV [1] = _Font->m_CharV0[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px; vtx.m_Pos[1] = py1; vtx.m_UV [0] = _Font->m_CharU0[ch]; vtx.m_UV [1] = _Font->m_CharV1[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px1; vtx.m_Pos[1] = py; vtx.m_UV [0] = _Font->m_CharU1[ch]; vtx.m_UV [1] = _Font->m_CharV0[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px1; vtx.m_Pos[1] = py1; vtx.m_UV [0] = _Font->m_CharU1[ch]; vtx.m_UV [1] = _Font->m_CharV1[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px; vtx.m_Pos[1] = py1; vtx.m_UV [0] = _Font->m_CharU0[ch]; vtx.m_UV [1] = _Font->m_CharV1[ch]; textVerts[textVtxIndex++] = vtx; x = x1; } if( _BgWidth>0 && bgVerts!=NULL ) { if( _LineBgColors!=NULL ) bgVtx.m_Color = ToR8G8B8A8(_LineBgColors[line]); else bgVtx.m_Color = ToR8G8B8A8(COLOR32_BLACK); px = ToNormScreenX(-1, m_WndWidth); py = ToNormScreenY(y, m_WndHeight); px1 = ToNormScreenX(_BgWidth+1, m_WndWidth); py1 = ToNormScreenY(y1, m_WndHeight); bgVtx.m_Pos[0] = px; bgVtx.m_Pos[1] = py; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px1; bgVtx.m_Pos[1] = py; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px; bgVtx.m_Pos[1] = py1; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px1; bgVtx.m_Pos[1] = py; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px1; bgVtx.m_Pos[1] = py1; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px; bgVtx.m_Pos[1] = py1; bgVerts[bgVtxIndex++] = bgVtx; } } assert( textVtxIndex==nbTextVerts ); assert( bgVtxIndex==nbBgVerts ); textObj->m_NbTextVerts = nbTextVerts; textObj->m_NbBgVerts = nbBgVerts; if( textVerts!=NULL ) textObj->m_TextVertexBuffer->Unmap(); if( bgVerts!=NULL ) textObj->m_BgVertexBuffer->Unmap(); } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor) { assert(m_Drawing==true); assert(_TextObj!=NULL); CTextObj *textObj = static_cast(_TextObj); float dx = 2.0f*(float)(_X + m_OffsetX)/m_WndWidth; float dy = -2.0f*(float)(_Y + m_OffsetY)/m_WndHeight; float offsetVec[4] = { 0, 0, 0, 0 }; offsetVec[0] = dx; offsetVec[1] = dy; if( m_OffsetVar ) m_OffsetVar->SetFloatVector(offsetVec); // Draw background if( textObj->m_NbBgVerts>=4 && textObj->m_BgVertexBuffer!=NULL ) { float color[4]; Color32ToARGBf(_BgColor, color+3, color+0, color+1, color+2); if( m_CstColorVar ) m_CstColorVar->SetFloatVector(color); // Set the input layout m_D3DDev->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDev->IASetVertexBuffers(0, 1, &textObj->m_BgVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // Render the bg rectangles ID3D10EffectTechnique *tech; if( _BgColor!=0 || !textObj->m_LineBgColors ) // use a constant bg color tech = m_LineRectCstColorTech; else // use vertex buffer colors tech = m_LineRectTech; D3D10_TECHNIQUE_DESC techDesc; tech->GetDesc(&techDesc); for( UINT p=0; pGetPassByIndex(p)->Apply(0); m_D3DDev->Draw(textObj->m_NbBgVerts, 0); } } // Draw text if( textObj->m_NbTextVerts>=4 && textObj->m_TextVertexBuffer!=NULL ) { float color[4]; Color32ToARGBf(_Color, color+3, color+0, color+1, color+2); if( m_CstColorVar ) m_CstColorVar->SetFloatVector(color); // Set the input layout m_D3DDev->IASetInputLayout(m_TextVertexLayout); // Set vertex buffer UINT stride = sizeof(CTextVtx); UINT offset = 0; m_D3DDev->IASetVertexBuffers(0, 1, &textObj->m_TextVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // Render text ID3D10EffectTechnique *tech; if( _Color!=0 || !textObj->m_LineColors ) // use a constant color tech = m_TextCstColorTech; else // use vertex buffer colors tech = m_TextTech; D3D10_TECHNIQUE_DESC techDesc; tech->GetDesc(&techDesc); for( UINT p=0; pGetPassByIndex(p)->Apply(0); m_D3DDev->Draw(textObj->m_NbTextVerts, 0); } } } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY) { if( _Width>0 && _Height>0 ) { /* viewport changes screen coordinates, use scissor instead D3D10_VIEWPORT vp; vp.TopLeftX = _X0; vp.TopLeftY = _Y0; vp.Width = _Width; vp.Height = _Height; vp.MinDepth = 0; vp.MaxDepth = 1; m_D3DDev->RSSetViewports(1, &vp); */ m_ViewportAndScissorRects[0].left = _X0; m_ViewportAndScissorRects[0].right = _X0 + _Width - 1; m_ViewportAndScissorRects[0].top = _Y0; m_ViewportAndScissorRects[0].bottom = _Y0 + _Height - 1; if( RectIsFull(m_ViewportAndScissorRects[1]) ) m_D3DDev->RSSetScissorRects(1, m_ViewportAndScissorRects); // viewport clipping only else m_D3DDev->RSSetScissorRects(2, m_ViewportAndScissorRects); m_OffsetX = _X0 + _OffsetX; m_OffsetY = _Y0 + _OffsetY; } } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::RestoreViewport() { //m_D3DDev->RSSetViewports(1, static_cast(m_ViewportInit)); m_ViewportAndScissorRects[0] = FullRect; m_D3DDev->RSSetScissorRects(1, m_ViewportAndScissorRects+1); // scissor only m_OffsetX = m_OffsetY = 0; } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::SetScissor(int _X0, int _Y0, int _Width, int _Height) { if( _Width>0 && _Height>0 ) { m_ViewportAndScissorRects[1].left = _X0 - 2; m_ViewportAndScissorRects[1].right = _X0 + _Width - 3; m_ViewportAndScissorRects[1].top = _Y0 - 1; m_ViewportAndScissorRects[1].bottom = _Y0 + _Height - 1; if( RectIsFull(m_ViewportAndScissorRects[0]) ) m_D3DDev->RSSetScissorRects(1, m_ViewportAndScissorRects+1); // no viewport clipping else m_D3DDev->RSSetScissorRects(2, m_ViewportAndScissorRects); } else { m_ViewportAndScissorRects[1] = FullRect; m_D3DDev->RSSetScissorRects(1, m_ViewportAndScissorRects); // apply viewport clipping only } } // --------------------------------------------------------------------------- void CTwGraphDirect3D10::DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode) { assert(m_Drawing==true); if( _NumTriangles<=0 ) return; if( m_TrianglesVertexBufferCount<3*_NumTriangles ) // force re-creation { if( m_TrianglesVertexBuffer!=NULL ) m_TrianglesVertexBuffer->Release(); m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; } // DrawTriangles uses LineRect layout and technique if( m_TrianglesVertexBuffer==NULL ) { // Create triangles vertex buffer D3D10_BUFFER_DESC bd; bd.Usage = D3D10_USAGE_DYNAMIC; bd.BindFlags = D3D10_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; bd.MiscFlags = 0; bd.ByteWidth = 3*_NumTriangles * sizeof(CLineRectVtx); HRESULT hr = m_D3DDev->CreateBuffer(&bd, NULL, &m_TrianglesVertexBuffer); if( SUCCEEDED(hr) ) m_TrianglesVertexBufferCount = 3*_NumTriangles; else { m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; return; // Problem: cannot create triangles VB } } assert( m_TrianglesVertexBufferCount>=3*_NumTriangles ); assert( m_TrianglesVertexBuffer!=NULL ); CLineRectVtx *vertices = NULL; HRESULT hr = m_TrianglesVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void **)&vertices); if( SUCCEEDED(hr) ) { // Fill vertex buffer for( int i=0; i<3*_NumTriangles; ++ i ) { vertices[i].m_Pos[0] = ToNormScreenX(_Vertices[2*i+0] + m_OffsetX, m_WndWidth); vertices[i].m_Pos[1] = ToNormScreenY(_Vertices[2*i+1] + m_OffsetY, m_WndHeight); vertices[i].m_Pos[2] = 0; vertices[i].m_Color = ToR8G8B8A8(_Colors[i]); } m_TrianglesVertexBuffer->Unmap(); // Reset shader globals float offsetVec[4] = { 0, 0, 0, 0 }; if( m_OffsetVar ) m_OffsetVar->SetFloatVector(offsetVec); float colorVec[4] = { 1, 1, 1, 1 }; if( m_CstColorVar ) m_CstColorVar->SetFloatVector(colorVec); // Set the input layout m_D3DDev->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDev->IASetVertexBuffers(0, 1, &m_TrianglesVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); if( _CullMode==CULL_CW ) m_D3DDev->RSSetState(m_RasterStateCullCW); else if( _CullMode==CULL_CCW ) m_D3DDev->RSSetState(m_RasterStateCullCCW); // Render the triangles D3D10_TECHNIQUE_DESC techDesc; m_LineRectTech->GetDesc(&techDesc); for(UINT p=0; pGetPassByIndex(p)->Apply(0); m_D3DDev->Draw(3*_NumTriangles, 0); } if( _CullMode==CULL_CW || _CullMode==CULL_CCW ) m_D3DDev->RSSetState(m_RasterState); // restore default raster state // Unset vertex buffer ID3D10Buffer *vb = NULL; m_D3DDev->IASetVertexBuffers(0, 1, &vb, &stride, &offset); } } // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwDirect3D10.h0000644000000000000000000001152712635011627025003 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwDirect3D10.h // @brief Direct3D10 graph functions // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_DIRECT3D10_INCLUDED #define ANT_TW_DIRECT3D10_INCLUDED #include "TwGraph.h" // --------------------------------------------------------------------------- class CTwGraphDirect3D10 : public ITwGraph { public: virtual int Init(); virtual int Shut(); virtual void BeginDraw(int _WndWidth, int _WndHeight); virtual void EndDraw(); virtual bool IsDrawing(); virtual void Restore(); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased=false); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color, bool _AntiAliased=false) { DrawLine(_X0, _Y0, _X1, _Y1, _Color, _Color, _AntiAliased); } virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11); virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color) { DrawRect(_X0, _Y0, _X1, _Y1, _Color, _Color, _Color, _Color); } virtual void DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode); virtual void * NewTextObj(); virtual void DeleteTextObj(void *_TextObj); virtual void BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth); virtual void DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor); virtual void ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY); virtual void RestoreViewport(); virtual void SetScissor(int _X0, int _Y0, int _Width, int _Height); protected: struct ID3D10Device * m_D3DDev; unsigned int m_D3DDevInitialRefCount; bool m_Drawing; const CTexFont * m_FontTex; struct ID3D10ShaderResourceView *m_FontD3DTexRV; int m_WndWidth; int m_WndHeight; int m_OffsetX; int m_OffsetY; void * m_ViewportInit; RECT m_ViewportAndScissorRects[2]; struct CLineRectVtx { float m_Pos[3]; color32 m_Color; }; struct CTextVtx { float m_Pos[3]; color32 m_Color; float m_UV[2]; }; struct CTextObj { struct ID3D10Buffer * m_TextVertexBuffer; struct ID3D10Buffer * m_BgVertexBuffer; int m_NbTextVerts; int m_NbBgVerts; int m_TextVertexBufferSize; int m_BgVertexBufferSize; bool m_LineColors; bool m_LineBgColors; }; struct CState10 * m_State; struct ID3D10DepthStencilState *m_DepthStencilState; struct ID3D10BlendState * m_BlendState; struct ID3D10RasterizerState * m_RasterState; struct ID3D10RasterizerState * m_RasterStateAntialiased; struct ID3D10RasterizerState * m_RasterStateCullCW; struct ID3D10RasterizerState * m_RasterStateCullCCW; struct ID3D10Effect * m_Effect; struct ID3D10EffectTechnique* m_LineRectTech; struct ID3D10EffectTechnique* m_LineRectCstColorTech; struct ID3D10InputLayout * m_LineRectVertexLayout; struct ID3D10Buffer * m_LineVertexBuffer; struct ID3D10Buffer * m_RectVertexBuffer; struct ID3D10Buffer * m_TrianglesVertexBuffer; int m_TrianglesVertexBufferCount; struct ID3D10EffectTechnique* m_TextTech; struct ID3D10EffectTechnique* m_TextCstColorTech; struct ID3D10InputLayout * m_TextVertexLayout; struct ID3D10EffectShaderResourceVariable *m_FontD3DResVar; struct ID3D10EffectVectorVariable *m_OffsetVar; struct ID3D10EffectVectorVariable *m_CstColorVar; }; // --------------------------------------------------------------------------- #endif // !defined ANT_TW_DIRECT3D10_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwDirect3D11.cpp0000644000000000000000000016076212635011627025345 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwDirect3D11.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "TwDirect3D11.h" #include "TwMgr.h" #include "TwColors.h" #include "d3d10vs2003.h" // Workaround to include D3D10.h and D3D11.h with VS2003 #define D3D11_IGNORE_SDK_LAYERS // d3d11sdklayers.h may not exist #include using namespace std; const char *g_ErrCantLoadD3D11 = "Cannot load Direct3D11 library dynamically"; const char *g_ErrCreateVS11 = "Direct3D11 vertex shader creation failed"; const char *g_ErrCreatePS11 = "Direct3D11 pixel shader creation failed"; const char *g_ErrCreateLayout11 = "Direct3D11 vertex layout creation failed"; const char *g_ErrCreateBuffer11 = "Direct3D11 vertex buffer creation failed"; const char *g_ErrCreateSampler11 = "Direct3D11 sampler state creation failed"; // --------------------------------------------------------------------------- // Shaders : In order to avoid linkage with D3DX11 or D3DCompile libraries, // vertex and pixel shaders are compiled offline in a pre-build step using // the fxc.exe compiler (from the DirectX SDK Aug'09 or later) #ifdef _WIN64 # ifdef _DEBUG # include "debug64\TwDirect3D11_LineRectVS.h" # include "debug64\TwDirect3D11_LineRectCstColorVS.h" # include "debug64\TwDirect3D11_LineRectPS.h" # include "debug64\TwDirect3D11_TextVS.h" # include "debug64\TwDirect3D11_TextCstColorVS.h" # include "debug64\TwDirect3D11_TextPS.h" # else # include "release64\TwDirect3D11_LineRectVS.h" # include "release64\TwDirect3D11_LineRectCstColorVS.h" # include "release64\TwDirect3D11_LineRectPS.h" # include "release64\TwDirect3D11_TextVS.h" # include "release64\TwDirect3D11_TextCstColorVS.h" # include "release64\TwDirect3D11_TextPS.h" # endif #else # ifdef _DEBUG # include "debug32\TwDirect3D11_LineRectVS.h" # include "debug32\TwDirect3D11_LineRectCstColorVS.h" # include "debug32\TwDirect3D11_LineRectPS.h" # include "debug32\TwDirect3D11_TextVS.h" # include "debug32\TwDirect3D11_TextCstColorVS.h" # include "debug32\TwDirect3D11_TextPS.h" # else # include "release32\TwDirect3D11_LineRectVS.h" # include "release32\TwDirect3D11_LineRectCstColorVS.h" # include "release32\TwDirect3D11_LineRectPS.h" # include "release32\TwDirect3D11_TextVS.h" # include "release32\TwDirect3D11_TextCstColorVS.h" # include "release32\TwDirect3D11_TextPS.h" # endif #endif // --------------------------------------------------------------------------- const RECT FullRect = {0, 0, 16000, 16000}; static bool RectIsFull(const RECT& r) { return r.left==FullRect.left && r.right==FullRect.right && r.top==FullRect.top && r.bottom==FullRect.bottom; } // --------------------------------------------------------------------------- static void BindFont(ID3D11Device *_Dev, const CTexFont *_Font, ID3D11Texture2D **_Tex, ID3D11ShaderResourceView **_TexRV) { assert(_Font!=NULL); *_Tex = NULL; *_TexRV = NULL; int w = _Font->m_TexWidth; int h = _Font->m_TexHeight; color32 *font32 = new color32[w*h]; color32 *p = font32; for( int i=0; im_TexBytes[i]))<<24); D3D11_TEXTURE2D_DESC desc; desc.Width = w; desc.Height = h; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_IMMUTABLE; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; D3D11_SUBRESOURCE_DATA data; data.pSysMem = font32; data.SysMemPitch = w*sizeof(color32); data.SysMemSlicePitch = 0; if( SUCCEEDED(_Dev->CreateTexture2D(&desc, &data, _Tex)) ) _Dev->CreateShaderResourceView(*_Tex, NULL, _TexRV); delete[] font32; } // --------------------------------------------------------------------------- static void UnbindFont(ID3D11Device *_Dev, ID3D11Texture2D *_Tex, ID3D11ShaderResourceView *_TexRV) { (void)_Dev; if( _TexRV ) { ULONG rc = _TexRV->Release(); assert( rc==0 ); (void)rc; } if( _Tex ) { ULONG rc = _Tex->Release(); assert( rc==0 ); (void)rc; } } // --------------------------------------------------------------------------- struct CState11 { ID3D11ComputeShader * m_CSShader; ID3D11ClassInstance ** m_CSClassInstances; UINT m_CSNumClassInstances; ID3D11DomainShader * m_DSShader; ID3D11ClassInstance ** m_DSClassInstances; UINT m_DSNumClassInstances; ID3D11GeometryShader * m_GSShader; ID3D11ClassInstance ** m_GSClassInstances; UINT m_GSNumClassInstances; ID3D11HullShader * m_HSShader; ID3D11ClassInstance ** m_HSClassInstances; UINT m_HSNumClassInstances; ID3D11PixelShader * m_PSShader; ID3D11ClassInstance ** m_PSClassInstances; UINT m_PSNumClassInstances; ID3D11Buffer * m_PSConstantBuffer; // backup the first constant buffer only ID3D11SamplerState * m_PSSampler; // backup the first sampler only ID3D11ShaderResourceView*m_PSShaderResourceView; // backup the first shader resource only ID3D11VertexShader * m_VSShader; ID3D11ClassInstance ** m_VSClassInstances; UINT m_VSNumClassInstances; ID3D11Buffer * m_VSConstantBuffer; // backup the first constant buffer only ID3D11Buffer * m_IAIndexBuffer; DXGI_FORMAT m_IAIndexBufferFormat; UINT m_IAIndexBufferOffset; ID3D11InputLayout * m_IAInputLayout; D3D11_PRIMITIVE_TOPOLOGY m_IATopology; ID3D11Buffer * m_IAVertexBuffer; // backup the first buffer only UINT m_IAVertexBufferStride; UINT m_IAVertexBufferOffset; ID3D11BlendState * m_OMBlendState; FLOAT m_OMBlendFactor[4]; UINT m_OMSampleMask; ID3D11DepthStencilState*m_OMDepthStencilState; UINT m_OMStencilRef; UINT m_RSScissorNumRects; D3D11_RECT m_RSScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; ID3D11RasterizerState * m_RSRasterizerState; UINT m_RSNumViewports; D3D11_VIEWPORT m_RSViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; void Save(); void Restore(); void Release(); CState11(ID3D11Device *_Dev, ID3D11DeviceContext *_ImmCtx); ~CState11(); private: ID3D11Device * m_D3DDev; ID3D11DeviceContext * m_D3DDevImmContext; }; CState11::CState11(ID3D11Device *_Dev, ID3D11DeviceContext *_ImmCtx) { ZeroMemory(this, sizeof(CState11)); m_D3DDev = _Dev; m_D3DDevImmContext = _ImmCtx; } CState11::~CState11() { Release(); m_D3DDev = NULL; m_D3DDevImmContext = NULL; } void CState11::Save() { // Release previous state if needed Release(); // Save shaders. // Not sure how xxGetShader works, D3D11 doc is evasive... Attempt: // First call GetShader with NULL ClassInstances to get the number of class instances. // Second, if not zero allocate an array of class instances and call GetShader again // with this array ptr to get the class instances and release the shader since its // ref count has been incremented a second time. m_CSShader = NULL; m_CSClassInstances = NULL; m_CSNumClassInstances = 0; m_D3DDevImmContext->CSGetShader(&m_CSShader, NULL, &m_CSNumClassInstances); if (m_CSNumClassInstances > 0) { m_CSClassInstances = new ID3D11ClassInstance*[m_CSNumClassInstances]; for (UINT i = 0; i < m_CSNumClassInstances; i++) m_CSClassInstances[i] = NULL; m_D3DDevImmContext->CSGetShader(&m_CSShader, m_CSClassInstances, &m_CSNumClassInstances); if (m_CSShader != NULL) m_CSShader->Release(); } m_DSShader = NULL; m_DSClassInstances = NULL; m_DSNumClassInstances = 0; m_D3DDevImmContext->DSGetShader(&m_DSShader, NULL, &m_DSNumClassInstances); if (m_DSNumClassInstances > 0) { m_DSClassInstances = new ID3D11ClassInstance*[m_DSNumClassInstances]; for (UINT i = 0; i < m_DSNumClassInstances; i++) m_DSClassInstances[i] = NULL; m_D3DDevImmContext->DSGetShader(&m_DSShader, m_DSClassInstances, &m_DSNumClassInstances); if (m_DSShader != NULL) m_DSShader->Release(); } m_GSShader = NULL; m_GSClassInstances = NULL; m_GSNumClassInstances = 0; m_D3DDevImmContext->GSGetShader(&m_GSShader, NULL, &m_GSNumClassInstances); if (m_GSNumClassInstances > 0) { m_GSClassInstances = new ID3D11ClassInstance*[m_GSNumClassInstances]; for (UINT i = 0; i < m_GSNumClassInstances; i++) m_GSClassInstances[i] = NULL; m_D3DDevImmContext->GSGetShader(&m_GSShader, m_GSClassInstances, &m_GSNumClassInstances); if (m_GSShader != NULL) m_GSShader->Release(); } m_HSShader = NULL; m_HSClassInstances = NULL; m_HSNumClassInstances = 0; m_D3DDevImmContext->HSGetShader(&m_HSShader, NULL, &m_HSNumClassInstances); if (m_HSNumClassInstances > 0) { m_HSClassInstances = new ID3D11ClassInstance*[m_HSNumClassInstances]; for (UINT i = 0; i < m_HSNumClassInstances; i++) m_HSClassInstances[i] = NULL; m_D3DDevImmContext->HSGetShader(&m_HSShader, m_HSClassInstances, &m_HSNumClassInstances); if (m_HSShader != NULL) m_HSShader->Release(); } m_PSShader = NULL; m_PSClassInstances = NULL; m_PSNumClassInstances = 0; m_D3DDevImmContext->PSGetShader(&m_PSShader, NULL, &m_PSNumClassInstances); if (m_PSNumClassInstances > 0) { m_PSClassInstances = new ID3D11ClassInstance*[m_PSNumClassInstances]; for (UINT i = 0; i < m_PSNumClassInstances; i++) m_PSClassInstances[i] = NULL; m_D3DDevImmContext->PSGetShader(&m_PSShader, m_PSClassInstances, &m_PSNumClassInstances); if (m_PSShader != NULL) m_PSShader->Release(); } m_D3DDevImmContext->PSGetConstantBuffers(0, 1, &m_PSConstantBuffer); m_D3DDevImmContext->PSGetSamplers(0, 1, &m_PSSampler); m_D3DDevImmContext->PSGetShaderResources(0, 1, &m_PSShaderResourceView); m_VSShader = NULL; m_VSClassInstances = NULL; m_VSNumClassInstances = 0; m_D3DDevImmContext->VSGetShader(&m_VSShader, NULL, &m_VSNumClassInstances); if (m_VSNumClassInstances > 0) { m_VSClassInstances = new ID3D11ClassInstance*[m_VSNumClassInstances]; for (UINT i = 0; i < m_VSNumClassInstances; i++) m_VSClassInstances[i] = NULL; m_D3DDevImmContext->VSGetShader(&m_VSShader, m_VSClassInstances, &m_VSNumClassInstances); if (m_VSShader != NULL) m_VSShader->Release(); } m_D3DDevImmContext->VSGetConstantBuffers(0, 1, &m_VSConstantBuffer); // Save Input-Assembler states m_D3DDevImmContext->IAGetIndexBuffer(&m_IAIndexBuffer, &m_IAIndexBufferFormat, &m_IAIndexBufferOffset); m_D3DDevImmContext->IAGetInputLayout(&m_IAInputLayout); m_D3DDevImmContext->IAGetPrimitiveTopology(&m_IATopology); m_D3DDevImmContext->IAGetVertexBuffers(0, 1, &m_IAVertexBuffer, &m_IAVertexBufferStride, &m_IAVertexBufferOffset); // Save Ouput-Merger states m_D3DDevImmContext->OMGetBlendState(&m_OMBlendState, m_OMBlendFactor, &m_OMSampleMask); m_D3DDevImmContext->OMGetDepthStencilState(&m_OMDepthStencilState, &m_OMStencilRef); // Save Rasterizer states m_D3DDevImmContext->RSGetScissorRects(&m_RSScissorNumRects, NULL); if (m_RSScissorNumRects > 0) m_D3DDevImmContext->RSGetScissorRects(&m_RSScissorNumRects, m_RSScissorRects); m_D3DDevImmContext->RSGetViewports(&m_RSNumViewports, NULL); if (m_RSNumViewports > 0) m_D3DDevImmContext->RSGetViewports(&m_RSNumViewports, m_RSViewports); m_D3DDevImmContext->RSGetState(&m_RSRasterizerState); } void CState11::Restore() { // Restore shaders m_D3DDevImmContext->CSSetShader(m_CSShader, m_CSClassInstances, m_CSNumClassInstances); m_D3DDevImmContext->DSSetShader(m_DSShader, m_DSClassInstances, m_DSNumClassInstances); m_D3DDevImmContext->GSSetShader(m_GSShader, m_GSClassInstances, m_GSNumClassInstances); m_D3DDevImmContext->HSSetShader(m_HSShader, m_HSClassInstances, m_HSNumClassInstances); m_D3DDevImmContext->PSSetShader(m_PSShader, m_PSClassInstances, m_PSNumClassInstances); m_D3DDevImmContext->PSSetConstantBuffers(0, 1, &m_PSConstantBuffer); m_D3DDevImmContext->PSSetSamplers(0, 1, &m_PSSampler); m_D3DDevImmContext->PSSetShaderResources(0, 1, &m_PSShaderResourceView); m_D3DDevImmContext->VSSetShader(m_VSShader, m_VSClassInstances, m_VSNumClassInstances); m_D3DDevImmContext->VSSetConstantBuffers(0, 1, &m_VSConstantBuffer); // Restore Input-Assembler m_D3DDevImmContext->IASetIndexBuffer(m_IAIndexBuffer, m_IAIndexBufferFormat, m_IAIndexBufferOffset); m_D3DDevImmContext->IASetInputLayout(m_IAInputLayout); m_D3DDevImmContext->IASetPrimitiveTopology(m_IATopology); m_D3DDevImmContext->IASetVertexBuffers(0, 1, &m_IAVertexBuffer, &m_IAVertexBufferStride, &m_IAVertexBufferOffset); // Restore Ouput-Merger m_D3DDevImmContext->OMSetBlendState(m_OMBlendState, m_OMBlendFactor, m_OMSampleMask); m_D3DDevImmContext->OMSetDepthStencilState(m_OMDepthStencilState, m_OMStencilRef); // Restore Rasterizer states m_D3DDevImmContext->RSSetScissorRects(m_RSScissorNumRects, m_RSScissorRects); m_D3DDevImmContext->RSSetViewports(m_RSNumViewports, m_RSViewports); m_D3DDevImmContext->RSSetState(m_RSRasterizerState); } void CState11::Release() { // Release stored shaders if (m_CSClassInstances != NULL) { for (UINT i = 0; i < m_CSNumClassInstances; i++) if (m_CSClassInstances[i] != NULL) m_CSClassInstances[i]->Release(); delete[] m_CSClassInstances; m_CSClassInstances = NULL; m_CSNumClassInstances = 0; } if (m_CSShader != NULL) { m_CSShader->Release(); m_CSShader = NULL; } if (m_DSClassInstances != NULL) { for (UINT i = 0; i < m_DSNumClassInstances; i++) if (m_DSClassInstances[i] != NULL) m_DSClassInstances[i]->Release(); delete[] m_DSClassInstances; m_DSClassInstances = NULL; m_DSNumClassInstances = 0; } if (m_DSShader != NULL) { m_DSShader->Release(); m_DSShader = NULL; } if (m_GSClassInstances != NULL) { for (UINT i = 0; i < m_GSNumClassInstances; i++) if (m_GSClassInstances[i] != NULL) m_GSClassInstances[i]->Release(); delete[] m_GSClassInstances; m_GSClassInstances = NULL; m_GSNumClassInstances = 0; } if (m_GSShader != NULL) { m_GSShader->Release(); m_GSShader = NULL; } if (m_HSClassInstances != NULL) { for (UINT i = 0; i < m_HSNumClassInstances; i++) if (m_HSClassInstances[i] != NULL) m_HSClassInstances[i]->Release(); delete[] m_HSClassInstances; m_HSClassInstances = NULL; m_HSNumClassInstances = 0; } if (m_HSShader != NULL) { m_HSShader->Release(); m_HSShader = NULL; } if (m_PSClassInstances != NULL) { for (UINT i = 0; i < m_PSNumClassInstances; i++) if (m_PSClassInstances[i] != NULL) m_PSClassInstances[i]->Release(); delete[] m_PSClassInstances; m_PSClassInstances = NULL; m_PSNumClassInstances = 0; } if (m_PSShader != NULL) { m_PSShader->Release(); m_PSShader = NULL; } if (m_PSConstantBuffer != NULL) { m_PSConstantBuffer->Release(); m_PSConstantBuffer = NULL; } if (m_PSSampler != NULL) { m_PSSampler->Release(); m_PSSampler = NULL; } if (m_PSShaderResourceView != NULL) { m_PSShaderResourceView->Release(); m_PSShaderResourceView = NULL; } if (m_VSClassInstances != NULL) { for (UINT i = 0; i < m_VSNumClassInstances; i++) if (m_VSClassInstances[i] != NULL) m_VSClassInstances[i]->Release(); delete[] m_VSClassInstances; m_VSClassInstances = NULL; m_VSNumClassInstances = 0; } if (m_VSShader != NULL) { m_VSShader->Release(); m_VSShader = NULL; } if (m_VSConstantBuffer != NULL) { m_VSConstantBuffer->Release(); m_VSConstantBuffer = NULL; } // Release Input-Assembler states if (m_IAIndexBuffer != NULL) { m_IAIndexBuffer->Release(); m_IAIndexBuffer = NULL; } if (m_IAInputLayout != NULL) { m_IAInputLayout->Release(); m_IAInputLayout = 0; } if (m_IAVertexBuffer != NULL) { m_IAVertexBuffer->Release(); m_IAVertexBuffer = NULL; } // Release Output-Merger states if (m_OMBlendState != NULL) { m_OMBlendState->Release(); m_OMBlendState = NULL; } if (m_OMDepthStencilState != NULL) { m_OMDepthStencilState->Release(); m_OMDepthStencilState = NULL; } // Release Rasterizer state if (m_RSRasterizerState != 0) { m_RSRasterizerState->Release(); m_RSRasterizerState = NULL; } m_RSNumViewports = 0; m_RSScissorNumRects = 0; } // --------------------------------------------------------------------------- int CTwGraphDirect3D11::Init() { assert(g_TwMgr!=NULL); assert(g_TwMgr->m_Device!=NULL); m_D3DDev = static_cast(g_TwMgr->m_Device); m_D3DDevInitialRefCount = m_D3DDev->AddRef() - 1; m_D3DDev->GetImmediateContext(&m_D3DDevImmContext); m_Drawing = false; m_OffsetX = m_OffsetY = 0; m_ViewportInit = new D3D11_VIEWPORT; m_FontTex = NULL; m_FontD3DTex = NULL; m_FontD3DTexRV = NULL; m_WndWidth = 0; m_WndHeight = 0; m_State = NULL; m_DepthStencilState = NULL; m_BlendState = NULL; m_RasterState = NULL; m_RasterStateAntialiased = NULL; m_RasterStateMultisample = NULL; m_RasterStateCullCW = NULL; m_RasterStateCullCCW = NULL; m_LineRectVS = NULL; m_LineRectCstColorVS = NULL; m_LineRectPS = NULL; m_LineRectVertexLayout = NULL; m_TextVS = NULL; m_TextCstColorVS = NULL; m_TextPS = NULL; m_TextVertexLayout = NULL; m_LineVertexBuffer = NULL; m_RectVertexBuffer = NULL; m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; m_ConstantBuffer = NULL; m_SamplerState = NULL; // Allocate state object m_State = new CState11(m_D3DDev, m_D3DDevImmContext); // Disable client shaders m_D3DDevImmContext->CSSetShader(NULL, NULL, 0); m_D3DDevImmContext->DSSetShader(NULL, NULL, 0); m_D3DDevImmContext->GSSetShader(NULL, NULL, 0); m_D3DDevImmContext->HSSetShader(NULL, NULL, 0); m_D3DDevImmContext->PSSetShader(NULL, NULL, 0); m_D3DDevImmContext->VSSetShader(NULL, NULL, 0); // Create shaders HRESULT hr = m_D3DDev->CreateVertexShader(g_LineRectVS, sizeof(g_LineRectVS), NULL, &m_LineRectVS); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateVS11); Shut(); return 0; } hr = m_D3DDev->CreateVertexShader(g_LineRectCstColorVS, sizeof(g_LineRectCstColorVS), NULL, &m_LineRectCstColorVS); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateVS11); Shut(); return 0; } hr = m_D3DDev->CreatePixelShader(g_LineRectPS, sizeof(g_LineRectPS), NULL, &m_LineRectPS); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreatePS11); Shut(); return 0; } hr = m_D3DDev->CreateVertexShader(g_TextVS, sizeof(g_TextVS), NULL, &m_TextVS); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateVS11); Shut(); return 0; } hr = m_D3DDev->CreateVertexShader(g_TextCstColorVS, sizeof(g_TextCstColorVS), NULL, &m_TextCstColorVS); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateVS11); Shut(); return 0; } hr = m_D3DDev->CreatePixelShader(g_TextPS, sizeof(g_TextPS), NULL, &m_TextPS); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreatePS11); Shut(); return 0; } // Create input layout for lines & rect D3D11_INPUT_ELEMENT_DESC lineRectLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(CLineRectVtx, m_Color), D3D11_INPUT_PER_VERTEX_DATA, 0 } }; hr = m_D3DDev->CreateInputLayout(lineRectLayout, sizeof(lineRectLayout)/sizeof(lineRectLayout[0]), g_LineRectVS, sizeof(g_LineRectVS), &m_LineRectVertexLayout); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateLayout11); Shut(); return 0; } // Create line vertex buffer D3D11_BUFFER_DESC bd; bd.Usage = D3D11_USAGE_DYNAMIC; bd.ByteWidth = 2 * sizeof(CLineRectVtx); bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; bd.StructureByteStride = 0; hr = m_D3DDev->CreateBuffer(&bd, NULL, &m_LineVertexBuffer); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateBuffer11); Shut(); return 0; } // Create rect vertex buffer bd.ByteWidth = 4 * sizeof(CLineRectVtx); hr = m_D3DDev->CreateBuffer(&bd, NULL, &m_RectVertexBuffer); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateBuffer11); Shut(); return 0; } // Create constant buffer bd.ByteWidth = sizeof(CConstants); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; hr = m_D3DDev->CreateBuffer(&bd, NULL, &m_ConstantBuffer); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateBuffer11); Shut(); return 0; } // Create sampler D3D11_SAMPLER_DESC sd; sd.AddressU = sd.AddressV = sd.AddressW = D3D11_TEXTURE_ADDRESS_BORDER; sd.BorderColor[0] = sd.BorderColor[1] = sd.BorderColor[2] = sd.BorderColor[3] = 0; sd.ComparisonFunc = D3D11_COMPARISON_NEVER; sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; sd.MaxAnisotropy = 1; sd.MaxLOD = sd.MinLOD = 0; sd.MipLODBias = 0; hr = m_D3DDev->CreateSamplerState(&sd, &m_SamplerState); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateSampler11); Shut(); return 0; } // Create input layout for text D3D11_INPUT_ELEMENT_DESC textLayout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(CTextVtx, m_Color), D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(CTextVtx, m_UV), D3D11_INPUT_PER_VERTEX_DATA, 0 } }; hr = m_D3DDev->CreateInputLayout(textLayout, sizeof(textLayout)/sizeof(textLayout[0]), g_TextVS, sizeof(g_TextVS), &m_TextVertexLayout); if( FAILED(hr) ) { g_TwMgr->SetLastError(g_ErrCreateLayout11); Shut(); return 0; } // Create depth stencil state object D3D11_DEPTH_STENCILOP_DESC od; od.StencilFunc = D3D11_COMPARISON_ALWAYS; od.StencilFailOp = D3D11_STENCIL_OP_KEEP; od.StencilPassOp = D3D11_STENCIL_OP_KEEP; od.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; D3D11_DEPTH_STENCIL_DESC dsd; dsd.DepthEnable = FALSE; dsd.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; dsd.DepthFunc = D3D11_COMPARISON_ALWAYS; dsd.StencilEnable = FALSE; dsd.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; dsd.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; dsd.FrontFace = od; dsd.BackFace = od; m_D3DDev->CreateDepthStencilState(&dsd, &m_DepthStencilState); // Create blend state object D3D11_BLEND_DESC bsd; bsd.AlphaToCoverageEnable = FALSE; bsd.IndependentBlendEnable = FALSE; for(int i=0; i<8; ++i) { bsd.RenderTarget[i].BlendEnable = TRUE; bsd.RenderTarget[i].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; bsd.RenderTarget[i].SrcBlend = D3D11_BLEND_SRC_ALPHA; bsd.RenderTarget[i].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; bsd.RenderTarget[i].BlendOp = D3D11_BLEND_OP_ADD; bsd.RenderTarget[i].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA; bsd.RenderTarget[i].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; bsd.RenderTarget[i].BlendOpAlpha = D3D11_BLEND_OP_ADD; } m_D3DDev->CreateBlendState(&bsd, &m_BlendState); // Create rasterizer state object D3D11_RASTERIZER_DESC rd; rd.FillMode = D3D11_FILL_SOLID; rd.CullMode = D3D11_CULL_NONE; rd.FrontCounterClockwise = true; rd.DepthBias = false; rd.DepthBiasClamp = 0; rd.SlopeScaledDepthBias = 0; rd.DepthClipEnable = false; rd.ScissorEnable = true; rd.MultisampleEnable = false; // do not allow msaa (fonts would be degraded) rd.AntialiasedLineEnable = false; m_D3DDev->CreateRasterizerState(&rd, &m_RasterState); rd.AntialiasedLineEnable = true; m_D3DDev->CreateRasterizerState(&rd, &m_RasterStateAntialiased); rd.AntialiasedLineEnable = false; // the three following raster states allow msaa rd.MultisampleEnable = true; m_D3DDev->CreateRasterizerState(&rd, &m_RasterStateMultisample); rd.CullMode = D3D11_CULL_BACK; m_D3DDev->CreateRasterizerState(&rd, &m_RasterStateCullCW); rd.CullMode = D3D11_CULL_FRONT; m_D3DDev->CreateRasterizerState(&rd, &m_RasterStateCullCCW); return 1; } // --------------------------------------------------------------------------- int CTwGraphDirect3D11::Shut() { assert(m_Drawing==false); UnbindFont(m_D3DDev, m_FontD3DTex, m_FontD3DTexRV); m_FontD3DTex = NULL; m_FontD3DTexRV = NULL; if( m_State ) { delete m_State; m_State = NULL; } if( m_ViewportInit ) { delete m_ViewportInit; m_ViewportInit = NULL; } if( m_DepthStencilState ) { ULONG rc = m_DepthStencilState->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_DepthStencilState = NULL; } if( m_BlendState ) { ULONG rc = m_BlendState->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_BlendState = NULL; } if( m_RasterState ) { ULONG rc = m_RasterState->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterState = NULL; } if( m_RasterStateAntialiased ) { ULONG rc = m_RasterStateAntialiased->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterStateAntialiased = NULL; } if( m_RasterStateMultisample ) { ULONG rc = m_RasterStateMultisample->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterStateMultisample = NULL; } if( m_RasterStateCullCW ) { ULONG rc = m_RasterStateCullCW->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterStateCullCW = NULL; } if( m_RasterStateCullCCW ) { ULONG rc = m_RasterStateCullCCW->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_RasterStateCullCCW = NULL; } if( m_SamplerState ) { ULONG rc = m_SamplerState->Release(); //assert( rc==0 ); // no assert: the client can use a similar (then shared) state (void)rc; m_SamplerState = NULL; } if( m_LineRectVS ) { ULONG rc = m_LineRectVS->Release(); assert( rc==0 ); (void)rc; m_LineRectVS = NULL; } if( m_LineRectCstColorVS ) { ULONG rc = m_LineRectCstColorVS->Release(); assert( rc==0 ); (void)rc; m_LineRectCstColorVS = NULL; } if( m_LineRectPS ) { ULONG rc = m_LineRectPS->Release(); assert( rc==0 ); (void)rc; m_LineRectPS = NULL; } if( m_TextVS ) { ULONG rc = m_TextVS->Release(); assert( rc==0 ); (void)rc; m_TextVS = NULL; } if( m_TextCstColorVS ) { ULONG rc = m_TextCstColorVS->Release(); assert( rc==0 ); (void)rc; m_TextCstColorVS = NULL; } if( m_TextPS ) { ULONG rc = m_TextPS->Release(); assert( rc==0 ); (void)rc; m_TextPS = NULL; } if( m_LineVertexBuffer ) { ULONG rc = m_LineVertexBuffer->Release(); assert( rc==0 ); (void)rc; m_LineVertexBuffer = NULL; } if( m_RectVertexBuffer ) { ULONG rc = m_RectVertexBuffer->Release(); assert( rc==0 ); (void)rc; m_RectVertexBuffer = NULL; } if( m_TrianglesVertexBuffer ) { ULONG rc = m_TrianglesVertexBuffer->Release(); assert( rc==0 ); (void)rc; m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; } if( m_ConstantBuffer ) { ULONG rc = m_ConstantBuffer->Release(); assert( rc==0 ); (void)rc; m_ConstantBuffer = NULL; } if( m_LineRectVertexLayout ) { ULONG rc = m_LineRectVertexLayout->Release(); assert( rc==0 ); (void)rc; m_LineRectVertexLayout = NULL; } if( m_TextVertexLayout ) { ULONG rc = m_TextVertexLayout->Release(); assert( rc==0 ); (void)rc; m_TextVertexLayout = NULL; } if( m_D3DDevImmContext ) { m_D3DDevImmContext->Release(); m_D3DDevImmContext = NULL; } if( m_D3DDev ) { //unsigned int rc = m_D3DDev->Release(); //assert( m_D3DDevInitialRefCount==rc ); (void)rc; m_D3DDev->Release(); m_D3DDev = NULL; } return 1; } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::BeginDraw(int _WndWidth, int _WndHeight) { assert(m_Drawing==false && _WndWidth>0 && _WndHeight>0); m_Drawing = true; m_WndWidth = _WndWidth; m_WndHeight = _WndHeight; m_OffsetX = m_OffsetY = 0; // save client context state m_State->Save(); // Setup the viewport D3D11_VIEWPORT vp; vp.Width = (FLOAT)_WndWidth; vp.Height = (FLOAT)_WndHeight; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; m_D3DDevImmContext->RSSetViewports(1, &vp); *static_cast(m_ViewportInit) = vp; m_ViewportAndScissorRects[0] = FullRect; m_ViewportAndScissorRects[1] = FullRect; m_D3DDevImmContext->RSSetScissorRects(1, m_ViewportAndScissorRects); m_D3DDevImmContext->RSSetState(m_RasterState); m_D3DDevImmContext->OMSetDepthStencilState(m_DepthStencilState, 0); float blendFactors[4] = { 1, 1, 1, 1 }; m_D3DDevImmContext->OMSetBlendState(m_BlendState, blendFactors, 0xffffffff); m_D3DDevImmContext->CSSetShader(NULL, NULL, 0); m_D3DDevImmContext->DSSetShader(NULL, NULL, 0); m_D3DDevImmContext->GSSetShader(NULL, NULL, 0); m_D3DDevImmContext->HSSetShader(NULL, NULL, 0); } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::EndDraw() { m_D3DDevImmContext->RSSetState(NULL); m_D3DDevImmContext->OMSetDepthStencilState(NULL, 0); m_D3DDevImmContext->OMSetBlendState(NULL, NULL, 0xffffffff); assert(m_Drawing==true); m_Drawing = false; // restore and release client context state m_State->Restore(); m_State->Release(); } // --------------------------------------------------------------------------- bool CTwGraphDirect3D11::IsDrawing() { return m_Drawing; } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::Restore() { if( m_State ) m_State->Release(); UnbindFont(m_D3DDev, m_FontD3DTex, m_FontD3DTexRV); m_FontD3DTexRV = NULL; m_FontD3DTex = NULL; m_FontTex = NULL; } // --------------------------------------------------------------------------- static inline float ToNormScreenX(int x, int wndWidth) { return 2.0f*((float)x-0.5f)/wndWidth - 1.0f; } static inline float ToNormScreenY(int y, int wndHeight) { return 1.0f - 2.0f*((float)y-0.5f)/wndHeight; } static inline color32 ToR8G8B8A8(color32 col) { return (col & 0xff00ff00) | ((col>>16) & 0xff) | ((col<<16) & 0xff0000); } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased) { assert(m_Drawing==true); float x0 = ToNormScreenX(_X0 + m_OffsetX, m_WndWidth); float y0 = ToNormScreenY(_Y0 + m_OffsetY, m_WndHeight); float x1 = ToNormScreenX(_X1 + m_OffsetX, m_WndWidth); float y1 = ToNormScreenY(_Y1 + m_OffsetY, m_WndHeight); D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT hr = m_D3DDevImmContext->Map(m_LineVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CLineRectVtx *vertices = (CLineRectVtx *)mappedResource.pData; // Fill vertex buffer vertices[0].m_Pos[0] = x0; vertices[0].m_Pos[1] = y0; vertices[0].m_Pos[2] = 0; vertices[0].m_Color = ToR8G8B8A8(_Color0); vertices[1].m_Pos[0] = x1; vertices[1].m_Pos[1] = y1; vertices[1].m_Pos[2] = 0; vertices[1].m_Color = ToR8G8B8A8(_Color1); m_D3DDevImmContext->Unmap(m_LineVertexBuffer, 0); if( _AntiAliased ) m_D3DDevImmContext->RSSetState(m_RasterStateAntialiased); // Reset shader constants hr = m_D3DDevImmContext->Map(m_ConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CConstants *constants = (CConstants *)mappedResource.pData; constants->m_Offset[0] = 0; constants->m_Offset[1] = 0; constants->m_Offset[2] = 0; constants->m_Offset[3] = 0; constants->m_CstColor[0] = 1; constants->m_CstColor[1] = 1; constants->m_CstColor[2] = 1; constants->m_CstColor[3] = 1; m_D3DDevImmContext->Unmap(m_ConstantBuffer, 0); } // Set the input layout m_D3DDevImmContext->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDevImmContext->IASetVertexBuffers(0, 1, &m_LineVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDevImmContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); // Render the line m_D3DDevImmContext->VSSetConstantBuffers(0, 1, &m_ConstantBuffer); m_D3DDevImmContext->VSSetShader(m_LineRectVS, NULL, 0); m_D3DDevImmContext->PSSetShader(m_LineRectPS, NULL, 0); m_D3DDevImmContext->Draw(2, 0); if( _AntiAliased ) m_D3DDevImmContext->RSSetState(m_RasterState); // restore default raster state } } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11) { assert(m_Drawing==true); // border adjustment if(_X0<_X1) ++_X1; else if(_X0>_X1) ++_X0; if(_Y0<_Y1) ++_Y1; else if(_Y0>_Y1) ++_Y0; float x0 = ToNormScreenX(_X0 + m_OffsetX, m_WndWidth); float y0 = ToNormScreenY(_Y0 + m_OffsetY, m_WndHeight); float x1 = ToNormScreenX(_X1 + m_OffsetX, m_WndWidth); float y1 = ToNormScreenY(_Y1 + m_OffsetY, m_WndHeight); D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT hr = m_D3DDevImmContext->Map(m_RectVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CLineRectVtx *vertices = (CLineRectVtx *)mappedResource.pData; // Fill vertex buffer vertices[0].m_Pos[0] = x0; vertices[0].m_Pos[1] = y0; vertices[0].m_Pos[2] = 0; vertices[0].m_Color = ToR8G8B8A8(_Color00); vertices[1].m_Pos[0] = x1; vertices[1].m_Pos[1] = y0; vertices[1].m_Pos[2] = 0; vertices[1].m_Color = ToR8G8B8A8(_Color10); vertices[2].m_Pos[0] = x0; vertices[2].m_Pos[1] = y1; vertices[2].m_Pos[2] = 0; vertices[2].m_Color = ToR8G8B8A8(_Color01); vertices[3].m_Pos[0] = x1; vertices[3].m_Pos[1] = y1; vertices[3].m_Pos[2] = 0; vertices[3].m_Color = ToR8G8B8A8(_Color11); m_D3DDevImmContext->Unmap(m_RectVertexBuffer, 0); // Reset shader constants hr = m_D3DDevImmContext->Map(m_ConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CConstants *constants = (CConstants *)mappedResource.pData; constants->m_Offset[0] = 0; constants->m_Offset[1] = 0; constants->m_Offset[2] = 0; constants->m_Offset[3] = 0; constants->m_CstColor[0] = 1; constants->m_CstColor[1] = 1; constants->m_CstColor[2] = 1; constants->m_CstColor[3] = 1; m_D3DDevImmContext->Unmap(m_ConstantBuffer, 0); } // Set the input layout m_D3DDevImmContext->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDevImmContext->IASetVertexBuffers(0, 1, &m_RectVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDevImmContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); // Render the rect m_D3DDevImmContext->VSSetConstantBuffers(0, 1, &m_ConstantBuffer); m_D3DDevImmContext->VSSetShader(m_LineRectVS, NULL, 0); m_D3DDevImmContext->PSSetShader(m_LineRectPS, NULL, 0); m_D3DDevImmContext->Draw(4, 0); } } // --------------------------------------------------------------------------- void *CTwGraphDirect3D11::NewTextObj() { CTextObj *textObj = new CTextObj; memset(textObj, 0, sizeof(CTextObj)); return textObj; } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::DeleteTextObj(void *_TextObj) { assert(_TextObj!=NULL); CTextObj *textObj = static_cast(_TextObj); if( textObj->m_TextVertexBuffer ) textObj->m_TextVertexBuffer->Release(); if( textObj->m_BgVertexBuffer ) textObj->m_BgVertexBuffer->Release(); memset(textObj, 0, sizeof(CTextObj)); delete textObj; } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth) { assert(m_Drawing==true); assert(_TextObj!=NULL); assert(_Font!=NULL); if( _Font != m_FontTex ) { UnbindFont(m_D3DDev, m_FontD3DTex, m_FontD3DTexRV); BindFont(m_D3DDev, _Font, &m_FontD3DTex, &m_FontD3DTexRV); m_FontTex = _Font; } int nbTextVerts = 0; int line; for( line=0; line<_NbLines; ++line ) nbTextVerts += 6 * (int)_TextLines[line].length(); int nbBgVerts = 0; if( _BgWidth>0 ) nbBgVerts = _NbLines*6; CTextObj *textObj = static_cast(_TextObj); textObj->m_LineColors = (_LineColors!=NULL); textObj->m_LineBgColors = (_LineBgColors!=NULL); // (re)create text vertex buffer if needed, and map it CTextVtx *textVerts = NULL; if( nbTextVerts>0 ) { if( textObj->m_TextVertexBuffer==NULL || textObj->m_TextVertexBufferSizem_TextVertexBuffer!=NULL ) { ULONG rc = textObj->m_TextVertexBuffer->Release(); assert( rc==0 ); (void)rc; textObj->m_TextVertexBuffer = NULL; } textObj->m_TextVertexBufferSize = nbTextVerts + 6*256; // add a reserve of 256 characters D3D11_BUFFER_DESC bd; bd.Usage = D3D11_USAGE_DYNAMIC; bd.ByteWidth = textObj->m_TextVertexBufferSize * sizeof(CTextVtx); bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; bd.StructureByteStride = 0; m_D3DDev->CreateBuffer(&bd, NULL, &textObj->m_TextVertexBuffer); } if( textObj->m_TextVertexBuffer!=NULL ) { D3D11_MAPPED_SUBRESOURCE mappedResource; m_D3DDevImmContext->Map(textObj->m_TextVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); textVerts = (CTextVtx *)mappedResource.pData; } } // (re)create bg vertex buffer if needed, and map it CLineRectVtx *bgVerts = NULL; if( nbBgVerts>0 ) { if( textObj->m_BgVertexBuffer==NULL || textObj->m_BgVertexBufferSizem_BgVertexBuffer!=NULL ) { ULONG rc = textObj->m_BgVertexBuffer->Release(); assert( rc==0 ); (void)rc; textObj->m_BgVertexBuffer = NULL; } textObj->m_BgVertexBufferSize = nbBgVerts + 6*32; // add a reserve of 32 rects D3D11_BUFFER_DESC bd; bd.Usage = D3D11_USAGE_DYNAMIC; bd.ByteWidth = textObj->m_BgVertexBufferSize * sizeof(CLineRectVtx); bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; bd.StructureByteStride = 0; m_D3DDev->CreateBuffer(&bd, NULL, &textObj->m_BgVertexBuffer); } if( textObj->m_BgVertexBuffer!=NULL ) { D3D11_MAPPED_SUBRESOURCE mappedResource; m_D3DDevImmContext->Map(textObj->m_BgVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); bgVerts = (CLineRectVtx *)mappedResource.pData; } } int x, x1, y, y1, i, len; float px, px1, py, py1; unsigned char ch; const unsigned char *text; color32 lineColor = COLOR32_RED; CTextVtx vtx; vtx.m_Pos[2] = 0; CLineRectVtx bgVtx; bgVtx.m_Pos[2] = 0; int textVtxIndex = 0; int bgVtxIndex = 0; for( line=0; line<_NbLines; ++line ) { x = 0; y = line * (_Font->m_CharHeight+_Sep); y1 = y+_Font->m_CharHeight; len = (int)_TextLines[line].length(); text = (const unsigned char *)(_TextLines[line].c_str()); if( _LineColors!=NULL ) lineColor = ToR8G8B8A8(_LineColors[line]); if( textVerts!=NULL ) for( i=0; im_CharWidth[ch]; px = ToNormScreenX(x, m_WndWidth); py = ToNormScreenY(y, m_WndHeight); px1 = ToNormScreenX(x1, m_WndWidth); py1 = ToNormScreenY(y1, m_WndHeight); vtx.m_Color = lineColor; vtx.m_Pos[0] = px; vtx.m_Pos[1] = py; vtx.m_UV [0] = _Font->m_CharU0[ch]; vtx.m_UV [1] = _Font->m_CharV0[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px1; vtx.m_Pos[1] = py; vtx.m_UV [0] = _Font->m_CharU1[ch]; vtx.m_UV [1] = _Font->m_CharV0[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px; vtx.m_Pos[1] = py1; vtx.m_UV [0] = _Font->m_CharU0[ch]; vtx.m_UV [1] = _Font->m_CharV1[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px1; vtx.m_Pos[1] = py; vtx.m_UV [0] = _Font->m_CharU1[ch]; vtx.m_UV [1] = _Font->m_CharV0[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px1; vtx.m_Pos[1] = py1; vtx.m_UV [0] = _Font->m_CharU1[ch]; vtx.m_UV [1] = _Font->m_CharV1[ch]; textVerts[textVtxIndex++] = vtx; vtx.m_Pos[0] = px; vtx.m_Pos[1] = py1; vtx.m_UV [0] = _Font->m_CharU0[ch]; vtx.m_UV [1] = _Font->m_CharV1[ch]; textVerts[textVtxIndex++] = vtx; x = x1; } if( _BgWidth>0 && bgVerts!=NULL ) { if( _LineBgColors!=NULL ) bgVtx.m_Color = ToR8G8B8A8(_LineBgColors[line]); else bgVtx.m_Color = ToR8G8B8A8(COLOR32_BLACK); px = ToNormScreenX(-1, m_WndWidth); py = ToNormScreenY(y, m_WndHeight); px1 = ToNormScreenX(_BgWidth+1, m_WndWidth); py1 = ToNormScreenY(y1, m_WndHeight); bgVtx.m_Pos[0] = px; bgVtx.m_Pos[1] = py; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px1; bgVtx.m_Pos[1] = py; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px; bgVtx.m_Pos[1] = py1; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px1; bgVtx.m_Pos[1] = py; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px1; bgVtx.m_Pos[1] = py1; bgVerts[bgVtxIndex++] = bgVtx; bgVtx.m_Pos[0] = px; bgVtx.m_Pos[1] = py1; bgVerts[bgVtxIndex++] = bgVtx; } } assert( textVtxIndex==nbTextVerts ); assert( bgVtxIndex==nbBgVerts ); textObj->m_NbTextVerts = nbTextVerts; textObj->m_NbBgVerts = nbBgVerts; if( textVerts!=NULL ) m_D3DDevImmContext->Unmap(textObj->m_TextVertexBuffer, 0); if( bgVerts!=NULL ) m_D3DDevImmContext->Unmap(textObj->m_BgVertexBuffer, 0); } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor) { assert(m_Drawing==true); assert(_TextObj!=NULL); CTextObj *textObj = static_cast(_TextObj); float dx = 2.0f*(float)(_X + m_OffsetX)/m_WndWidth; float dy = -2.0f*(float)(_Y + m_OffsetY)/m_WndHeight; // Draw background if( textObj->m_NbBgVerts>=4 && textObj->m_BgVertexBuffer!=NULL ) { // Set offset and constant color D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT hr = m_D3DDevImmContext->Map(m_ConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CConstants *constants = (CConstants *)mappedResource.pData; constants->m_Offset[0] = dx; constants->m_Offset[1] = dy; constants->m_Offset[2] = 0; constants->m_Offset[3] = 0; Color32ToARGBf(_BgColor, constants->m_CstColor+3, constants->m_CstColor+0, constants->m_CstColor+1, constants->m_CstColor+2); m_D3DDevImmContext->Unmap(m_ConstantBuffer, 0); } // Set the input layout m_D3DDevImmContext->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDevImmContext->IASetVertexBuffers(0, 1, &textObj->m_BgVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDevImmContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // Render the bg rectangles m_D3DDevImmContext->VSSetConstantBuffers(0, 1, &m_ConstantBuffer); if( _BgColor!=0 || !textObj->m_LineBgColors ) // use a constant bg color m_D3DDevImmContext->VSSetShader(m_LineRectCstColorVS, NULL, 0); else m_D3DDevImmContext->VSSetShader(m_LineRectVS, NULL, 0); m_D3DDevImmContext->PSSetSamplers(0, 1, &m_SamplerState); m_D3DDevImmContext->PSSetShader(m_LineRectPS, NULL, 0); m_D3DDevImmContext->Draw(textObj->m_NbBgVerts, 0); } // Draw text if( textObj->m_NbTextVerts>=4 && textObj->m_TextVertexBuffer!=NULL ) { // Set offset and constant color D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT hr = m_D3DDevImmContext->Map(m_ConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CConstants *constants = (CConstants *)mappedResource.pData; constants->m_Offset[0] = dx; constants->m_Offset[1] = dy; constants->m_Offset[2] = 0; constants->m_Offset[3] = 0; Color32ToARGBf(_Color, constants->m_CstColor+3, constants->m_CstColor+0, constants->m_CstColor+1, constants->m_CstColor+2); m_D3DDevImmContext->Unmap(m_ConstantBuffer, 0); } // Set the input layout m_D3DDevImmContext->IASetInputLayout(m_TextVertexLayout); // Set vertex buffer UINT stride = sizeof(CTextVtx); UINT offset = 0; m_D3DDevImmContext->IASetVertexBuffers(0, 1, &textObj->m_TextVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDevImmContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // Render the text m_D3DDevImmContext->VSSetConstantBuffers(0, 1, &m_ConstantBuffer); if( _Color!=0 || !textObj->m_LineColors ) // use a constant color m_D3DDevImmContext->VSSetShader(m_TextCstColorVS, NULL, 0); else m_D3DDevImmContext->VSSetShader(m_TextVS, NULL, 0); m_D3DDevImmContext->PSSetShaderResources(0, 1, &m_FontD3DTexRV); m_D3DDevImmContext->PSSetSamplers(0, 1, &m_SamplerState); m_D3DDevImmContext->PSSetShader(m_TextPS, NULL, 0); m_D3DDevImmContext->Draw(textObj->m_NbTextVerts, 0); } } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY) { if( _Width>0 && _Height>0 ) { /* viewport changes screen coordinates, use scissor instead D3D11_VIEWPORT vp; vp.TopLeftX = _X0; vp.TopLeftY = _Y0; vp.Width = _Width; vp.Height = _Height; vp.MinDepth = 0; vp.MaxDepth = 1; m_D3DDev->RSSetViewports(1, &vp); */ m_ViewportAndScissorRects[0].left = _X0; m_ViewportAndScissorRects[0].right = _X0 + _Width - 1; m_ViewportAndScissorRects[0].top = _Y0; m_ViewportAndScissorRects[0].bottom = _Y0 + _Height - 1; if( RectIsFull(m_ViewportAndScissorRects[1]) ) m_D3DDevImmContext->RSSetScissorRects(1, m_ViewportAndScissorRects); // viewport clipping only else m_D3DDevImmContext->RSSetScissorRects(2, m_ViewportAndScissorRects); m_OffsetX = _X0 + _OffsetX; m_OffsetY = _Y0 + _OffsetY; } } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::RestoreViewport() { //m_D3DDevImmContext->RSSetViewports(1, static_cast(m_ViewportInit)); m_ViewportAndScissorRects[0] = FullRect; m_D3DDevImmContext->RSSetScissorRects(1, m_ViewportAndScissorRects+1); // scissor only m_OffsetX = m_OffsetY = 0; } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::SetScissor(int _X0, int _Y0, int _Width, int _Height) { if( _Width>0 && _Height>0 ) { m_ViewportAndScissorRects[1].left = _X0 - 2; m_ViewportAndScissorRects[1].right = _X0 + _Width - 3; m_ViewportAndScissorRects[1].top = _Y0 - 1; m_ViewportAndScissorRects[1].bottom = _Y0 + _Height - 1; if( RectIsFull(m_ViewportAndScissorRects[0]) ) m_D3DDevImmContext->RSSetScissorRects(1, m_ViewportAndScissorRects+1); // no viewport clipping else m_D3DDevImmContext->RSSetScissorRects(2, m_ViewportAndScissorRects); } else { m_ViewportAndScissorRects[1] = FullRect; m_D3DDevImmContext->RSSetScissorRects(1, m_ViewportAndScissorRects); // apply viewport clipping only } } // --------------------------------------------------------------------------- void CTwGraphDirect3D11::DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode) { assert(m_Drawing==true); if( _NumTriangles<=0 ) return; if( m_TrianglesVertexBufferCount<3*_NumTriangles ) // force re-creation { if( m_TrianglesVertexBuffer!=NULL ) m_TrianglesVertexBuffer->Release(); m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; } // DrawTriangles uses LineRect layout and shaders if( m_TrianglesVertexBuffer==NULL ) { // Create triangles vertex buffer D3D11_BUFFER_DESC bd; bd.Usage = D3D11_USAGE_DYNAMIC; bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bd.MiscFlags = 0; bd.ByteWidth = 3*_NumTriangles * sizeof(CLineRectVtx); bd.StructureByteStride = 0; HRESULT hr = m_D3DDev->CreateBuffer(&bd, NULL, &m_TrianglesVertexBuffer); if( SUCCEEDED(hr) ) m_TrianglesVertexBufferCount = 3*_NumTriangles; else { m_TrianglesVertexBuffer = NULL; m_TrianglesVertexBufferCount = 0; return; // Problem: cannot create triangles VB } } assert( m_TrianglesVertexBufferCount>=3*_NumTriangles ); assert( m_TrianglesVertexBuffer!=NULL ); D3D11_MAPPED_SUBRESOURCE mappedResource; HRESULT hr = m_D3DDevImmContext->Map(m_TrianglesVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CLineRectVtx *vertices = (CLineRectVtx *)mappedResource.pData; // Fill vertex buffer for( int i=0; i<3*_NumTriangles; ++ i ) { vertices[i].m_Pos[0] = ToNormScreenX(_Vertices[2*i+0] + m_OffsetX, m_WndWidth); vertices[i].m_Pos[1] = ToNormScreenY(_Vertices[2*i+1] + m_OffsetY, m_WndHeight); vertices[i].m_Pos[2] = 0; vertices[i].m_Color = ToR8G8B8A8(_Colors[i]); } m_D3DDevImmContext->Unmap(m_TrianglesVertexBuffer, 0); // Reset shader constants hr = m_D3DDevImmContext->Map(m_ConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); if( SUCCEEDED(hr) ) { CConstants *constants = (CConstants *)mappedResource.pData; constants->m_Offset[0] = 0; constants->m_Offset[1] = 0; constants->m_Offset[2] = 0; constants->m_Offset[3] = 0; constants->m_CstColor[0] = 1; constants->m_CstColor[1] = 1; constants->m_CstColor[2] = 1; constants->m_CstColor[3] = 1; m_D3DDevImmContext->Unmap(m_ConstantBuffer, 0); } // Set the input layout m_D3DDevImmContext->IASetInputLayout(m_LineRectVertexLayout); // Set vertex buffer UINT stride = sizeof(CLineRectVtx); UINT offset = 0; m_D3DDevImmContext->IASetVertexBuffers(0, 1, &m_TrianglesVertexBuffer, &stride, &offset); // Set primitive topology m_D3DDevImmContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); if( _CullMode==CULL_CW ) m_D3DDevImmContext->RSSetState(m_RasterStateCullCW); else if( _CullMode==CULL_CCW ) m_D3DDevImmContext->RSSetState(m_RasterStateCullCCW); else m_D3DDevImmContext->RSSetState(m_RasterStateMultisample); // Render the triangles m_D3DDevImmContext->VSSetConstantBuffers(0, 1, &m_ConstantBuffer); m_D3DDevImmContext->VSSetShader(m_LineRectVS, NULL, 0); m_D3DDevImmContext->PSSetShader(m_LineRectPS, NULL, 0); m_D3DDevImmContext->Draw(3*_NumTriangles, 0); m_D3DDevImmContext->RSSetState(m_RasterState); // restore default raster state } } // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwDirect3D11.h0000644000000000000000000001214312635011627024777 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwDirect3D11.h // @brief Direct3D11 graphic functions // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_DIRECT3D11_INCLUDED #define ANT_TW_DIRECT3D11_INCLUDED #include "TwGraph.h" // --------------------------------------------------------------------------- class CTwGraphDirect3D11 : public ITwGraph { public: virtual int Init(); virtual int Shut(); virtual void BeginDraw(int _WndWidth, int _WndHeight); virtual void EndDraw(); virtual bool IsDrawing(); virtual void Restore(); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased=false); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color, bool _AntiAliased=false) { DrawLine(_X0, _Y0, _X1, _Y1, _Color, _Color, _AntiAliased); } virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11); virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color) { DrawRect(_X0, _Y0, _X1, _Y1, _Color, _Color, _Color, _Color); } virtual void DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode); virtual void * NewTextObj(); virtual void DeleteTextObj(void *_TextObj); virtual void BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth); virtual void DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor); virtual void ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY); virtual void RestoreViewport(); virtual void SetScissor(int _X0, int _Y0, int _Width, int _Height); protected: struct ID3D11Device * m_D3DDev; struct ID3D11DeviceContext *m_D3DDevImmContext; unsigned int m_D3DDevInitialRefCount; bool m_Drawing; const CTexFont * m_FontTex; struct ID3D11Texture2D * m_FontD3DTex; struct ID3D11ShaderResourceView *m_FontD3DTexRV; int m_WndWidth; int m_WndHeight; int m_OffsetX; int m_OffsetY; void * m_ViewportInit; RECT m_ViewportAndScissorRects[2]; struct CLineRectVtx { float m_Pos[3]; color32 m_Color; }; struct CTextVtx { float m_Pos[3]; color32 m_Color; float m_UV[2]; }; struct CConstants { float m_Offset[4]; float m_CstColor[4]; }; struct CTextObj { struct ID3D11Buffer * m_TextVertexBuffer; struct ID3D11Buffer * m_BgVertexBuffer; int m_NbTextVerts; int m_NbBgVerts; int m_TextVertexBufferSize; int m_BgVertexBufferSize; bool m_LineColors; bool m_LineBgColors; }; struct CState11 * m_State; struct ID3D11DepthStencilState *m_DepthStencilState; struct ID3D11BlendState * m_BlendState; struct ID3D11RasterizerState * m_RasterState; struct ID3D11RasterizerState * m_RasterStateAntialiased; struct ID3D11RasterizerState * m_RasterStateMultisample; struct ID3D11RasterizerState * m_RasterStateCullCW; struct ID3D11RasterizerState * m_RasterStateCullCCW; struct ID3D11VertexShader * m_LineRectVS; struct ID3D11VertexShader * m_LineRectCstColorVS; struct ID3D11PixelShader * m_LineRectPS; struct ID3D11InputLayout * m_LineRectVertexLayout; struct ID3D11VertexShader * m_TextVS; struct ID3D11VertexShader * m_TextCstColorVS; struct ID3D11PixelShader * m_TextPS; struct ID3D11InputLayout * m_TextVertexLayout; struct ID3D11Buffer * m_LineVertexBuffer; struct ID3D11Buffer * m_RectVertexBuffer; struct ID3D11Buffer * m_TrianglesVertexBuffer; int m_TrianglesVertexBufferCount; struct ID3D11Buffer * m_ConstantBuffer; struct ID3D11SamplerState * m_SamplerState; }; // --------------------------------------------------------------------------- #endif // !defined ANT_TW_DIRECT3D11_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwDirect3D11.hlsl0000644000000000000000000000402112635011627025506 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwDirect3D11.hlsl // @author Philippe Decaudin - http://www.antisphere.com // @brief AntTweakBar shaders and techniques for Direct3D11 support // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- float4 g_Offset : register(c0) = 0; float4 g_CstColor : register(c1) = 1; // Shaders for lines and rectangles struct LineRectPSInput { float4 Pos : SV_POSITION; float4 Color : COLOR0; }; LineRectPSInput LineRectVS(float4 pos : POSITION, float4 color : COLOR) { LineRectPSInput ps; ps.Pos = pos + g_Offset; ps.Color = color; return ps; } LineRectPSInput LineRectCstColorVS(float4 pos : POSITION, float4 color : COLOR) { LineRectPSInput ps; ps.Pos = pos + g_Offset; ps.Color = g_CstColor; return ps; } float4 LineRectPS(LineRectPSInput input) : SV_TARGET { return input.Color; } // Shaders for text Texture2D g_Font : register(t0); SamplerState g_FontSampler : register(s0) { Filter = MIN_MAG_MIP_POINT; AddressU = BORDER; AddressV = BORDER; BorderColor = float4(0, 0, 0, 0); }; struct TextPSInput { float4 Pos : SV_POSITION; float4 Color : COLOR0; float2 Tex : TEXCOORD0; }; TextPSInput TextVS(float4 pos : POSITION, float4 color : COLOR, float2 tex : TEXCOORD0) { TextPSInput ps; ps.Pos = pos + g_Offset; ps.Color = color; ps.Tex = tex; return ps; } TextPSInput TextCstColorVS(float4 pos : POSITION, float4 color : COLOR, float2 tex : TEXCOORD0) { TextPSInput ps; ps.Pos = pos + g_Offset; ps.Color = g_CstColor; ps.Tex = tex; return ps; } float4 TextPS(TextPSInput input) : SV_TARGET { return g_Font.Sample(g_FontSampler, input.Tex) * input.Color; } ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwDirect3D9.cpp0000644000000000000000000004611412635011627025266 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwDirect3D9.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "TwDirect3D9.h" #include "TwMgr.h" #include #ifdef _DEBUG // #include // #pragma comment(lib, "dxerr9") #endif // _DEBUG using namespace std; const char *g_ErrCantLoadD3D9 = "Cannot load Direct3D9 library dynamically"; const char *g_ErrCantUnloadD3D9 = "Cannot unload Direct3D9 library"; // --------------------------------------------------------------------------- static IDirect3DTexture9 *BindFont(IDirect3DDevice9 *_Dev, const CTexFont *_Font) { assert(_Font!=NULL); IDirect3DTexture9 *Tex = NULL; HRESULT hr = _Dev->CreateTexture(_Font->m_TexWidth, _Font->m_TexHeight, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &Tex, NULL); if( FAILED(hr) ) return NULL; D3DLOCKED_RECT r; hr = Tex->LockRect(0, &r, NULL, 0); if( SUCCEEDED(hr) ) { color32 *p = static_cast(r.pBits); for( int i=0; i<_Font->m_TexWidth*_Font->m_TexHeight; ++i, ++p ) *p = 0x00ffffff | (((color32)(_Font->m_TexBytes[i]))<<24); Tex->UnlockRect(0); } return Tex; } // --------------------------------------------------------------------------- static void UnbindFont(IDirect3DDevice9 *_Dev, IDirect3DTexture9 *_Tex) { (void)_Dev; if( _Tex ) _Tex->Release(); } // --------------------------------------------------------------------------- struct CState { IDirect3DStateBlock9 *m_StateBlock; // DeviceCaps (filled by constructor) D3DCAPS9 m_Caps; void Save(); void Restore(); CState(IDirect3DDevice9 *_Dev); ~CState(); private: IDirect3DDevice9 *m_D3DDev; }; CState::CState(IDirect3DDevice9 *_Dev) { ZeroMemory(this, sizeof(CState)); m_D3DDev = _Dev; m_D3DDev->GetDeviceCaps(&m_Caps); } CState::~CState() { if( m_StateBlock ) { UINT rc = m_StateBlock->Release(); assert( rc==0 ); (void)rc; m_StateBlock = NULL; } } void CState::Save() { if( !m_StateBlock && m_D3DDev ) m_D3DDev->CreateStateBlock(D3DSBT_ALL, &m_StateBlock); if( m_StateBlock ) m_StateBlock->Capture(); } void CState::Restore() { if( m_StateBlock ) m_StateBlock->Apply(); } // --------------------------------------------------------------------------- int CTwGraphDirect3D9::Init() { assert(g_TwMgr->m_Device!=NULL); m_D3DDev = static_cast(g_TwMgr->m_Device); m_Drawing = false; m_FontTex = NULL; m_FontD3DTex = NULL; D3DDEVICE_CREATION_PARAMETERS cp; m_D3DDev->GetCreationParameters(&cp); m_PureDevice = ( cp.BehaviorFlags & D3DCREATE_PUREDEVICE ) ? true : false; m_WndWidth = 0; m_WndHeight = 0; m_State = new CState(m_D3DDev); m_ViewportInit = new D3DVIEWPORT9; ZeroMemory(m_ViewportInit, sizeof(D3DVIEWPORT9)); m_OffsetX = 0; m_OffsetY = 0; return 1; } // --------------------------------------------------------------------------- int CTwGraphDirect3D9::Shut() { assert(m_Drawing==false); UnbindFont(m_D3DDev, m_FontD3DTex); m_FontD3DTex = NULL; delete m_State; m_State = NULL; m_D3DDev = NULL; delete m_ViewportInit; m_ViewportInit = NULL; return 1; } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::BeginDraw(int _WndWidth, int _WndHeight) { assert(m_Drawing==false && _WndWidth>0 && _WndHeight>0); m_Drawing = true; m_WndWidth = _WndWidth; m_WndHeight = _WndHeight; m_OffsetX = 0; m_OffsetY = 0; // save context if( !m_PureDevice ) m_State->Save(); if( m_WndWidth>0 && m_WndHeight>0 ) { D3DVIEWPORT9 Vp; Vp.X = 0; Vp.Y = 0; Vp.Width = m_WndWidth; Vp.Height = m_WndHeight; Vp.MinZ = 0; Vp.MaxZ = 1; m_D3DDev->SetViewport(&Vp); //D3DMATRIX Transfo = { 2.0f/_WndWidth,0,0,0, 0,2.0f/_WndHeight,0,0, 0,0,-1,0, 0,0,0,1 }; //m_D3DDev->SetTransform(D3DTS_PROJECTION, &Transfo); } m_D3DDev->GetViewport(static_cast(m_ViewportInit)); // const D3DMATRIX id = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }; // m_D3DDev->SetTransform(D3DTS_VIEW, &id); // m_D3DDev->SetTransform(D3DTS_WORLD, &id); // m_D3DDev->SetTransform(D3DTS_TEXTURE0, &id); m_D3DDev->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); m_D3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); m_D3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); m_D3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); m_D3DDev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); m_D3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); m_D3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); m_D3DDev->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); m_D3DDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); m_D3DDev->SetRenderState(D3DRS_LASTPIXEL, FALSE); m_D3DDev->SetRenderState(D3DRS_FOGENABLE, FALSE); m_D3DDev->SetRenderState(D3DRS_STENCILENABLE, FALSE); m_D3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, 0x0000000F); m_D3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); if( m_State->m_Caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND ) m_D3DDev->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); //if( m_State->m_Caps.LineCaps & D3DLINECAPS_ANTIALIAS ) m_D3DDev->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, FALSE); m_D3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); m_D3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); m_D3DDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); m_D3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); m_D3DDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); m_D3DDev->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU); m_D3DDev->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); m_D3DDev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); m_D3DDev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); m_D3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); m_D3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); m_D3DDev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); m_D3DDev->SetVertexShader(NULL); m_D3DDev->SetPixelShader(NULL); } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::EndDraw() { assert(m_Drawing==true); m_Drawing = false; // restore context if( !m_PureDevice ) m_State->Restore(); } // --------------------------------------------------------------------------- bool CTwGraphDirect3D9::IsDrawing() { return m_Drawing; } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::Restore() { if( m_State ) if( m_State->m_StateBlock ) { UINT rc = m_State->m_StateBlock->Release(); assert( rc==0 ); (void)rc; m_State->m_StateBlock = NULL; } UnbindFont(m_D3DDev, m_FontD3DTex); m_FontD3DTex = NULL; m_FontTex = NULL; } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased) { assert(m_Drawing==true); struct CVtx { float m_Pos[4]; DWORD m_Color; }; CVtx p[2]; p[0].m_Pos[0] = (float)(_X0 + m_OffsetX); p[0].m_Pos[1] = (float)(_Y0 + m_OffsetY); p[0].m_Pos[2] = 0; p[0].m_Pos[3] = 0; p[0].m_Color = _Color0; p[1].m_Pos[0] = (float)(_X1 + m_OffsetX); p[1].m_Pos[1] = (float)(_Y1 + m_OffsetY); p[1].m_Pos[2] = 0; p[1].m_Pos[3] = 0; p[1].m_Color = _Color1; //if( m_State->m_Caps.LineCaps & D3DLINECAPS_ANTIALIAS ) m_D3DDev->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, (_AntiAliased ? TRUE : FALSE)); m_D3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); m_D3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); m_D3DDev->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE); m_D3DDev->DrawPrimitiveUP(D3DPT_LINELIST, 1, p, sizeof(CVtx)); //if( m_State->m_Caps.LineCaps & D3DLINECAPS_ANTIALIAS ) m_D3DDev->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, FALSE); } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11) { assert(m_Drawing==true); // border adjustment if(_X0<_X1) ++_X1; else if(_X0>_X1) ++_X0; if(_Y0<_Y1) ++_Y1; else if(_Y0>_Y1) ++_Y0; struct CVtx { float m_Pos[4]; DWORD m_Color; }; CVtx p[4]; p[0].m_Pos[0] = (float)(_X1 + m_OffsetX); p[0].m_Pos[1] = (float)(_Y0 + m_OffsetY); p[0].m_Pos[2] = 0; p[0].m_Pos[3] = 1; p[0].m_Color = _Color10; p[1].m_Pos[0] = (float)(_X0 + m_OffsetX); p[1].m_Pos[1] = (float)(_Y0 + m_OffsetY); p[1].m_Pos[2] = 0; p[1].m_Pos[3] = 1; p[1].m_Color = _Color00; p[2].m_Pos[0] = (float)(_X1 + m_OffsetX); p[2].m_Pos[1] = (float)(_Y1 + m_OffsetY); p[2].m_Pos[2] = 0; p[2].m_Pos[3] = 1; p[2].m_Color = _Color11; p[3].m_Pos[0] = (float)(_X0 + m_OffsetX); p[3].m_Pos[1] = (float)(_Y1 + m_OffsetY); p[3].m_Pos[2] = 0; p[3].m_Pos[3] = 1; p[3].m_Color = _Color01; m_D3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); m_D3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); m_D3DDev->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE); m_D3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, p, sizeof(CVtx)); } // --------------------------------------------------------------------------- void *CTwGraphDirect3D9::NewTextObj() { return new CTextObj; } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::DeleteTextObj(void *_TextObj) { assert(_TextObj!=NULL); delete static_cast(_TextObj); } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth) { assert(m_Drawing==true); assert(_TextObj!=NULL); assert(_Font!=NULL); if( _Font != m_FontTex ) { UnbindFont(m_D3DDev, m_FontD3DTex); m_FontD3DTex = BindFont(m_D3DDev, _Font); m_FontTex = _Font; } CTextObj *TextObj = static_cast(_TextObj); TextObj->m_TextVerts.resize(0); TextObj->m_BgVerts.resize(0); TextObj->m_LineColors = (_LineColors!=NULL); TextObj->m_LineBgColors = (_LineBgColors!=NULL); int x, x1, y, y1, i, Len; unsigned char ch; const unsigned char *Text; color32 LineColor = COLOR32_RED; CTextVtx Vtx; Vtx.m_Pos[2] = 0; Vtx.m_Pos[3] = 1; CBgVtx BgVtx; BgVtx.m_Pos[2] = 0; BgVtx.m_Pos[3] = 1; for( int Line=0; Line<_NbLines; ++Line ) { x = 0; y = Line * (_Font->m_CharHeight+_Sep); y1 = y+_Font->m_CharHeight; Len = (int)_TextLines[Line].length(); Text = (const unsigned char *)(_TextLines[Line].c_str()); if( _LineColors!=NULL ) LineColor = _LineColors[Line]; for( i=0; im_CharWidth[ch]; Vtx.m_Color = LineColor; Vtx.m_Pos[0] = (float)x; Vtx.m_Pos[1] = (float)y; Vtx.m_UV [0] = _Font->m_CharU0[ch]; Vtx.m_UV [1] = _Font->m_CharV0[ch]; TextObj->m_TextVerts.push_back(Vtx); Vtx.m_Pos[0] = (float)x1; Vtx.m_Pos[1] = (float)y; Vtx.m_UV [0] = _Font->m_CharU1[ch]; Vtx.m_UV [1] = _Font->m_CharV0[ch]; TextObj->m_TextVerts.push_back(Vtx); Vtx.m_Pos[0] = (float)x; Vtx.m_Pos[1] = (float)y1; Vtx.m_UV [0] = _Font->m_CharU0[ch]; Vtx.m_UV [1] = _Font->m_CharV1[ch]; TextObj->m_TextVerts.push_back(Vtx); Vtx.m_Pos[0] = (float)x1; Vtx.m_Pos[1] = (float)y; Vtx.m_UV [0] = _Font->m_CharU1[ch]; Vtx.m_UV [1] = _Font->m_CharV0[ch]; TextObj->m_TextVerts.push_back(Vtx); Vtx.m_Pos[0] = (float)x1; Vtx.m_Pos[1] = (float)y1; Vtx.m_UV [0] = _Font->m_CharU1[ch]; Vtx.m_UV [1] = _Font->m_CharV1[ch]; TextObj->m_TextVerts.push_back(Vtx); Vtx.m_Pos[0] = (float)x; Vtx.m_Pos[1] = (float)y1; Vtx.m_UV [0] = _Font->m_CharU0[ch]; Vtx.m_UV [1] = _Font->m_CharV1[ch]; TextObj->m_TextVerts.push_back(Vtx); x = x1; } if( _BgWidth>0 ) { if( _LineBgColors!=NULL ) BgVtx.m_Color = _LineBgColors[Line]; else BgVtx.m_Color = COLOR32_BLACK; BgVtx.m_Pos[0] = -1; BgVtx.m_Pos[1] = (float)y; TextObj->m_BgVerts.push_back(BgVtx); BgVtx.m_Pos[0] = (float)(_BgWidth+1); BgVtx.m_Pos[1] = (float)y; TextObj->m_BgVerts.push_back(BgVtx); BgVtx.m_Pos[0] = -1; BgVtx.m_Pos[1] = (float)y1; TextObj->m_BgVerts.push_back(BgVtx); BgVtx.m_Pos[0] = (float)(_BgWidth+1); BgVtx.m_Pos[1] = (float)y; TextObj->m_BgVerts.push_back(BgVtx); BgVtx.m_Pos[0] = (float)(_BgWidth+1); BgVtx.m_Pos[1] = (float)y1; TextObj->m_BgVerts.push_back(BgVtx); BgVtx.m_Pos[0] = -1; BgVtx.m_Pos[1] = (float)y1; TextObj->m_BgVerts.push_back(BgVtx); } } } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor) { assert(m_Drawing==true); assert(_TextObj!=NULL); CTextObj *TextObj = static_cast(_TextObj); float x = (float)_X; float y = (float)_Y; int i; int nv = (int)TextObj->m_TextVerts.size(); int nb = (int)TextObj->m_BgVerts.size(); if( nb>=4 ) { for( i=0; im_BgVerts[i].m_Pos[0] += x + m_OffsetX; TextObj->m_BgVerts[i].m_Pos[1] += y + m_OffsetY; if( _BgColor!=0 || !TextObj->m_LineBgColors ) TextObj->m_BgVerts[i].m_Color = _BgColor; } m_D3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); m_D3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); m_D3DDev->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE); m_D3DDev->DrawPrimitiveUP(D3DPT_TRIANGLELIST, nb/3, &(TextObj->m_BgVerts[0]), sizeof(CBgVtx)); for( i=0; im_BgVerts[i].m_Pos[0] -= x + m_OffsetX; TextObj->m_BgVerts[i].m_Pos[1] -= y + m_OffsetY; } } if( nv>=4 ) { for( i=0; im_TextVerts[i].m_Pos[0] += x + m_OffsetX; TextObj->m_TextVerts[i].m_Pos[1] += y + m_OffsetY; } if( _Color!=0 || !TextObj->m_LineColors ) for( i=0; im_TextVerts[i].m_Color = _Color; m_D3DDev->SetTexture(0, m_FontD3DTex); m_D3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); m_D3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); m_D3DDev->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1|D3DFVF_TEXCOORDSIZE2(0)); m_D3DDev->DrawPrimitiveUP(D3DPT_TRIANGLELIST, nv/3, &(TextObj->m_TextVerts[0]), sizeof(CTextVtx)); for( i=0; im_TextVerts[i].m_Pos[0] -= x + m_OffsetX; TextObj->m_TextVerts[i].m_Pos[1] -= y + m_OffsetY; } } } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY) { if( _Width>0 && _Height>0 ) { D3DVIEWPORT9 Vp; Vp.X = _X0; Vp.Y = _Y0; Vp.Width = _Width; Vp.Height = _Height; Vp.MinZ = 0; Vp.MaxZ = 1; m_D3DDev->SetViewport(&Vp); m_OffsetX = _X0 + _OffsetX; m_OffsetY = _Y0 + _OffsetY - 1; } } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::RestoreViewport() { m_D3DDev->SetViewport(static_cast(m_ViewportInit)); m_OffsetX = m_OffsetY = 0; } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::SetScissor(int _X0, int _Y0, int _Width, int _Height) { if( _Width>0 && _Height>0 ) { RECT Rect; Rect.left = _X0 - 1; Rect.right = Rect.left + _Width - 1; Rect.top = _Y0; Rect.bottom = Rect.top + _Height; m_D3DDev->SetScissorRect(&Rect); m_D3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); } else m_D3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); } // --------------------------------------------------------------------------- void CTwGraphDirect3D9::DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode) { assert(m_Drawing==true); if( _NumTriangles<0 ) return; DWORD prevCullMode = D3DCULL_NONE; m_D3DDev->GetRenderState(D3DRS_CULLMODE, &prevCullMode); if( _CullMode==CULL_CW ) m_D3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); else if( _CullMode==CULL_CCW ) m_D3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); else m_D3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); if( (int)m_TriVertices.size()<3*_NumTriangles ) m_TriVertices.resize(3*_NumTriangles); for( int i=0; i<3*_NumTriangles; ++i ) { m_TriVertices[i].m_Pos[0] = (float)(_Vertices[2*i+0] + m_OffsetX); m_TriVertices[i].m_Pos[1] = (float)(_Vertices[2*i+1] + m_OffsetY); m_TriVertices[i].m_Pos[2] = 0; m_TriVertices[i].m_Pos[3] = 1; m_TriVertices[i].m_Color = _Colors[i]; } m_D3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE); m_D3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); m_D3DDev->SetFVF(D3DFVF_XYZRHW|D3DFVF_DIFFUSE); m_D3DDev->DrawPrimitiveUP(D3DPT_TRIANGLELIST, _NumTriangles, &(m_TriVertices[0]), sizeof(CTriVtx)); m_D3DDev->SetRenderState(D3DRS_CULLMODE, prevCullMode); } // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwDirect3D9.h0000644000000000000000000000707412635011627024735 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwDirect3D9.h // @brief Direct3D9 graph functions // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_DIRECT3D9_INCLUDED #define ANT_TW_DIRECT3D9_INCLUDED #include "TwGraph.h" // --------------------------------------------------------------------------- class CTwGraphDirect3D9 : public ITwGraph { public: virtual int Init(); virtual int Shut(); virtual void BeginDraw(int _WndWidth, int _WndHeight); virtual void EndDraw(); virtual bool IsDrawing(); virtual void Restore(); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased=false); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color, bool _AntiAliased=false) { DrawLine(_X0, _Y0, _X1, _Y1, _Color, _Color, _AntiAliased); } virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11); virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color) { DrawRect(_X0, _Y0, _X1, _Y1, _Color, _Color, _Color, _Color); } virtual void DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode); virtual void * NewTextObj(); virtual void DeleteTextObj(void *_TextObj); virtual void BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth); virtual void DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor); virtual void ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY); virtual void RestoreViewport(); virtual void SetScissor(int _X0, int _Y0, int _Width, int _Height); protected: struct IDirect3DDevice9 * m_D3DDev; bool m_Drawing; const CTexFont * m_FontTex; struct IDirect3DTexture9 * m_FontD3DTex; bool m_PureDevice; int m_WndWidth; int m_WndHeight; void * m_ViewportInit; int m_OffsetX; int m_OffsetY; struct CTextVtx { float m_Pos[4]; color32 m_Color; float m_UV[2]; }; struct CBgVtx { float m_Pos[4]; color32 m_Color; }; struct CTextObj { std::vector m_TextVerts; std::vector m_BgVerts; bool m_LineColors; bool m_LineBgColors; }; struct CTriVtx { float m_Pos[4]; DWORD m_Color; }; std::vector m_TriVertices; struct CState * m_State; }; // --------------------------------------------------------------------------- #endif // !defined ANT_TW_DIRECT3D9_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwEventGLFW.c0000644000000000000000000001431712635011627024775 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwEventGLFW.c // @brief Helper: // translate and re-send mouse and keyboard events // from GLFW event callbacks to AntTweakBar // // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- // #include #include "MiniGLFW.h" // a subset of GLFW.h needed to compile TwEventGLFW.c // note: AntTweakBar.dll does not need to link with GLFW, // it just needs some definitions for its helper functions. #include int TW_CALL TwEventMouseButtonGLFW(int glfwButton, int glfwAction) { int handled = 0; TwMouseAction action = (glfwAction==GLFW_PRESS) ? TW_MOUSE_PRESSED : TW_MOUSE_RELEASED; if( glfwButton==GLFW_MOUSE_BUTTON_LEFT ) handled = TwMouseButton(action, TW_MOUSE_LEFT); else if( glfwButton==GLFW_MOUSE_BUTTON_RIGHT ) handled = TwMouseButton(action, TW_MOUSE_RIGHT); else if( glfwButton==GLFW_MOUSE_BUTTON_MIDDLE ) handled = TwMouseButton(action, TW_MOUSE_MIDDLE); return handled; } int g_KMod = 0; int TW_CALL TwEventKeyGLFW(int glfwKey, int glfwAction) { int handled = 0; // Register of modifiers state if( glfwAction==GLFW_PRESS ) { switch( glfwKey ) { case GLFW_KEY_LSHIFT: case GLFW_KEY_RSHIFT: g_KMod |= TW_KMOD_SHIFT; break; case GLFW_KEY_LCTRL: case GLFW_KEY_RCTRL: g_KMod |= TW_KMOD_CTRL; break; case GLFW_KEY_LALT: case GLFW_KEY_RALT: g_KMod |= TW_KMOD_ALT; break; } } else { switch( glfwKey ) { case GLFW_KEY_LSHIFT: case GLFW_KEY_RSHIFT: g_KMod &= ~TW_KMOD_SHIFT; break; case GLFW_KEY_LCTRL: case GLFW_KEY_RCTRL: g_KMod &= ~TW_KMOD_CTRL; break; case GLFW_KEY_LALT: case GLFW_KEY_RALT: g_KMod &= ~TW_KMOD_ALT; break; } } // Process key pressed if( glfwAction==GLFW_PRESS ) { int mod = g_KMod; int testkp = ((mod&TW_KMOD_CTRL) || (mod&TW_KMOD_ALT)) ? 1 : 0; if( (mod&TW_KMOD_CTRL) && glfwKey>0 && glfwKey=GLFW_KEY_SPECIAL ) { int k = 0; if( glfwKey>=GLFW_KEY_F1 && glfwKey<=GLFW_KEY_F15 ) k = TW_KEY_F1 + (glfwKey-GLFW_KEY_F1); else if( testkp && glfwKey>=GLFW_KEY_KP_0 && glfwKey<=GLFW_KEY_KP_9 ) k = '0' + (glfwKey-GLFW_KEY_KP_0); else { switch( glfwKey ) { case GLFW_KEY_ESC: k = TW_KEY_ESCAPE; break; case GLFW_KEY_UP: k = TW_KEY_UP; break; case GLFW_KEY_DOWN: k = TW_KEY_DOWN; break; case GLFW_KEY_LEFT: k = TW_KEY_LEFT; break; case GLFW_KEY_RIGHT: k = TW_KEY_RIGHT; break; case GLFW_KEY_TAB: k = TW_KEY_TAB; break; case GLFW_KEY_ENTER: k = TW_KEY_RETURN; break; case GLFW_KEY_BACKSPACE: k = TW_KEY_BACKSPACE; break; case GLFW_KEY_INSERT: k = TW_KEY_INSERT; break; case GLFW_KEY_DEL: k = TW_KEY_DELETE; break; case GLFW_KEY_PAGEUP: k = TW_KEY_PAGE_UP; break; case GLFW_KEY_PAGEDOWN: k = TW_KEY_PAGE_DOWN; break; case GLFW_KEY_HOME: k = TW_KEY_HOME; break; case GLFW_KEY_END: k = TW_KEY_END; break; case GLFW_KEY_KP_ENTER: k = TW_KEY_RETURN; break; case GLFW_KEY_KP_DIVIDE: if( testkp ) k = '/'; break; case GLFW_KEY_KP_MULTIPLY: if( testkp ) k = '*'; break; case GLFW_KEY_KP_SUBTRACT: if( testkp ) k = '-'; break; case GLFW_KEY_KP_ADD: if( testkp ) k = '+'; break; case GLFW_KEY_KP_DECIMAL: if( testkp ) k = '.'; break; case GLFW_KEY_KP_EQUAL: if( testkp ) k = '='; break; } } if( k>0 ) handled = TwKeyPressed(k, mod); } } return handled; } int TW_CALL TwEventCharGLFW(int glfwChar, int glfwAction) { if( glfwAction==GLFW_PRESS && (glfwChar & 0xff00)==0 ) return TwKeyPressed(glfwChar, g_KMod); return 0; } // functions with __cdecl calling convension TW_API int TW_CDECL_CALL TwEventMouseButtonGLFWcdecl(int glfwButton, int glfwAction) { return TwEventMouseButtonGLFW(glfwButton, glfwAction); } TW_API int TW_CDECL_CALL TwEventKeyGLFWcdecl(int glfwKey, int glfwAction) { return TwEventKeyGLFW(glfwKey, glfwAction); } TW_API int TW_CDECL_CALL TwEventCharGLFWcdecl(int glfwChar, int glfwAction) { return TwEventCharGLFW(glfwChar, glfwAction); } TW_API int TW_CDECL_CALL TwEventMousePosGLFWcdecl(int mouseX, int mouseY) { return TwMouseMotion(mouseX, mouseY); } TW_API int TW_CDECL_CALL TwEventMouseWheelGLFWcdecl(int wheelPos) { return TwMouseWheel(wheelPos); } ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwEventGLUT.c0000644000000000000000000001026312635011627025005 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwEventGLUT.c // @brief Helper: // translate and re-send mouse and keyboard events // from GLUT event callbacks to AntTweakBar // // @author Philippe Decaudin - http://www.antisphere.com // @date 2006/05/10 // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #define GLUT_NO_LIB_PRAGMA // we do not want to force linkage with glut #ifdef _MSC_VER # pragma warning(disable: 4505) // glut generates 'unreferenced function' warnings # pragma warning(disable: 4100) // unreferenced parameter #endif // _MSC_VER // #include #include "MiniGLUT.h" // a subset of glut.h needed to compile TwEventGLUT.c // note: AntTweakBar.dll does not need to link with GLUT, // it just needs some definitions for its helper functions. #include int TW_GLUT_CALL TwEventMouseButtonGLUT(int glutButton, int glutState, int mouseX, int mouseY) { TwMouseAction action = (glutState==GLUT_DOWN) ? TW_MOUSE_PRESSED : TW_MOUSE_RELEASED; TwMouseMotion(mouseX, mouseY); switch( glutButton ) { case GLUT_LEFT_BUTTON: return TwMouseButton(action, TW_MOUSE_LEFT); case GLUT_RIGHT_BUTTON: return TwMouseButton(action, TW_MOUSE_RIGHT); case GLUT_MIDDLE_BUTTON: return TwMouseButton(action, TW_MOUSE_MIDDLE); default: return 0; } } int TW_GLUT_CALL TwEventMouseMotionGLUT(int mouseX, int mouseY) { return TwMouseMotion(mouseX, mouseY); } // GLUT does not send modifiers state to 'Key' and 'Special' callbacks, // and we cannot call glutGetModifiers here because we do not want to link // AntTweakBar with glut, so the following function is used to store // a pointer to the glutGetModifiers function of the calling application. // It must be called at initialisation of the application. int (TW_CALL *g_GLUTGetModifiers)(void) = NULL; int TW_CALL TwGLUTModifiersFunc(int (TW_CALL *glutGetModifiersFunc)(void)) { g_GLUTGetModifiers = glutGetModifiersFunc; return (g_GLUTGetModifiers==NULL) ? 0 : 1; } int TW_GLUT_CALL TwEventKeyboardGLUT(unsigned char glutKey, int mouseX, int mouseY) { int kmod = 0; if( g_GLUTGetModifiers!=NULL ) { int glutMod = g_GLUTGetModifiers(); if( glutMod&GLUT_ACTIVE_SHIFT ) kmod |= TW_KMOD_SHIFT; if( glutMod&GLUT_ACTIVE_CTRL ) kmod |= TW_KMOD_CTRL; if( glutMod&GLUT_ACTIVE_ALT ) kmod |= TW_KMOD_ALT; } if( (kmod&TW_KMOD_CTRL) && (glutKey>0 && glutKey<27) ) // CTRL special case glutKey += 'a'-1; return TwKeyPressed((int)glutKey, kmod); } int TW_GLUT_CALL TwEventSpecialGLUT(int glutKey, int mouseX, int mouseY) { int k = 0, kmod = 0; if( g_GLUTGetModifiers!=NULL ) { int glutMod = g_GLUTGetModifiers(); if( glutMod&GLUT_ACTIVE_SHIFT ) kmod |= TW_KMOD_SHIFT; if( glutMod&GLUT_ACTIVE_CTRL ) kmod |= TW_KMOD_CTRL; if( glutMod&GLUT_ACTIVE_ALT ) kmod |= TW_KMOD_ALT; } if( glutKey>=GLUT_KEY_F1 && glutKey<=GLUT_KEY_F12 ) k = TW_KEY_F1 + (glutKey-GLUT_KEY_F1); else { switch( glutKey ) { case GLUT_KEY_LEFT: k = TW_KEY_LEFT; break; case GLUT_KEY_UP: k = TW_KEY_UP; break; case GLUT_KEY_RIGHT: k = TW_KEY_RIGHT; break; case GLUT_KEY_DOWN: k = TW_KEY_DOWN; break; case GLUT_KEY_PAGE_UP: k = TW_KEY_PAGE_UP; break; case GLUT_KEY_PAGE_DOWN: k = TW_KEY_PAGE_DOWN; break; case GLUT_KEY_HOME: k = TW_KEY_HOME; break; case GLUT_KEY_END: k = TW_KEY_END; break; case GLUT_KEY_INSERT: k = TW_KEY_INSERT; break; } } if( k>0 && k int TW_CALL TwEventSDL12(const void *sdlEvent); // implemented in TwEventSDL12.c int TW_CALL TwEventSDL13(const void *sdlEvent); // implmeneted in TwEventSDL13.c #ifdef __cplusplus extern "C" { int TW_CALL TwSetLastError(const char *staticErrorMessage); } #else int TW_CALL TwSetLastError(const char *staticErrorMessage); #endif // __cplusplus // TwEventSDL returns zero if msg has not been handled or the SDL version // is not supported, and a non-zero value if it has been handled by the // AntTweakBar library. int TW_CALL TwEventSDL(const void *sdlEvent, unsigned char majorVersion, unsigned char minorVersion) { if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 2)) { static const char *g_ErrBadSDLVersion = "Unsupported SDL version"; TwSetLastError(g_ErrBadSDLVersion); return 0; } else if (majorVersion == 1 && minorVersion == 2) return TwEventSDL12(sdlEvent); else // if( majorVersion==1 && minorVersion==3 ) return TwEventSDL13(sdlEvent); // will probably not work for version > 1.3, but give it a chance } ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwEventSDL12.c0000644000000000000000000000514012635011627025015 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwEventSDL12.c // @brief Helper: // translate and re-send mouse and keyboard events // from SDL 1.2 event loop to AntTweakBar // // @author Philippe Decaudin - http://www.antisphere.com // @date 2006/05/10 // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "MiniSDL12.h" // a subset of SDL.h needed to compile TwEventSDL12.c // note: AntTweakBar.dll does not need to link with SDL, // it just needs some definitions for its helper functions. #include // TwEventSDL12 returns zero if msg has not been handled, // and a non-zero value if it has been handled by the AntTweakBar library. int TW_CALL TwEventSDL12(const void *sdlEvent) { int handled = 0; const SDL_Event *event = (const SDL_Event *)sdlEvent; if( event==NULL ) return 0; switch( event->type ) { case SDL_KEYDOWN: if( event->key.keysym.unicode!=0 && (event->key.keysym.unicode & 0xFF00)==0 ) { if( (event->key.keysym.unicode & 0xFF)<32 && (event->key.keysym.unicode & 0xFF)!=event->key.keysym.sym ) handled = TwKeyPressed((event->key.keysym.unicode & 0xFF)+'a'-1, event->key.keysym.mod); else handled = TwKeyPressed(event->key.keysym.unicode & 0xFF, event->key.keysym.mod); } else handled = TwKeyPressed(event->key.keysym.sym, event->key.keysym.mod); break; case SDL_MOUSEMOTION: handled = TwMouseMotion(event->motion.x, event->motion.y); break; case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONDOWN: if( event->type==SDL_MOUSEBUTTONDOWN && (event->button.button==4 || event->button.button==5) ) // mouse wheel { static int s_WheelPos = 0; if( event->button.button==4 ) ++s_WheelPos; else --s_WheelPos; handled = TwMouseWheel(s_WheelPos); } else handled = TwMouseButton((event->type==SDL_MOUSEBUTTONUP)?TW_MOUSE_RELEASED:TW_MOUSE_PRESSED, (TwMouseButtonID)event->button.button); break; case SDL_VIDEORESIZE: // tell the new size to TweakBar TwWindowSize(event->resize.w, event->resize.h); // do not set 'handled', SDL_VIDEORESIZE may be also processed by the calling application break; } return handled; } ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwEventSDL13.c0000644000000000000000000001064212635011627025021 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwEventSDL13.c // @brief Helper: // translate and re-send mouse and keyboard events // from SDL 1.3 event loop to AntTweakBar // // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "MiniSDL13.h" // a subset of SDL.h needed to compile TwEventSDL.c // note: AntTweakBar.dll does not need to link with SDL, // it just needs some definitions for its helper functions. #include // The way SDL handles keyboard events has changed between version 1.2 // and 1.3. It is now more difficult to translate SDL keyboard events to // AntTweakBar events. The following code is an attempt to do so, but // it is rather complex and not always accurate (eg, CTRL+1 is not handled). // If someone knows a better and more robust way to do the keyboard events // translation, please let me know. // TwEventSDL returns zero if msg has not been handled, // and a non-zero value if it has been handled by the AntTweakBar library. int TW_CALL TwEventSDL13(const void *sdlEvent) { int handled = 0; static int s_KeyMod = 0; const SDL_Event *event = (const SDL_Event *)sdlEvent; if( event==NULL ) return 0; switch( event->type ) { case SDL_TEXTINPUT: if( event->text.text[0]!=0 && event->text.text[1]==0 ) { if( s_KeyMod & TW_KMOD_CTRL && event->text.text[0]<32 ) handled = TwKeyPressed(event->text.text[0]+'a'-1, s_KeyMod); else { if (s_KeyMod & KMOD_RALT) s_KeyMod &= ~KMOD_CTRL; handled = TwKeyPressed(event->text.text[0], s_KeyMod); } } s_KeyMod = 0; break; case SDL_KEYDOWN: if( event->key.keysym.sym & SDLK_SCANCODE_MASK ) { int key = 0; switch( event->key.keysym.sym ) { case SDLK_UP: key = TW_KEY_UP; break; case SDLK_DOWN: key = TW_KEY_DOWN; break; case SDLK_RIGHT: key = TW_KEY_RIGHT; break; case SDLK_LEFT: key = TW_KEY_LEFT; break; case SDLK_INSERT: key = TW_KEY_INSERT; break; case SDLK_HOME: key = TW_KEY_HOME; break; case SDLK_END: key = TW_KEY_END; break; case SDLK_PAGEUP: key = TW_KEY_PAGE_UP; break; case SDLK_PAGEDOWN: key = TW_KEY_PAGE_DOWN; break; default: if( event->key.keysym.sym>=SDLK_F1 && event->key.keysym.sym<=SDLK_F12 ) key = event->key.keysym.sym + TW_KEY_F1 - SDLK_F1; } if( key!=0 ) handled = TwKeyPressed(key, event->key.keysym.mod); } else if( event->key.keysym.mod & TW_KMOD_ALT ) handled = TwKeyPressed(event->key.keysym.sym & 0xFF, event->key.keysym.mod); else s_KeyMod = event->key.keysym.mod; break; case SDL_KEYUP: s_KeyMod = 0; break; case SDL_MOUSEMOTION: handled = TwMouseMotion(event->motion.x, event->motion.y); break; case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONDOWN: if( event->type==SDL_MOUSEBUTTONDOWN && (event->button.button==4 || event->button.button==5) ) // mouse wheel { static int s_WheelPos = 0; if( event->button.button==4 ) ++s_WheelPos; else --s_WheelPos; handled = TwMouseWheel(s_WheelPos); } else handled = TwMouseButton((event->type==SDL_MOUSEBUTTONUP)?TW_MOUSE_RELEASED:TW_MOUSE_PRESSED, (TwMouseButtonID)event->button.button); break; case SDL_VIDEORESIZE: // tell the new size to TweakBar TwWindowSize(event->resize.w, event->resize.h); // do not set 'handled', SDL_VIDEORESIZE may be also processed by the calling application break; } return handled; } ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwEventSFML.cpp0000644000000000000000000001314112635011627025331 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwEventSFML.cpp // @brief Helper: // translate and re-send mouse and keyboard events // from SFML 1.6 event loop to AntTweakBar // // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "MiniSFML16.h" // a subset of SFML 1.6 headers needed to compile TwEventSFML.cpp // note: AntTweakBar.dll does not need to link with SFML, // it just needs some definitions for its helper functions. #include // TwEventSFML returns zero if msg has not been handled, // and a non-zero value if it has been handled by the AntTweakBar library. int TW_CALL TwEventSFML(const void *sfmlEvent, unsigned char majorVersion, unsigned char minorVersion) { // Assume version 1.6 (will possibly not work for version != 1.6, but give it a chance) /* if (majorVersion > 1 || (majorVersion == 1 && minorVersion > 6) { static const char *g_ErrBadSFMLVersion = "Unsupported SFML version"; TwSetLastError(g_ErrBadSFMLVersion); return 0; } */ (void)majorVersion, (void)minorVersion; int handled = 0; const sf::Event *event = (const sf::Event *)sfmlEvent; TwMouseAction mouseAction; int key = 0; static int s_KMod = 0; static bool s_PreventTextHandling = false; static int s_WheelPos = 0; if (event == NULL) return 0; switch (event->Type) { case sf::Event::KeyPressed: s_PreventTextHandling = false; s_KMod = 0; if (event->Key.Shift) s_KMod |= TW_KMOD_SHIFT; if (event->Key.Alt) s_KMod |= TW_KMOD_ALT; if (event->Key.Control) s_KMod |= TW_KMOD_CTRL; key = 0; switch (event->Key.Code) { case sf::Key::Escape: key = TW_KEY_ESCAPE; break; case sf::Key::Return: key = TW_KEY_RETURN; break; case sf::Key::Tab: key = TW_KEY_TAB; break; case sf::Key::Back: key = TW_KEY_BACKSPACE; break; case sf::Key::PageUp: key = TW_KEY_PAGE_UP; break; case sf::Key::PageDown: key = TW_KEY_PAGE_DOWN; break; case sf::Key::Up: key = TW_KEY_UP; break; case sf::Key::Down: key = TW_KEY_DOWN; break; case sf::Key::Left: key = TW_KEY_LEFT; break; case sf::Key::Right: key = TW_KEY_RIGHT; break; case sf::Key::End: key = TW_KEY_END; break; case sf::Key::Home: key = TW_KEY_HOME; break; case sf::Key::Insert: key = TW_KEY_INSERT; break; case sf::Key::Delete: key = TW_KEY_DELETE; break; case sf::Key::Space: key = TW_KEY_SPACE; break; default: if (event->Key.Code >= sf::Key::F1 && event->Key.Code <= sf::Key::F15) key = TW_KEY_F1 + event->Key.Code - sf::Key::F1; else if (s_KMod & TW_KMOD_ALT) { if (event->Key.Code >= sf::Key::A && event->Key.Code <= sf::Key::Z) { if (s_KMod & TW_KMOD_SHIFT) key = 'A' + event->Key.Code - sf::Key::A; else key = 'a' + event->Key.Code - sf::Key::A; } } } if (key != 0) { handled = TwKeyPressed(key, s_KMod); s_PreventTextHandling = true; } break; case sf::Event::KeyReleased: s_PreventTextHandling = false; s_KMod = 0; break; case sf::Event::TextEntered: if (!s_PreventTextHandling && event->Text.Unicode != 0 && (event->Text.Unicode & 0xFF00) == 0) { if ((event->Text.Unicode & 0xFF) < 32) // CTRL+letter handled = TwKeyPressed((event->Text.Unicode & 0xFF)+'a'-1, TW_KMOD_CTRL|s_KMod); else handled = TwKeyPressed(event->Text.Unicode & 0xFF, 0); } s_PreventTextHandling = false; break; case sf::Event::MouseMoved: handled = TwMouseMotion(event->MouseMove.X, event->MouseMove.Y); break; case sf::Event::MouseButtonPressed: case sf::Event::MouseButtonReleased: mouseAction = (event->Type==sf::Event::MouseButtonPressed) ? TW_MOUSE_PRESSED : TW_MOUSE_RELEASED; switch (event->MouseButton.Button) { case sf::Mouse::Left: handled = TwMouseButton(mouseAction, TW_MOUSE_LEFT); break; case sf::Mouse::Middle: handled = TwMouseButton(mouseAction, TW_MOUSE_MIDDLE); break; case sf::Mouse::Right: handled = TwMouseButton(mouseAction, TW_MOUSE_RIGHT); break; default: break; } break; case sf::Event::MouseWheelMoved: s_WheelPos += event->MouseWheel.Delta; handled = TwMouseWheel(s_WheelPos); break; case sf::Event::Resized: // tell the new size to TweakBar TwWindowSize(event->Size.Width, event->Size.Height); // do not set 'handled', sf::Event::Resized may be also processed by the client application break; default: break; } return handled; } ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwEventWin.c0000644000000000000000000002010512635011627024763 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwEventWin.c // @brief Helper: // translate and re-send mouse and keyboard events // from Windows message proc to AntTweakBar // // @author Philippe Decaudin - http://www.antisphere.com // @date 2006/05/10 // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include // Mouse wheel support #if !defined WM_MOUSEWHEEL # define WM_MOUSEWHEEL 0x020A #endif // WM_MOUSEWHEEL #if !defined WHEEL_DELTA #define WHEEL_DELTA 120 #endif // WHEEL_DELTA #ifdef _WIN64 #define PARAM_INT __int64 #else #define PARAM_INT int #endif // TwEventWin returns zero if msg has not been handled, // and a non-zero value if it has been handled by the AntTweakBar library. int TW_CALL TwEventWin(void *wnd, unsigned int msg, unsigned PARAM_INT _W64 wParam, PARAM_INT _W64 lParam) { int handled = 0; static unsigned PARAM_INT s_PrevKeyDown = 0; static PARAM_INT s_PrevKeyDownMod = 0; static int s_PrevKeyDownHandled = 0; switch( msg ) { case WM_MOUSEMOVE: // send signed! mouse coordinates handled = TwMouseMotion((short)LOWORD(lParam), (short)HIWORD(lParam)); break; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: SetCapture(wnd); handled = TwMouseButton(TW_MOUSE_PRESSED, TW_MOUSE_LEFT); break; case WM_LBUTTONUP: ReleaseCapture(); handled = TwMouseButton(TW_MOUSE_RELEASED, TW_MOUSE_LEFT); break; case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: SetCapture(wnd); handled = TwMouseButton(TW_MOUSE_PRESSED, TW_MOUSE_MIDDLE); break; case WM_MBUTTONUP: ReleaseCapture(); handled = TwMouseButton(TW_MOUSE_RELEASED, TW_MOUSE_MIDDLE); break; case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: SetCapture(wnd); handled = TwMouseButton(TW_MOUSE_PRESSED, TW_MOUSE_RIGHT); break; case WM_RBUTTONUP: ReleaseCapture(); handled = TwMouseButton(TW_MOUSE_RELEASED, TW_MOUSE_RIGHT); break; case WM_CHAR: case WM_SYSCHAR: { int key = (int)(wParam&0xff); int kmod = 0; if( GetAsyncKeyState(VK_SHIFT)<0 ) kmod |= TW_KMOD_SHIFT; if( GetAsyncKeyState(VK_CONTROL)<0 ) { kmod |= TW_KMOD_CTRL; if( key>0 && key<27 ) key += 'a'-1; } if( GetAsyncKeyState(VK_MENU)<0 ) kmod |= TW_KMOD_ALT; if( key>0 && key<256 ) handled = TwKeyPressed(key, kmod); } break; case WM_KEYDOWN: case WM_SYSKEYDOWN: { int kmod = 0; int testkp = 0; int k = 0; if( GetAsyncKeyState(VK_SHIFT)<0 ) kmod |= TW_KMOD_SHIFT; if( GetAsyncKeyState(VK_CONTROL)<0 ) { kmod |= TW_KMOD_CTRL; testkp = 1; } if( GetAsyncKeyState(VK_MENU)<0 ) { kmod |= TW_KMOD_ALT; testkp = 1; } if( wParam>=VK_F1 && wParam<=VK_F15 ) k = TW_KEY_F1 + ((int)wParam-VK_F1); else if( testkp && wParam>=VK_NUMPAD0 && wParam<=VK_NUMPAD9 ) k = '0' + ((int)wParam-VK_NUMPAD0); else { switch( wParam ) { case VK_UP: k = TW_KEY_UP; break; case VK_DOWN: k = TW_KEY_DOWN; break; case VK_LEFT: k = TW_KEY_LEFT; break; case VK_RIGHT: k = TW_KEY_RIGHT; break; case VK_INSERT: k = TW_KEY_INSERT; break; case VK_DELETE: k = TW_KEY_DELETE; break; case VK_PRIOR: k = TW_KEY_PAGE_UP; break; case VK_NEXT: k = TW_KEY_PAGE_DOWN; break; case VK_HOME: k = TW_KEY_HOME; break; case VK_END: k = TW_KEY_END; break; case VK_DIVIDE: if( testkp ) k = '/'; break; case VK_MULTIPLY: if( testkp ) k = '*'; break; case VK_SUBTRACT: if( testkp ) k = '-'; break; case VK_ADD: if( testkp ) k = '+'; break; case VK_DECIMAL: if( testkp ) k = '.'; break; default: if( (kmod&TW_KMOD_CTRL) && (kmod&TW_KMOD_ALT) ) k = MapVirtualKey( (UINT)wParam, 2 ) & 0x0000FFFF; } } if( k!=0 ) handled = TwKeyPressed(k, kmod); else { // if the key will be handled at next WM_CHAR report this event as handled int key = (int)(wParam&0xff); if( kmod&TW_KMOD_CTRL && key>0 && key<27 ) key += 'a'-1; if( key>0 && key<256 ) handled = TwKeyTest(key, kmod); } s_PrevKeyDown = wParam; s_PrevKeyDownMod = kmod; s_PrevKeyDownHandled = handled; } break; case WM_KEYUP: case WM_SYSKEYUP: { int kmod = 0; if( GetAsyncKeyState(VK_SHIFT)<0 ) kmod |= TW_KMOD_SHIFT; if( GetAsyncKeyState(VK_CONTROL)<0 ) kmod |= TW_KMOD_CTRL; if( GetAsyncKeyState(VK_MENU)<0 ) kmod |= TW_KMOD_ALT; // if the key has been handled at previous WM_KEYDOWN report this event as handled if( s_PrevKeyDown==wParam && s_PrevKeyDownMod==kmod ) handled = s_PrevKeyDownHandled; else { // if the key would have been handled report this event as handled int key = (int)(wParam&0xff); if( kmod&TW_KMOD_CTRL && key>0 && key<27 ) key += 'a'-1; if( key>0 && key<256 ) handled = TwKeyTest(key, kmod); } // reset previous keydown s_PrevKeyDown = 0; s_PrevKeyDownMod = 0; s_PrevKeyDownHandled = 0; } break; case WM_MOUSEWHEEL: { static int s_WheelPos = 0; s_WheelPos += ((short)HIWORD(wParam))/WHEEL_DELTA; handled = TwMouseWheel(s_WheelPos); } break; case WM_SIZE: // tell the new size to AntTweakBar TwWindowSize(LOWORD(lParam), HIWORD(lParam)); // do not set 'handled', WM_SIZE may be also processed by the calling application break; } if( handled ) // Event has been handled by AntTweakBar, so we invalidate the window // content to send a WM_PAINT which will redraw the tweak bar(s). InvalidateRect(wnd, NULL, FALSE); return handled; } // For compatibility with AntTweakBar versions prior to 1.11 #undef TwEventWin32 #ifdef __cplusplus extern "C" { #endif // __cplusplus TW_EXPORT_API int TW_CALL TwEventWin32(void *wnd, unsigned int msg, unsigned int _W64 wParam, int _W64 lParam) { return TwEventWin(wnd, msg, wParam, lParam); } #ifdef __cplusplus } #endif // __cplusplus ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwFonts.cpp0000644000000000000000000107241312635011627024667 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwFonts.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "TwMgr.h" #include "TwFonts.h" // Fedora patch: memset() using std::memset; // --------------------------------------------------------------------------- CTexFont::CTexFont() { for( int i=0; i<256; ++i ) { m_CharU0[i] = 0; m_CharU1[i] = 0; m_CharV0[i] = 0; m_CharV1[i] = 0; m_CharWidth[i] = 0; } m_TexWidth = 0; m_TexHeight = 0; m_TexBytes = NULL; m_NbCharRead = 0; m_CharHeight = 0; } // --------------------------------------------------------------------------- CTexFont::~CTexFont() { if( m_TexBytes ) delete[] m_TexBytes; m_TexBytes = NULL; m_TexWidth = 0; m_TexHeight = 0; m_NbCharRead = 0; } // --------------------------------------------------------------------------- static int NextPow2(int _n) { int r = 1; while( r<_n ) r *= 2; return r; } // --------------------------------------------------------------------------- const char *g_ErrBadFontHeight = "Cannot determine font height while reading font bitmap (check first pixel column)"; CTexFont *TwGenerateFont(const unsigned char *_Bitmap, int _BmWidth, int _BmHeight) { // find height of the font int x, y; int h = 0, hh = 0; int r, NbRow = 0; for( y=0; y<_BmHeight; ++y ) if( _Bitmap[y*_BmWidth]==0 ) { if( (hh<=0 && h<=0) || (h!=hh && h>0 && hh>0) ) { g_TwMgr->SetLastError(g_ErrBadFontHeight); return NULL; } else if( h<=0 ) h = hh; else if( hh<=0 ) break; hh = 0; ++NbRow; } else ++hh; // find width and position of each character int w = 0; int x0[224], y0[224], x1[224], y1[224]; int ch = 32; int start; for( r=0; rlmax ) lmax = l; } // A little empty margin is added between chars to avoid artefact when antialiasing is on const int MARGIN_X = 2; const int MARGIN_Y = 2; lmax += 16*MARGIN_X; // - Second, build the texture CTexFont *TexFont = new CTexFont; TexFont->m_NbCharRead = ch-32; TexFont->m_CharHeight = h; TexFont->m_TexWidth = NextPow2(lmax); TexFont->m_TexHeight = NextPow2(14*(h+MARGIN_Y)); TexFont->m_TexBytes = new unsigned char[TexFont->m_TexWidth*TexFont->m_TexHeight]; memset(TexFont->m_TexBytes, 0, TexFont->m_TexWidth*TexFont->m_TexHeight); int xx; float du = 0.4f; float dv = 0.4f; assert( g_TwMgr!=NULL ); if( g_TwMgr ) { if( g_TwMgr->m_GraphAPI==TW_OPENGL || g_TwMgr->m_GraphAPI==TW_OPENGL_CORE ) { du = 0; dv = 0; } else // texel alignement for D3D { du = 0.5f; dv = 0.5f; } } float alpha; for( r=0; r<14; ++r ) for( xx=0, ch=r*16; ch<(r+1)*16; ++ch ) if( y1[ch]-y0[ch]==h-1 ) { for( y=0; ym_TexBytes[(xx+x-x0[ch])+(r*(h+MARGIN_Y)+y)*TexFont->m_TexWidth] = (unsigned char)(alpha*256.0f); } TexFont->m_CharU0[ch+32] = (float(xx)+du)/float(TexFont->m_TexWidth); xx += x1[ch]-x0[ch]+1; TexFont->m_CharU1[ch+32] = (float(xx)+du)/float(TexFont->m_TexWidth); TexFont->m_CharV0[ch+32] = (float(r*(h+MARGIN_Y))+dv)/float(TexFont->m_TexHeight); TexFont->m_CharV1[ch+32] = (float(r*(h+MARGIN_Y)+h)+dv)/float(TexFont->m_TexHeight); TexFont->m_CharWidth[ch+32] = x1[ch]-x0[ch]+1; xx += MARGIN_X; } const unsigned char Undef = 127; // default character used as for undifined ones (having ascii codes from 0 to 31) for( ch=0; ch<32; ++ch ) { TexFont->m_CharU0[ch] = TexFont->m_CharU0[Undef]; TexFont->m_CharU1[ch] = TexFont->m_CharU1[Undef]; TexFont->m_CharV0[ch] = TexFont->m_CharV0[Undef]; TexFont->m_CharV1[ch] = TexFont->m_CharV1[Undef]; TexFont->m_CharWidth[ch] = TexFont->m_CharWidth[Undef]/2; } return TexFont; } // --------------------------------------------------------------------------- CTexFont *g_DefaultSmallFont = NULL; CTexFont *g_DefaultNormalFont = NULL; CTexFont *g_DefaultLargeFont = NULL; // Small font const int FONT0_BM_W = 211; const int FONT0_BM_H = 84; static const unsigned char s_Font0[] = { 127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0, 0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,0,0,0,255,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,255,0,255,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,0,0,255,255,0,0, 0,255,0,0,0,0,255,255,0,0,0,255,0,0,255,0,0,255,0,0,255,0,255,0,255,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,255,0,0,0,255,0,0,255,255, 255,0,0,255,255,255,0,0,0,0,0,255,0,255,255,255,255,0,0,255,255,0,0,255, 255,255,255,0,0,255,255,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,127,0,0,0,0,255,0,255,0,255,0,0,0,255,0,0,255,0,0,255,255,255,255, 0,255,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,255,0,255,0,0,0,0,255,0,0,255, 255,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,255, 255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,255,255,0,255,0,0,0,0,255,0,0,0,0,0, 0,0,255,0,255,0,0,255,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,255,0,0,0,0,0,0,255,255,255,255,255,255,255,0,255,0,0,0,255,0,0, 255,0,255,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,255,0,255,0,255,0,255, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0,0, 0,0,255,0,0,0,0,255,0,0,255,0,255,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0, 255,0,0,255,0,255,0,0,255,0,0,255,0,0,255,0,0,0,0,0,255,255,0,0,0,0,0,0, 0,0,0,255,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127,0,0,0,0,255,0,0,0,0,0,0,0,255,0,255,0,0,0,255,255,0,0,0,0,255,255,0, 255,0,255,255,0,0,0,255,255,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0, 0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,0,0,255,0,0,0,255,255,0,0,255,0,0,255,0,255,255,255,0,0,255,255,255, 0,0,0,0,255,0,0,0,255,255,0,0,0,255,255,255,0,0,255,0,0,255,0,0,0,255,255, 0,0,0,255,255,255,255,255,255,0,0,0,0,255,255,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,255,0,0,0,0,0,255,255,255,255,255, 255,0,0,0,255,255,0,0,0,0,0,255,0,255,0,0,255,0,255,0,0,255,0,0,0,0,255, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,255,0,0,0,0,0,255,0, 0,255,0,0,255,0,0,255,0,0,0,255,0,0,0,0,0,0,255,0,255,255,255,255,255,0, 0,0,255,0,255,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0, 255,0,255,0,0,0,0,255,0,255,0,0,255,0,255,0,0,255,255,0,0,0,255,0,0,0,0, 255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,255,0, 0,255,0,0,255,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,255,0, 0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,0,255,0,0,255,0,0,255,0,0,0,255,255, 0,0,0,255,255,255,255,255,255,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,255,0,0,0,0,0,0,255,0,0,255,0,0,255, 255,255,255,0,0,0,0,255,0,0,0,255,255,0,0,0,255,255,0,0,255,0,0,255,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,255, 255,0,0,255,255,255,0,255,255,255,255,0,255,255,255,0,0,0,0,0,255,0,255, 255,255,0,0,0,255,255,0,0,255,0,0,0,0,0,255,255,0,0,0,255,255,0,0,0,255, 0,0,255,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,0,127,0,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,127,0,127,127,127,127,127,0,127,0,127,127,0,127,127,127,0,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,0,127,127,127,0,127,0,127, 127,127,0,127,127,127,127,0,127,127,127,0,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,0,127,127,127,127,0,127,127,0,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,255,0,0,0,255,255,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,255,255,255,0,0,0,0,0, 255,255,0,0,0,255,255,255,0,0,0,0,0,255,255,255,0,0,255,255,255,255,0,0, 0,255,255,255,255,255,0,255,255,255,255,255,0,0,0,255,255,255,0,0,255,0, 0,0,0,255,0,255,255,255,0,0,255,255,0,255,0,0,0,255,0,255,0,0,0,255,255, 0,0,0,255,255,0,255,0,0,0,0,255,0,0,0,255,255,255,0,0,0,255,255,255,255, 0,0,0,0,255,255,255,0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,255,255, 255,255,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,255,0,0,255,0, 255,0,0,255,0,255,0,0,0,255,0,255,255,255,255,0,255,0,0,255,0,0,0,0,255, 0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,255,0, 0,0,255,0,0,0,0,255,255,0,0,0,255,0,0,255,0,0,0,255,0,0,0,255,0,255,0,0, 0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,255, 0,0,255,0,0,0,0,255,0,255,0,0,255,0,0,255,0,0,0,255,255,0,0,0,255,255,0, 255,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255, 0,0,255,0,0,0,255,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,255,0, 0,0,0,255,0,255,0,0,255,0,0,255,0,255,0,0,255,0,0,255,0,255,0,0,0,0,0,255, 0,255,0,0,0,255,0,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,127,255,0,0,255,255,0,255,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0, 0,0,0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,0,255,0,255,0,255,0,0,0,255,0,0, 0,255,0,255,0,255,0,255,0,255,0,255,0,0,255,0,255,0,0,0,0,0,255,0,255,0, 0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,0,0,0,0,255,0,0, 0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,255,0,255,0,255,0,0,255,255, 0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,0,255,0,0,0,255,0,255,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,255,0,255,0,255, 0,0,255,0,0,255,0,0,255,255,255,255,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255, 0,255,255,255,255,0,0,255,255,255,255,0,0,255,0,0,255,255,255,0,255,255, 255,255,255,255,0,0,255,0,0,0,0,255,0,255,255,0,0,0,0,255,0,0,0,255,0,255, 0,255,0,255,0,255,0,0,255,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,255,0,255, 0,0,0,0,0,255,0,255,255,255,255,0,0,0,255,255,255,0,0,0,0,255,0,0,0,255, 0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,255,0,255,0,255,0,0,255,255,0,0,0, 0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,255,0,255,0,255,0,255,255,255, 255,255,255,0,255,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0, 0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,0,0,255, 0,255,0,255,0,0,0,255,0,0,0,255,0,0,255,0,0,255,0,255,0,0,0,255,255,0,255, 0,0,0,0,0,255,0,255,255,255,255,0,0,255,0,0,0,0,0,255,0,255,0,255,0,0,0, 0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,255, 0,255,0,255,0,0,255,255,0,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255, 0,0,255,255,255,0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,0,255,0,0,0,255,0, 255,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0, 0,0,255,0,0,255,0,0,0,0,255,0,255,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0, 255,0,255,0,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,0,0,0,255,0,0,0,255, 0,0,255,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255, 255,0,0,0,0,255,0,0,0,255,0,0,255,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,255, 0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,127,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,255,255,255,255,0,0,0,0,255, 255,255,0,0,255,255,255,255,0,0,0,255,255,255,255,255,0,255,0,0,0,0,0,0, 0,255,255,255,255,0,255,0,0,0,0,255,0,255,255,255,0,255,255,0,0,255,0,0, 0,255,0,255,255,255,255,255,0,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,255,255, 255,0,0,0,255,0,0,0,0,0,0,0,255,255,255,0,0,0,255,0,0,0,255,0,255,255,255, 255,0,0,0,0,255,0,0,0,0,255,255,255,255,0,0,0,0,255,255,0,0,0,0,255,0,0, 0,255,0,0,255,0,0,255,0,0,0,255,0,0,0,255,255,255,255,0,255,0,0,0,0,255, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0, 0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, 0,0,0,0,0,255,255,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,0, 127,127,127,127,127,127,0,127,127,127,0,127,127,127,0,127,127,127,127,127, 0,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0, 127,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,0,127, 127,0,127,127,127,0,127,127,0,127,127,127,127,127,0,127,127,127,127,127, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,0,255,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,255,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,255,0,0,0,0,0,0,0,255,0,0, 0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0, 255,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,4,4, 4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0, 0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0, 0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,4,4,4,4,12,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127,0,0,0,0,0,255,255,0,0,255,255,255,0,0,0,255,255,0,0,255,255,255,0,0, 255,255,0,0,255,255,255,0,255,255,255,0,255,255,255,0,0,255,0,255,255,0, 255,0,0,255,0,255,0,255,255,255,0,255,255,0,0,255,255,255,0,0,0,255,255, 0,0,255,255,255,0,0,0,255,255,255,0,255,0,255,255,255,255,0,255,255,0,255, 0,0,255,0,255,0,0,0,255,0,255,0,0,255,0,0,255,0,255,0,255,0,255,0,0,0,255, 0,255,255,255,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,4,4,4,4,0, 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0, 255,0,255,0,0,255,0,255,0,0,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0, 0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,255,0,0,255,0,255,0,0,255,0,0, 255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,255,0, 255,0,0,0,255,0,0,255,0,0,255,0,0,255,0,255,0,0,255,0,0,255,0,0,255,0,0, 255,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,255, 0,0,255,0,0,255,4,4,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,127,0,0,0,0,0,255,255,255,0,255,0,0,255,0,255,0,0,0,255,0,0,255,0, 255,255,255,255,0,255,0,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255, 255,0,0,0,255,0,255,0,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0, 0,255,0,255,0,0,255,0,255,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0,255,0,255, 0,0,255,0,255,0,255,0,255,0,0,255,0,0,0,255,0,255,0,0,0,255,0,0,255,0,0, 0,0,255,0,0,0,0,255,0,255,0,0,255,255,0,0,0,255,255,4,255,255,0,4,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,255,0,0,255,0,255,0, 0,255,0,255,0,0,0,255,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,255,0,255,0, 0,255,0,255,0,0,255,0,255,0,255,0,0,255,0,255,0,0,255,0,0,255,0,255,0,0, 255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,0,0,255,0,255,0, 0,255,0,0,255,0,0,255,0,255,0,0,0,255,255,0,255,255,0,0,0,255,0,0,0,255, 0,255,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255, 255,255,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 0,255,255,255,0,255,255,255,0,0,0,255,255,0,0,255,255,255,0,0,255,255,255, 0,255,0,0,0,255,255,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255, 0,255,0,0,255,0,0,255,0,255,0,0,255,0,0,255,255,0,0,255,255,255,0,0,0,255, 255,255,0,255,0,0,255,255,255,0,0,255,0,0,255,255,255,0,0,0,255,0,0,0,0, 255,0,0,0,255,0,0,255,0,255,0,0,0,255,0,0,0,255,255,255,0,0,255,0,0,0,255, 0,0,0,255,0,0,0,0,0,0,0,0,0,0,20,0,255,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255, 0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,4,4,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,255,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,0,127,127,127,127,0, 127,127,127,127,0,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127, 127,0,127,127,127,127,0,127,127,127,127,0,127,0,127,127,0,127,127,127,127, 0,127,0,127,127,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127, 0,127,127,127,127,0,127,127,127,127,0,127,127,0,127,127,127,0,127,127,0, 127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,0,127,127,127,127,127,0,127,127,127,0,127,127,127,0,127,127,127, 0,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0, 255,255,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, 0,255,0,0,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,255,255,255,0,0,255,255,255,255,255,255,255,0,0,0,0,0,0,255,255,0,0,0, 0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,255,255,0,0, 0,255,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,255,255,255,255,255,255,255, 0,0,255,255,255,255,255,255,255,0,255,255,255,255,0,0,255,255,255,255,255, 255,255,0,0,255,255,255,255,255,255,255,0,255,0,0,255,255,0,255,0,0,255, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,255,255,255,255,0,255, 0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,0, 0,255,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,255,255,255,255,0,255,255,255,255,255,0,0,0,0,0,0,255,0,0,255,0,255, 0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0, 255,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,255,255, 0,0,255,0,255,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255, 0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 255,255,255,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255,0,0,255,0,255,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,255,0,255,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0, 0,255,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,255,0, 255,255,255,0,255,0,0,0,255,255,0,255,255,0,0,0,255,0,0,0,0,0,255,0,255, 255,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,255,255,0,255,0,255, 255,0,255,255,0,0,0,255,255,255,0,0,255,0,0,255,0,0,0,255,255,255,255,0, 0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,255,0,0,255,0,0,255,0, 0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,255,255,255,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,255, 0,0,255,0,0,255,0,0,0,0,0,255,0,255,0,0,255,0,0,0,255,0,0,0,0,0,255,0,0, 0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,0,0,255,255,255,0,255,255,255,255,0,255,255,255,255,255, 255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,255,255, 255,255,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,255, 0,0,255,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,255,0,255,0,0,255,0,0,255,0,0,0,0,0,255,0,0,255,0,255,0,0,0,255, 0,0,0,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,255,0,0,255,0,0,0,0,0, 255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,127,0,255,255,255,0,0,255,255,255,255,255,255,255,0,0,255, 0,255,0,0,0,0,255,0,255,0,255,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,255,0,0,0,255,255,0,255,255,0,0,255,255,255,255,0,0,0,0,0,0,255, 255,255,255,255,255,255,0,0,255,255,255,255,255,255,255,0,255,255,255,255, 0,0,255,255,255,255,255,255,255,0,0,255,255,255,255,255,255,255,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,255,255,0,0,0,0,0,255,255,0,255,255,255,0,0,255,255,255,255,255, 255,255,0,255,255,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,255,0,0,0,255,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,0,127,127, 127,127,0,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,0, 127,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,0,127,127,0,127,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,0,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,0,127,0,127, 127,127,0,127,127,127,0,127,127,127,0,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 0,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,127,127,127,0,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,255,0,0,0,0,0,0,0,255,0, 0,0,255,0,255,0,0,255,255,255,0,0,255,0,255,0,0,0,255,255,255,255,0,0,255, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,255,255,255,0,255,255,255,0,0,255,0,0,0,0,0,0, 0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,255,0,0,0,0,0,0,0,0,255, 0,0,255,0,0,0,0,0,255,0,0,0,255,0,0,0,255,255,255,0,0,255,0,0,0,0,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, 0,255,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,255,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,255, 0,0,0,0,255,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,255,0,255, 0,0,0,0,0,0,0,0,0,0,255,255,0,255,0,0,255,0,0,0,0,0,0,255,255,0,255,0,0, 0,0,0,255,255,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127,0,0,0,0,0,255,0,0,255,255,255,0,0,255,0,0,0,0,255,255,255,0,0,0,255, 0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,255,0,0,255,255,0,0,255,255,0,255, 0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,255,255,255,0,0,255,0,0,0,0,0, 0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,255, 255,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,255,0,255,0,255,0,0,0,255, 0,255,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,0,0,255,0,255,0,255,0,0,255,255,255,0,0,0,255,0,255, 0,0,0,0,255,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,255,0,255,0,0,0,0,255,0, 255,255,0,255,0,255,0,0,0,255,255,255,255,255,0,0,0,0,255,0,255,0,0,255, 0,255,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,0,0,255,255,255,0,255,255, 0,0,0,0,0,0,255,0,0,255,0,255,255,0,255,0,0,255,0,0,0,0,0,0,0,255,255,255, 0,255,255,0,0,0,255,0,255,0,0,255,255,0,0,255,255,0,0,0,255,0,255,0,255, 255,0,0,255,255,0,255,0,255,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0, 255,0,255,0,255,0,0,0,255,0,0,0,0,255,255,255,0,0,0,255,255,255,0,0,0,0, 255,0,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0, 0,0,0,255,0,255,255,0,255,0,255,255,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,255,0,0,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0,255,0,255,0,255,0,0,0,0,255, 0,0,0,0,255,0,0,0,255,0,255,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 0,255,0,255,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0, 255,255,255,0,0,0,0,0,0,255,0,0,255,255,0,0,255,0,0,0,0,0,255,0,255,0,0, 0,0,0,0,255,0,0,0,0,255,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0,0,255,0,255,255,255,255,0,0,0,255, 0,0,0,255,0,0,0,0,255,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0, 0,0,0,255,0,0,255,255,255,0,255,255,255,255,0,0,0,0,0,0,0,0,0,255,0,0,0, 255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,255,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,255, 255,0,0,255,0,0,0,0,255,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0, 0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,127,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,127,127,127,127,0,127,0,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,0,127,127,127,127, 0,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,0,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 127,0,127,127,127,0,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127, 127,127,0,127,127,127,0,127,127,127,0,127,127,127,127,0,127,127,127,127, 0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,255,0, 0,0,0,0,255,0,0,0,0,0,0,255,0,255,0,0,0,255,0,255,255,0,0,0,255,0,0,255, 0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255, 0,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,0,0,255,0,0,255,0,255,0,255, 0,255,0,0,0,0,0,0,0,0,0,255,0,255,255,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0, 0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,255,0,0,0,0,255,0,255,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,255, 0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,127,0,0,255,255, 0,0,0,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,0,255,255, 0,0,0,0,0,255,255,0,0,0,0,0,255,255,255,255,255,0,0,0,255,255,255,0,0,255, 255,255,255,255,0,255,255,255,255,255,0,255,255,255,255,255,0,255,255,255, 255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255, 255,255,0,0,0,255,0,0,0,0,255,0,0,0,255,255,255,0,0,0,0,0,255,255,255,0, 0,0,0,0,255,255,255,0,0,0,0,0,255,255,255,0,0,0,0,0,255,255,255,0,0,0,0, 0,0,0,0,0,0,0,0,255,255,255,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0, 255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,0,255,0,0, 255,0,127,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,0,255, 255,0,0,0,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,255,0,255,0,0,0,0,0,255, 0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255, 0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,255,0,0,0,255,0, 0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, 255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,255,0,0,0, 0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,255, 0,0,255,255,255,0,0,255,0,0,255,0,127,0,255,0,0,255,0,0,0,255,0,0,255,0, 0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0, 0,0,255,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0, 0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,0,0,0, 0,255,0,255,0,255,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,255,0,0,0,255, 0,255,0,0,0,255,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0, 255,0,255,0,0,0,0,255,0,0,255,0,255,0,0,255,0,0,255,0,255,0,255,0,0,127, 0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0, 0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,255,255,255,255,0,255,0,0,0, 0,0,0,255,255,255,255,0,0,255,255,255,255,0,0,255,255,255,255,0,0,255,255, 255,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,255,255,0,0,255, 0,255,0,0,255,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0, 0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,255,0,255,0,0,255, 0,0,255,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0, 255,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,0,255,0,0,255,0,127,255,255, 255,255,255,255,0,255,255,255,255,255,255,0,255,255,255,255,255,255,0,255, 255,255,255,255,255,0,255,255,255,255,255,255,0,255,255,255,255,255,255, 0,0,255,255,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255, 0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,0,0, 0,0,255,0,255,0,0,0,255,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0, 255,0,255,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255, 0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,255,0,255,0,0,255,0,127,255,0, 0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0, 0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,255,0,0,0,0,0,255,0,0,0,255,0,255, 0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0, 0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,0,255,0,0,255,0,0,0,255, 0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, 0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,0,0,255,0,0,255,0,0,0,0,255,0,255, 0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,255, 255,0,0,255,0,0,255,0,127,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0, 0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,255, 255,255,255,0,0,0,255,255,255,0,0,255,255,255,255,255,0,255,255,255,255, 255,0,255,255,255,255,255,0,255,255,255,255,255,0,255,255,255,0,255,255, 255,0,255,255,255,0,255,255,255,0,255,255,255,255,0,0,0,255,0,0,0,0,255, 0,0,0,255,255,255,0,0,0,0,0,255,255,255,0,0,0,0,0,255,255,255,0,0,0,0,0, 255,255,255,0,0,0,0,0,255,255,255,0,0,0,0,255,0,0,0,255,0,255,0,255,255, 255,0,0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,255,255,255,255, 0,0,0,255,255,255,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,255,0,0,127,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,0,127, 127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 0,127,127,127,0,127,127,127,0,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,127,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,255,255,0,255,0, 0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0, 0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,255,255,0,255, 0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,255,255,0,255,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,255, 0,0,0,0,255,0,0,0,255,0,255,0,255,0,255,255,0,0,255,0,255,0,0,255,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,255,0,255,0,0,255,0, 255,0,0,255,0,255,0,255,0,255,255,0,255,0,0,255,255,0,255,0,255,255,0,0, 0,255,0,0,0,0,255,0,0,0,255,0,255,0,255,0,255,255,0,255,0,0,255,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,255,0,255,0,0,255,0,255,0, 0,0,255,0,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,127,0,255,255,0,0,0,255,255,0,0,0,255,255,0,0,0,255,255,0,0,0,255, 255,0,0,0,255,255,0,0,255,255,255,0,255,255,0,0,0,255,255,0,0,255,255,0, 0,0,255,255,0,0,0,255,255,0,0,0,255,255,0,0,0,255,0,255,0,0,255,0,0,255, 0,0,0,0,255,0,255,255,255,0,0,0,255,255,0,0,0,255,255,0,0,0,255,255,0,0, 0,255,255,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,255,0,0,255, 0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,0,255,0,255,255,255, 0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,255,0,0,0, 0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,255, 0,255,0,0,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,0,255, 0,255,0,0,255,0,0,255,0,0,255,255,255,0,255,0,0,255,0,255,0,0,255,0,255, 0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,0,255,255,255,255,255, 0,255,0,0,255,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255, 0,0,255,0,255,0,0,255,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,255,255,255,0,0,255,255,255,0,0,255,255,255,0,0,255,255,255, 0,0,255,255,255,0,0,255,255,255,0,0,255,255,255,255,255,255,0,255,0,0,0, 255,255,255,255,0,255,255,255,255,0,255,255,255,255,0,255,255,255,255,0, 0,255,0,255,0,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0, 255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,0,0,0,0,0,0,0,255, 0,255,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,0, 255,0,255,0,0,255,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,127,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0, 255,0,255,0,0,255,0,255,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0, 0,255,0,0,0,0,255,0,0,0,0,0,255,0,255,0,0,255,0,0,255,0,255,0,0,255,0,255, 0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255,0, 0,255,0,0,0,0,255,0,0,0,255,255,0,0,255,0,255,0,0,255,0,255,0,0,255,0,255, 0,0,255,0,255,0,0,255,0,0,255,0,255,0,0,255,0,0,255,0,0,255,0,255,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,255,255,255,0,0,255,255,255,0,0,255, 255,255,0,0,255,255,255,0,0,255,255,255,0,0,255,255,255,0,0,255,255,0,255, 255,255,0,0,255,255,0,0,255,255,255,0,0,255,255,255,0,0,255,255,255,0,0, 255,255,255,0,0,255,0,255,0,0,255,0,0,255,0,0,255,255,0,0,255,0,0,255,0, 0,255,255,0,0,0,255,255,0,0,0,255,255,0,0,0,255,255,0,0,0,255,255,0,0,0, 0,0,0,0,0,0,0,255,255,255,0,0,0,255,255,255,0,0,255,255,255,0,0,255,255, 255,0,0,255,255,255,0,0,0,255,0,0,0,255,255,255,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,0,127,127,127,127,0,127,127, 127,127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,0,127,127,127,127,0,127,127,127,127,0, 127,127,127,127,0,127,127,127,127,0,127,127,0,127,0,127,127,0,127,127,0, 127,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,0, 127,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127, 127,127,0,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,0,127, 127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // Normal font const int FONT1_BM_W = 253; const int FONT1_BM_H = 106; static const unsigned char s_Font1[] = { 127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,255, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0, 0,255,0,255,0,0,0,0,0,255,0,0,0,0,255,255,0,0,0,0,255,0,0,0,0,0,255,255, 255,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255,0,255,0,255,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,255,255,255,0,0,0,0,0, 255,0,0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,0,0,0,255,0,0,255, 255,255,255,255,255,0,0,0,255,255,255,0,0,255,255,255,255,255,255,0,0,255, 255,255,255,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,127,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,255,255, 255,0,0,255,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255, 0,0,0,0,255,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,255,255,255,0,0,0,255,0,0,0,0,255,0, 255,0,0,0,0,255,0,0,0,0,255,255,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255, 0,0,255,0,255,0,255,0,255,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,255,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,255,0,0,255,0,255,0,255,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,255,0,0,0,0,0,0,255,0,0,0,0, 0,0,0,0,0,0,255,0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,0,255, 0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,255, 0,0,0,0,255,0,255,0,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,255,0,255,0,0,0, 0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0, 0,255,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255,255,255,255,255,0,0,255,255, 255,255,255,0,0,0,0,0,0,255,0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255, 0,0,0,255,0,0,0,0,0,0,255,255,0,0,0,0,255,255,255,255,255,255,0,0,0,0,255, 255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,255,0,0, 0,0,0,0,0,0,0,0,255,0,255,0,0,0,0,0,255,255,0,0,0,0,255,255,0,0,255,0,0, 255,255,0,0,0,255,255,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0, 255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,255,255,0,0,255,0,0,0,255, 0,0,0,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,255,255,255, 0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,255,255,0, 0,0,0,0,0,0,255,0,255,0,0,255,0,255,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0, 0,0,0,255,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,0,0,255,255, 255,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,255, 0,0,0,0,0,0,0,0,255,0,255,255,255,255,255,255,0,0,0,0,0,0,255,0,255,0,0, 0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,255,255,255,255,255,0,0,0, 0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255,255,255,255,255,255,0,0,0,0,0,0,0, 0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,255,0,0,0,0, 0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,255,0,0,255, 0,255,0,0,0,255,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0, 0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,255, 0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0, 0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0, 0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,255,0,255,0,0,0,0,0,255,0,255,0,255,0,0,0,0,0,255,0,0,255,0,0,255,0,255, 0,0,0,255,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255, 0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,0, 255,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0, 255,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0, 0,0,255,0,0,0,255,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,255,0,0,0,0,0, 0,0,0,0,255,0,255,0,0,0,0,0,0,255,255,255,0,0,0,0,0,255,0,0,0,0,255,255, 0,0,0,255,255,255,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0, 0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,255,255, 255,0,0,0,255,255,255,255,255,0,255,255,255,255,255,255,0,0,255,255,255, 255,0,0,0,0,0,0,255,0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,255, 0,0,0,0,0,0,255,255,255,255,0,0,0,255,255,255,0,0,0,0,255,0,0,0,255,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,0, 127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,0,127,127,127,0,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,0,127,127,127, 127,0,127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,255,0,0,0,0,0,255,255,255,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,255, 255,255,255,0,0,0,0,0,0,0,255,0,0,0,0,255,255,255,255,255,0,0,0,0,255,255, 255,255,0,255,255,255,255,255,0,0,0,255,255,255,255,255,255,0,255,255,255, 255,255,0,0,0,255,255,255,255,0,0,255,0,0,0,0,0,255,0,255,255,255,0,0,255, 255,255,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,255,0,0,0,0,255,255,0,255, 255,0,0,0,0,255,0,0,0,255,255,255,255,0,0,0,255,255,255,255,255,0,0,0,0, 255,255,255,255,0,0,0,255,255,255,255,0,0,0,0,255,255,255,255,0,0,255,255, 255,255,255,255,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0, 0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,255,255,255, 255,255,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,255,255,0,0,0,0,255,255,0,0, 0,0,255,0,255,0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0, 0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,0, 0,255,0,0,0,0,0,255,0,255,0,0,0,255,0,0,255,0,0,0,0,0,255,255,0,0,0,0,255, 255,0,255,255,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,255, 0,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,255,0,0,255, 0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0, 0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,127,0,255,0,255,255,255,255,0,255,0,0,0,0,255,0,255,0,0,0,255,0,0, 0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0, 0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,255,0,0, 255,0,0,0,255,0,0,0,0,0,255,0,255,0,0,255,0,255,0,255,0,255,0,0,0,255,0, 255,0,0,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0, 255,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0, 0,255,0,0,0,255,0,0,255,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,0, 255,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,255,0,0, 0,255,0,0,255,0,0,0,255,0,255,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0, 0,0,0,255,0,0,255,0,0,0,0,0,255,0,255,0,255,0,0,0,0,255,0,0,0,0,0,255,0, 255,0,0,255,0,255,0,255,0,255,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0, 0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0, 255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,255,0,0,0,255,0,0,255,0,255, 0,0,255,0,0,0,0,255,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,255, 0,0,0,0,255,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,255,0,0,0,255,0,0,255,0,0,255,0,0,0,255, 0,0,255,255,255,255,255,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,255,255, 255,255,255,255,0,255,255,255,255,255,0,255,0,0,0,255,255,255,0,255,255, 255,255,255,255,255,0,0,255,0,0,0,0,0,255,0,255,255,0,0,0,0,0,255,0,0,0, 0,0,255,0,255,0,0,255,0,255,0,255,0,0,255,0,0,255,0,255,0,0,0,0,0,0,255, 0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,255,255,255,0,0,0,0,255,255, 255,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,0,255,0,0,0, 255,0,0,255,0,255,0,0,255,0,0,0,0,255,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255, 0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,255,0,0,0,255,0,0,255,0,0,255, 0,0,0,255,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,255, 0,0,0,0,0,255,0,255,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,255,255,0,0,255, 0,255,0,0,0,255,0,255,0,255,0,0,0,0,0,0,255,0,255,255,255,255,255,0,0,255, 0,0,0,0,0,0,255,0,255,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255, 0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,0, 255,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0, 0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,127,255,0,255,0,0,0,255,0,0,255,0,0,255,255,255,255,255,0,0,255,0,0,0, 0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0, 0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,255,0,0, 255,0,0,0,255,0,0,0,0,0,255,0,0,255,255,0,0,255,0,255,0,0,0,255,0,255,0, 255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,255,0,0,0,255, 0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,0,255,0,255, 0,0,0,0,0,255,255,0,0,0,255,255,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0, 0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,255,0,255,255,255,255, 255,255,0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0, 0,0,0,255,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0, 0,0,0,255,0,0,255,0,0,0,0,0,255,0,255,0,0,0,255,0,0,255,0,0,0,0,0,255,0, 0,0,0,0,0,255,0,255,0,0,0,0,255,255,0,0,255,0,0,0,0,255,0,0,255,0,0,0,0, 0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,255, 0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0, 0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0, 255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,255,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,255,255,255, 255,255,0,0,0,0,255,255,255,255,0,255,255,255,255,255,0,0,0,255,255,255, 255,255,255,0,255,0,0,0,0,0,0,0,255,255,255,255,255,0,255,0,0,0,0,0,255, 0,255,255,255,0,255,255,255,0,0,255,0,0,0,0,255,0,255,255,255,255,255,0, 255,0,0,0,0,0,0,255,0,255,0,0,0,0,255,255,0,0,0,255,255,255,255,0,0,0,255, 0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,255,0,0,0,0,255,0,0,255,255,255,255, 0,0,0,0,0,255,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0, 0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,255,255,255,255, 255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,255,255,255,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0,0,0,0,255,0,0, 255,255,255,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,127,127,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 0,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0, 0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,255, 0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0, 0,0,0,255,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,255,255,255,0,0,255,0,255,255, 255,0,0,0,255,255,255,255,0,0,255,255,255,255,255,0,0,255,255,255,255,0, 0,255,255,255,255,0,255,255,255,255,255,0,255,0,255,255,255,0,0,255,0,255, 255,0,255,0,0,0,255,0,255,0,255,255,255,255,0,255,255,255,0,0,255,0,255, 255,255,0,0,0,255,255,255,255,0,0,255,0,255,255,255,0,0,0,255,255,255,255, 255,0,255,0,255,0,0,255,255,255,0,255,255,255,255,0,255,0,0,0,0,255,0,255, 0,0,0,255,0,255,0,0,0,255,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,255, 255,255,255,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 0,0,0,0,0,0,255,0,255,255,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,255,0,255, 0,0,0,0,255,0,0,255,0,0,255,0,0,0,0,255,0,255,255,0,0,0,255,0,255,0,0,255, 0,255,0,0,255,0,0,255,0,255,0,0,0,255,0,0,0,255,0,255,255,0,0,0,255,0,255, 0,0,0,0,255,0,255,255,0,0,0,255,0,255,0,0,0,0,255,0,255,255,0,0,255,0,0, 0,0,0,255,0,0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,0,0,255, 0,0,255,0,255,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,0,255,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,0,255,0,0,0,0,255, 0,255,0,0,0,0,255,0,255,0,0,255,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0, 0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0, 0,0,255,0,255,0,0,0,255,0,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,255,0,255, 0,0,0,255,0,255,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,0,255, 0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,255,0,0,0,255,0,0,0, 255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0, 0,255,255,255,255,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,255,0,255, 255,255,255,255,255,0,0,255,0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255, 0,0,255,0,255,255,0,0,0,0,255,0,255,0,0,0,255,0,0,0,255,0,255,0,0,0,0,255, 0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255, 255,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,255,0,255,0,0,0,255,0,255,0,255, 0,255,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,0,0,255,255,0,0,0,0,0,0, 255,0,0,0,0,0,255,255,0,0,255,0,0,255,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,255,0,0,0,255,0,255,0, 0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,0,255,0,0,255, 0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,255,0,255,0,255,0,0,0,255,0,255, 0,0,0,255,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255, 0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,255,0,0,0,255,0,0,0,0,255,0, 0,255,0,255,0,0,0,255,0,255,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,255, 0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,255, 255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,255, 255,0,255,0,0,0,0,255,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,0,255,0, 255,0,0,255,0,255,0,0,255,0,0,255,0,255,0,0,0,255,0,0,0,255,0,255,0,0,0, 0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,255,255,0,255,0,0, 0,0,0,0,255,0,0,255,0,0,0,255,0,0,0,255,255,0,0,0,255,0,0,0,0,0,255,0,0, 0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0, 255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,255,255,255,255,0,255,255, 255,255,255,0,0,0,255,255,255,255,0,0,255,255,255,0,255,0,0,255,255,255, 255,0,0,0,255,0,0,0,255,255,255,0,255,0,255,0,0,0,0,255,0,255,0,0,255,0, 255,0,0,0,255,0,255,0,255,0,0,0,255,0,0,0,255,0,255,0,0,0,0,255,0,0,255, 255,255,255,0,0,255,255,255,255,255,0,0,0,255,255,255,0,255,0,255,0,0,0, 255,255,255,0,0,0,0,255,255,0,0,255,255,255,0,255,0,0,0,255,0,0,0,0,0,255, 0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,255,255,255,0,0,0,255, 0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255, 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0, 255,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,127,0,127,127,127,127,127,0, 127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,0,127,127,0,127,127,127,127,127,0,127,0,127,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,0,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 0,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,0,127,127, 127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,255,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0, 0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,255,0,255, 0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,127,0,0,255, 255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,255, 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0, 255,0,0,255,0,0,0,255,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,255,255,255, 0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,255,255, 255,255,255,255,255,255,0,255,255,255,255,255,255,0,0,0,255,255,255,255, 255,255,255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,0,255,0,0, 0,255,0,255,0,255,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,255,0,255,255,0,0,0,255,255,255,0,255,0,0,0,255,0,0,255,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255, 255,0,0,255,255,0,0,255,0,0,0,0,0,255,0,127,0,255,0,0,0,0,0,0,0,255,0,0, 0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 255,255,255,255,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,255,0,0,255,0,0, 255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0, 0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,255,0,255,0,0,0,255,0,255,0,255,0, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,0,0,255,255,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,127,255,0,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0, 0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0,0,0,255, 0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0, 0,0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255, 0,255,0,255,0,0,255,255,255,0,0,255,0,0,0,0,255,255,255,255,0,255,255,255, 0,0,0,0,255,0,0,0,0,0,0,0,255,0,255,255,255,255,0,0,255,0,0,0,255,0,0,127, 255,255,255,255,255,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0, 0,0,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255, 0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,0, 0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,255,0,0, 0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,255,0,255, 0,0,0,127,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,255, 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,255,255,0,0,255,0,0,255,255,0,0,0,255,255,0,0,0,255,255, 255,255,0,0,0,255,0,0,0,255,0,0,0,0,0,255,255,255,255,255,0,0,0,255,0,0, 0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0, 0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0, 0,0,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255, 0,0,0,255,0,0,0,0,0,255,0,0,0,0,127,255,255,255,255,255,255,0,0,0,255,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,255,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255, 0,0,255,0,255,0,0,255,0,0,0,0,0,0,255,0,0,255,0,0,0,255,0,0,0,0,0,255,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0, 0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 255,255,255,0,255,255,255,255,255,0,255,255,255,255,255,255,255,255,255, 255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,255, 0,255,0,0,0,0,255,255,255,255,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,255,0, 0,0,0,0,0,255,0,0,0,0,127,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,255,0,0,255,0,0,0, 0,0,0,255,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0, 0,255,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255, 0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0, 0,0,255,0,0,0,0,127,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,255,0, 0,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,255,0,0,255,0,255, 0,0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0, 0,0,255,0,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0, 0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,255,0,0,0,0,0, 0,0,255,0,0,0,0,127,0,0,255,255,255,255,0,0,0,255,255,255,255,255,255,255, 255,255,0,0,255,0,0,0,255,0,0,0,0,0,255,0,255,0,0,255,0,0,255,0,0,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,255,0, 0,0,255,255,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,255,255,255,255,255, 255,255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,0,255,255,255, 255,255,255,0,0,0,255,255,255,255,255,255,255,255,255,0,0,0,255,255,255, 255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 255,255,0,0,0,0,0,0,0,0,255,255,255,255,0,255,255,255,255,0,0,0,255,255, 255,255,255,255,255,255,255,0,255,255,255,255,0,0,0,0,255,0,0,0,0,127,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,127,127,0,127,127,0,127,127,127,127,127,127,0,127,127,127,127,0,127, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,0, 127,127,0,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127, 0,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,0,127,127, 127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,255,0,0,0, 0,0,255,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0, 255,0,0,0,0,255,255,255,255,0,0,255,0,0,255,0,0,0,0,0,255,255,255,255,0, 0,0,0,0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255, 255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,255, 255,255,0,0,0,255,255,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,255,255, 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,255,255,0,0,0,0,0,0, 0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,255, 255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, 0,0,0,0,255,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,255,255,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,255, 0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, 255,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,255,0,0,0,255,0,0, 0,0,0,0,0,0,0,255,255,0,0,0,255,0,0,0,0,0,0,255,255,0,0,0,0,255,0,0,0,0, 0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,127,0,0,0,0,0,255,0,0,0,0,255,255,255,255,0,0,255,0,0,0,0, 0,255,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0, 0,0,0,0,0,255,0,0,255,255,0,0,255,0,0,0,0,255,255,255,0,0,0,255,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,255,255,0,0,255,0,0,0,0,0,0,0,0, 0,0,255,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,255,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,255,0,255,255,255,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,0,0,255,0,0,0,255,0,255,0,0,255,0,0,0,0,0,255,0,0,0,255,0,0,0, 0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255,255,0,0,0,255,0,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,255,0,0, 0,255,0,255,0,0,0,0,255,0,0,0,0,0,0,255,255,255,255,0,0,0,0,255,0,255,0, 0,0,0,255,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255, 0,0,255,0,0,255,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255, 0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,255,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,255,255,255,255,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,255,0,0, 0,0,255,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,255, 0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,255,0,0,0, 0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0, 0,0,0,255,0,0,255,0,0,255,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,0,0,255,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, 255,255,255,0,0,255,255,255,255,0,0,255,255,255,0,0,0,0,0,0,0,0,0,255,0, 0,0,0,255,0,0,255,255,255,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,255,255, 0,255,0,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,255,255,0,0,0,0, 255,0,0,255,0,255,255,255,0,0,0,0,0,0,255,0,255,0,0,255,255,0,0,0,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,255,0,0, 0,255,0,255,0,0,0,255,255,255,255,255,0,0,0,255,0,0,255,0,0,0,255,255,255, 255,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0, 0,255,0,0,0,255,255,255,0,255,0,0,255,0,0,0,0,255,255,255,255,255,255,255, 0,255,255,255,0,255,0,0,255,255,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255, 0,0,0,0,255,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,0, 0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,255,0,0,0,0, 255,0,0,255,255,255,0,255,0,0,255,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0, 255,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255, 0,0,255,0,0,0,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0,0,0,0,0,0,0,255, 0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,255,0,0,255,0,0,0,0,0, 0,255,0,0,0,0,255,0,0,0,0,0,0,255,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,255,0,0,0,255,0,255, 0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0, 0,255,255,0,0,0,0,0,0,0,0,0,0,255,0,0,255,255,0,0,255,0,0,0,0,0,0,0,0,0, 0,255,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,255,0,0,0,255,255,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,255,0,0,0,0,255,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,255,0,0,255, 255,255,255,255,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,255,0,0,255,255,255, 255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,255,0,0,0,0,255,255,255,255,0,255,255,255,255,255,255,0,0,0,0, 0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255, 255,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0, 0,0,0,0,255,255,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,255,0,0,0, 0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,255,255,255,255,0,0,0,0,255, 0,0,0,0,0,0,255,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,255,255, 255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,255,255, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,0,255,0,255,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 127,127,0,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,0, 127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,0,127,127,127,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,127,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,255, 0,0,0,0,0,255,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,255,0,0,0,0,255,255,0, 0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,255,255,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255, 255,0,0,0,0,0,0,0,255,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,255,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,255,0,0,0, 255,0,255,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,255,0, 0,0,255,0,0,255,0,0,0,255,0,0,0,255,0,0,255,0,0,255,255,0,255,0,0,0,0,0, 0,0,0,0,0,255,0,255,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0, 0,255,0,0,255,0,0,0,0,0,255,0,255,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,255, 0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,255,0,0,0,0,0,0,0,255,0, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0, 0,0,0,0,0,0,255,255,255,255,255,255,255,0,0,0,255,255,255,255,0,255,255, 255,255,255,255,0,255,255,255,255,255,255,0,255,255,255,255,255,255,0,255, 255,255,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255, 255,0,0,255,255,255,255,0,0,0,255,255,0,0,0,0,255,0,0,0,255,255,255,255, 0,0,0,0,0,255,255,255,255,0,0,0,0,0,255,255,255,255,0,0,0,0,0,255,255,255, 255,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255, 0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,127,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,0, 255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255, 0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, 0,0,0,255,0,0,255,255,0,0,0,0,255,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0, 255,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,255,0,0,0, 0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,255,0,0,0,255,0,0,255, 0,0,0,0,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,127,0,0,255,0,255,0,0,0, 0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255, 0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0, 255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,255,0,255,0,255,0,0,0,255,0,255, 0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0, 0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,0,255, 0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0, 0,0,255,0,0,255,0,0,0,255,0,0,255,255,255,255,255,0,0,255,0,0,0,255,0,0, 0,0,0,0,0,0,0,0,0,127,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0, 255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0, 0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0, 255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0, 0,255,0,0,0,0,255,0,255,0,255,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0, 0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0, 0,255,0,0,0,255,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,255,0,0,0,0,0,255, 0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,255,0, 255,0,0,0,255,0,0,0,0,255,0,255,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, 0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,255,255,255,255, 255,0,255,0,0,0,0,0,0,255,255,255,255,255,255,0,255,255,255,255,255,255, 0,255,255,255,255,255,255,0,255,255,255,255,255,255,0,0,255,0,0,0,255,0, 0,0,255,0,0,0,255,0,0,255,255,255,255,0,0,255,0,255,0,0,255,0,0,255,0,255, 0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0, 0,0,0,255,0,255,0,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,0,255,0,0, 0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,0,0, 0,0,0,0,0,0,0,0,127,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0, 255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, 255,255,255,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0, 0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0, 0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,255,0,255,0,0,0,0,0,0,255,0,255,0, 0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0, 0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,255,0,255,0,0,0,0,0,255, 0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0,255, 0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,127,0,255, 255,255,255,255,0,0,0,255,255,255,255,255,0,0,0,255,255,255,255,255,0,0, 0,255,255,255,255,255,0,0,0,255,255,255,255,255,0,0,0,255,255,255,255,255, 0,0,0,255,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0, 0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255, 0,0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,255,0,255,0,0,0,0,0,0,255,0,255, 0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0,0,0,0,255,0,255,0,0,0, 0,0,0,255,0,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,0, 255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0, 255,0,0,0,0,255,255,255,255,255,0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0, 127,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0, 0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,255,0,0,0,255,0,0, 0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255, 0,0,0,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0, 255,0,0,0,0,255,255,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255, 0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,0,255,0,0,0,0,255,0,0, 0,255,0,0,0,255,0,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0, 0,255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0, 0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,127,255,0,0,0,0,0,255,0,255,0,0,0, 0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255,0,0,0,0,0,255,0,255, 0,0,0,0,0,255,0,255,0,0,0,0,255,255,255,255,255,0,0,0,255,255,255,255,0, 255,255,255,255,255,255,0,255,255,255,255,255,255,0,255,255,255,255,255, 255,0,255,255,255,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255, 0,255,255,255,0,0,255,255,255,255,0,0,0,255,0,0,0,0,255,255,0,0,0,255,255, 255,255,0,0,0,0,0,255,255,255,255,0,0,0,0,0,255,255,255,255,0,0,0,0,0,255, 255,255,255,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255, 255,255,255,0,0,0,0,0,255,255,255,0,0,0,0,0,255,255,255,0,0,0,0,0,255,255, 255,0,0,0,0,0,255,255,255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,0,0,0,0,255,0, 255,255,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,0,127,127,127,0,127,127, 127,0,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,255,0,0,0,0,0,0,255,0,0, 0,0,255,255,0,0,0,255,255,0,255,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,255,255,0,0, 0,0,0,0,0,0,0,0,255,0,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0, 255,0,0,255,0,0,0,0,0,0,0,0,0,255,0,0,0,0,255,255,0,0,0,0,0,255,255,0,255, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0, 0,255,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,255,0,0,0,0,255,0,0,0,0,255, 0,0,255,0,255,0,255,255,0,0,0,255,0,0,255,0,0,255,0,0,255,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,255,0,0, 0,255,0,0,255,0,0,0,255,0,255,0,255,0,255,255,0,255,0,0,255,0,255,0,0,0, 255,0,255,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,255, 0,255,255,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,0,0,0,0,0,0,255,0,0,0,0,255,0,0,255,0,0,0,255,0,0,255,0,0,0,0,255,0, 0,0,255,0,0,0,0,0,0,0,255,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127,0,255,255,255,0,0,0,255,255,255,0,0,0,255,255,255,0,0,0,255,255,255, 0,0,0,255,255,255,0,0,0,255,255,255,0,0,0,255,255,255,0,0,255,255,0,0,0, 0,255,255,255,255,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,255,255, 255,255,0,0,0,255,255,255,255,0,0,0,255,0,255,0,0,255,0,0,255,0,0,255,255, 0,255,0,0,255,0,255,255,255,0,0,0,255,255,255,255,0,0,0,255,255,255,255, 0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0, 0,0,0,255,0,0,0,0,0,0,255,255,255,255,0,0,255,0,0,0,0,255,0,255,0,0,0,0, 255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,255,0,255,0,255,255, 255,0,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,255,0,0,0,0,0, 255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255, 255,0,0,255,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0, 0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,255,0,0,255,0,0,255,0,0,0,0,0,0,255, 0,255,255,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255, 0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,255, 0,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255, 0,255,0,0,0,255,0,255,255,0,0,0,255,0,255,0,0,0,255,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,127,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0, 255,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0,0, 255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,255, 0,0,255,0,0,255,0,0,255,255,255,255,255,0,255,0,0,0,0,255,0,255,0,0,0,0, 255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0, 255,0,0,0,0,0,0,0,0,0,0,255,0,0,0,255,0,255,0,255,0,0,0,0,255,0,255,0,0, 0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,255,0,0,255,0,0,0, 0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,255,255,255,255,0,0, 255,255,255,255,0,0,255,255,255,255,0,0,255,255,255,255,0,0,255,255,255, 255,0,0,255,255,255,255,0,0,255,255,255,255,255,255,255,255,255,0,255,0, 0,0,0,0,255,255,255,255,255,255,0,255,255,255,255,255,255,0,255,255,255, 255,255,255,0,255,255,255,255,255,255,0,0,255,0,255,0,0,255,0,0,255,0,255, 0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255, 0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,255,255,255,255, 255,255,0,255,0,0,255,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255, 0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,255,0,0,255,0,0,0,0,255,0,0,255, 0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255,0,0,0,255,0,255,0,0,0,255,0,255, 0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255, 0,0,0,0,0,0,255,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0,0,255,0,0,0,0,0, 0,255,0,0,0,0,0,0,0,255,0,255,0,0,255,0,0,255,0,255,0,0,0,0,255,0,255,0, 0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0, 0,0,0,255,0,255,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,255,0,255,0,0,0,255,0,255, 0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255, 0,255,0,0,255,0,0,0,0,255,0,0,255,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,255, 0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255,0,255,0,0,0,255, 0,255,0,0,0,255,0,255,0,0,0,255,255,0,0,0,255,0,255,0,0,0,0,0,255,0,0,0, 0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,0,255,0,255, 0,0,255,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0, 255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0,255,0,0,0,0,255,0, 0,0,0,0,255,0,0,0,0,0,255,0,0,0,255,0,0,255,0,0,0,255,255,0,255,0,0,0,255, 255,0,255,0,0,0,255,255,0,255,0,0,0,255,255,0,0,0,255,0,0,0,255,0,0,0,0, 255,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,255,255,255,255,0,0,255, 255,255,255,0,0,255,255,255,255,0,0,255,255,255,255,0,0,255,255,255,255, 0,0,255,255,255,255,0,0,255,255,255,0,0,255,255,255,0,0,0,255,255,255,255, 0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,255, 255,255,255,0,0,0,255,0,255,0,0,255,0,0,255,0,0,255,255,255,255,0,0,255, 0,0,0,0,255,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,255,255,255, 255,0,0,0,255,255,255,255,0,0,0,255,255,255,255,0,0,0,0,0,0,255,0,0,0,0, 0,255,255,255,255,0,0,0,0,255,255,255,0,255,0,0,255,255,255,0,255,0,0,255, 255,255,0,255,0,0,255,255,255,0,255,0,0,0,255,0,0,0,255,255,255,255,255, 0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0, 0,255,0,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,255,0,0,0,0,255,0,0,0,0,0,0,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 127,127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,0,127,0,127,127,0,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // Normal font anti-aliased const int FONT1AA_BM_W = 264; const int FONT1AA_BM_H = 106; static const unsigned char s_Font1AA[] = { 127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0, 0,0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0, 59,241,97,206,166,0,0,0,0,0,0,0,0,0,0,0,0,0,168,34,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,251,89,0,0,89,255,125,89,255,125,0,0,0,0, 7,199,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0, 0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21,59,238,42, 206,125,0,0,0,0,7,199,34,89,166,0,0,0,0,168,34,0,0,0,175,255,255,166,0, 0,7,202,89,0,0,0,0,59,245,255,251,89,0,0,0,59,238,34,0,12,232,89,0,0,89, 247,34,0,59,245,206,199,124,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,7,202,89,0,12,235,255,247,34,0,0,0,0,12,232,89,0,0,12,235, 255,255,251,89,0,7,206,255,255,255,125,0,0,0,0,138,251,89,0,0,59,245,255, 255,255,251,89,0,0,89,255,255,166,0,89,255,255,255,255,255,201,0,0,59,245, 255,255,125,0,0,12,235,255,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255,255,255,247,34,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0, 0,0,0,0,0,127,0,0,0,0,0,138,225,21,59,238,34,175,125,0,0,0,0,59,192,0,172, 89,0,0,59,245,255,255,251,89,89,247,34,12,228,34,0,138,166,0,0,0,0,12,235, 125,0,175,225,21,0,0,59,238,34,0,138,201,0,0,0,0,175,166,0,0,0,89,255,201, 0,0,0,0,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,215,21,0,175, 166,0,138,201,0,0,7,206,255,251,89,0,0,59,192,0,0,138,247,34,59,192,0,0, 89,251,89,0,0,59,245,251,89,0,0,59,241,89,0,0,0,0,0,89,247,34,0,0,0,0,0, 0,0,7,206,166,0,7,206,125,0,89,247,34,7,206,166,0,138,225,21,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,12,232,89,0,0,0,0,0,0,0,0,0,0,0,175,166,0,0,0,0,0, 0,0,89,125,0,0,175,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0, 0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21,12,206, 21,175,125,0,0,89,255,255,255,255,255,255,166,59,241,89,168,34,138,125, 89,225,21,7,202,89,12,228,34,0,0,0,0,12,232,89,0,138,201,0,0,0,12,206,21, 7,202,89,0,0,0,0,59,215,21,59,245,206,199,124,255,125,0,0,0,0,7,202,89, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166,0,12,232,89,0,59,238,34,0,0, 0,59,241,89,0,0,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,12,232,132,241,89, 0,0,59,241,89,0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,89,247,34,0,12,232,89,0, 12,232,89,59,241,89,0,59,241,89,0,138,247,34,0,0,138,247,34,0,0,0,0,0,12, 235,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,166,0,0,0,0,0,0,0,0,0,138, 225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0, 0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,172, 89,59,192,0,0,59,238,34,168,34,0,0,89,247,34,12,228,34,138,166,0,0,0,0, 0,0,138,251,159,247,34,0,0,0,0,0,0,59,238,34,0,0,0,0,7,202,89,0,0,7,199, 34,0,0,0,0,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,59, 241,89,0,59,241,89,0,0,0,59,241,89,0,0,0,0,0,0,89,247,34,0,0,0,0,138,201, 0,7,206,125,59,241,89,0,0,59,245,255,255,251,89,0,12,235,255,255,255,125, 0,0,0,0,7,206,166,0,0,0,175,251,89,138,201,0,59,241,89,0,12,235,125,0,138, 247,34,0,0,138,247,34,0,0,0,59,245,247,34,0,0,0,0,7,206,255,255,255,255, 255,255,125,0,0,0,0,138,255,201,0,0,0,0,0,0,89,251,89,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0, 127,0,0,0,0,0,138,201,0,0,0,0,0,0,0,0,0,12,206,21,138,125,0,0,7,206,255, 247,34,0,0,0,175,255,255,166,59,215,21,175,255,255,125,0,0,138,171,206, 166,0,175,201,0,0,0,0,89,201,0,0,0,0,0,0,175,125,0,0,0,0,0,0,0,0,12,235, 255,255,255,255,255,255,125,0,0,0,0,138,255,255,251,89,0,0,0,0,0,59,215, 21,0,59,241,89,0,59,241,89,0,0,0,59,241,89,0,0,0,0,0,12,235,166,0,0,0,138, 255,255,125,0,175,201,0,59,241,89,0,0,0,0,0,0,175,247,34,59,241,89,0,89, 247,34,0,0,0,89,247,34,0,0,0,89,255,255,255,125,0,12,235,166,0,59,245,125, 0,0,0,0,0,0,0,0,0,0,0,175,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,89,251,89,0,0,7,206,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,201, 0,0,0,0,0,0,0,12,235,255,255,255,255,255,225,21,0,0,0,175,255,251,89,0, 0,0,0,0,175,125,89,225,21,59,238,34,89,225,21,12,235,166,175,166,0,0,0, 0,89,201,0,0,0,0,0,0,175,125,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,138,166,0,0,59,241,89,0,59,241,89,0,0,0,59,241,89, 0,0,0,0,12,235,166,0,0,0,0,0,0,59,241,97,206,255,255,255,255,255,125,0, 0,0,0,0,59,241,89,59,238,34,0,12,235,125,0,0,12,235,125,0,0,0,12,232,89, 0,59,245,125,0,89,255,255,232,241,89,0,0,0,0,0,0,0,0,0,0,0,0,59,245,247, 34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,201,0,0,0,0,7,206,125,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,4, 4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,125,12,206,21, 0,0,0,0,0,168,34,175,166,0,0,0,0,59,215,21,138,201,0,12,228,34,138,225, 21,0,12,235,251,89,0,0,0,0,59,215,21,0,0,0,0,12,232,89,0,0,0,0,0,0,0,0, 0,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,12,232,89,0, 59,238,34,0,0,0,59,241,89,0,0,0,12,235,166,0,0,0,0,0,0,0,12,235,125,0,0, 0,59,241,89,0,0,0,0,0,0,59,241,89,12,232,89,0,12,232,89,0,0,138,225,21, 0,0,0,59,238,34,0,7,206,166,0,0,0,0,89,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,12,235,247,34,0,0,7,206,255,255,255,255,255,255,125,0,0,138,255,166,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0, 0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21,0,0,0,0, 0,0,0,0,172,89,89,166,0,0,0,89,166,0,168,42,206,125,0,0,0,7,202,89,0,89, 225,21,59,238,34,89,251,89,0,0,175,255,201,0,0,0,0,7,202,89,0,0,0,0,59, 215,21,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,0,0,138,247,34,0,0,0,0,0,7,206, 201,0,12,228,34,0,0,0,175,166,0,138,201,0,0,0,0,59,241,89,0,0,12,235,166, 0,0,0,0,89,166,0,0,89,251,89,0,0,0,59,241,89,0,0,59,192,0,0,175,225,21, 0,175,201,0,138,225,21,0,12,235,125,0,0,0,0,12,235,166,0,59,241,89,0,0, 0,7,206,166,0,0,138,247,34,0,0,59,245,125,0,0,0,0,0,0,0,12,232,89,0,0,0, 0,0,0,0,0,0,0,0,175,166,0,0,0,0,0,0,0,0,7,206,166,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0, 127,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,12,206,21,138,125,0,0,0,12,235,255, 255,255,166,0,0,0,0,138,201,0,0,0,175,255,255,125,0,0,138,255,255,255,125, 12,235,247,0,0,0,0,138,201,0,0,0,0,175,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,7,206,166,0,0,0,0,0,0,7,206,201,0,89,201,0,0,0,0,12,235,255,247, 34,0,0,7,206,255,255,255,225,21,89,255,255,255,255,255,166,59,245,255,255, 251,89,0,0,0,0,59,241,89,0,0,12,235,255,255,225,21,0,0,12,235,255,251,89, 0,0,175,225,21,0,0,0,0,0,59,245,255,255,125,0,0,89,255,255,166,0,0,0,138, 247,34,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,7,206,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4, 0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,168,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,12,232,89,0,0,59,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,125, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0, 4,4,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,168,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89, 255,125,89,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,201,0,0,0,0, 0,0,0,0,0,0,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,228,34,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0, 127,127,127,127,0,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,0,127,127,127,127, 0,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,0,127,127,127,0,127,127,127,127,0,127,127,127,0,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,0, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,255,125,138,166,0,0,0,89,255,255,247, 34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,89,255,255, 255,255,166,0,0,0,0,0,12,235,225,21,0,0,59,245,255,255,255,251,89,0,0,0, 59,245,255,255,251,89,59,245,255,255,255,247,34,0,0,59,245,255,255,255, 255,127,81,245,255,255,255,255,127,0,0,59,245,255,255,255,166,0,59,241, 89,0,0,0,59,241,89,89,255,255,255,125,7,206,255,251,89,59,241,89,0,0,89, 255,166,59,241,89,0,0,0,0,59,245,225,21,0,0,7,206,251,89,59,245,247,34, 0,0,59,241,89,0,0,138,255,255,255,166,0,0,59,245,255,255,255,225,21,0,0, 0,138,255,255,255,166,0,0,59,245,255,255,255,251,89,0,0,0,59,245,255,255, 201,89,255,255,255,255,255,255,255,125,59,241,89,0,0,0,59,241,97,206,166, 0,0,0,0,175,201,175,201,0,0,7,206,201,0,0,0,175,171,206,225,21,0,0,59,245, 166,245,125,0,0,0,89,251,89,89,255,255,255,255,255,127,0,228,34,0,0,59, 215,21,0,0,0,0,12,228,34,0,0,0,59,245,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,0,175,225,21,0,0,0,175,225,21,0,0,0,89,232,241,89,0,0,59, 241,89,0,0,138,225,21,0,89,255,125,0,0,59,192,59,241,89,0,0,175,251,89, 0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,89,255,125,0,0,7,199,34,59,241, 89,0,0,0,59,241,89,0,59,241,89,0,0,0,59,241,89,59,241,89,0,59,241,89,0, 59,241,89,0,0,0,0,59,245,255,125,0,0,89,255,251,89,59,245,255,201,0,0,59, 241,89,0,138,251,89,0,12,235,166,0,59,241,89,0,7,206,225,21,0,138,251,89, 0,12,235,166,0,59,241,89,0,0,138,247,34,0,12,235,125,0,7,176,21,0,0,59, 241,89,0,0,0,59,241,89,0,0,0,59,241,89,138,225,21,0,0,12,235,125,89,225, 21,0,59,245,247,34,0,12,232,89,12,235,166,0,7,206,166,0,89,247,34,0,7,206, 125,0,0,0,0,0,7,206,166,12,228,34,0,0,7,202,89,0,0,0,0,12,228,34,0,0,12, 235,133,206,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,138,201,0,138, 255,255,255,125,138,166,0,0,7,206,166,175,166,0,0,59,241,89,0,0,89,247, 34,7,206,166,0,0,0,0,0,59,241,89,0,0,0,175,225,21,59,241,89,0,0,0,0,59, 241,89,0,0,0,0,7,206,166,0,0,0,0,0,0,59,241,89,0,0,0,59,241,89,0,59,241, 89,0,0,0,59,241,89,59,241,89,59,241,89,0,0,59,241,89,0,0,0,0,59,241,159, 225,21,0,175,166,241,89,59,241,132,241,89,0,59,241,89,12,235,166,0,0,0, 89,247,34,59,241,89,0,0,89,247,34,12,235,166,0,0,0,89,247,34,59,241,89, 0,0,59,241,89,0,59,238,34,0,0,0,0,0,0,59,241,89,0,0,0,59,241,89,0,0,0,59, 241,89,59,241,89,0,0,89,225,21,59,241,89,0,89,206,202,89,0,59,238,34,0, 89,251,89,138,225,21,0,0,175,201,0,138,225,21,0,0,0,0,0,175,225,21,12,228, 34,0,0,0,138,166,0,0,0,0,12,228,34,0,7,206,166,0,12,235,125,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,7,202,89,89,225,21,7,206,125,12,206,21,0,59,238, 34,89,247,34,0,59,241,89,0,0,175,201,0,59,241,89,0,0,0,0,0,59,241,89,0, 0,0,59,241,89,59,241,89,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,0, 59,241,89,0,0,0,59,241,89,0,59,241,89,0,0,0,59,241,89,59,241,102,232,89, 0,0,0,59,241,89,0,0,0,0,59,241,102,232,89,59,215,81,241,89,59,241,89,138, 225,21,59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,7,206,201,0,59,241, 89,0,0,0,59,241,89,59,241,89,0,0,175,201,0,0,12,235,166,0,0,0,0,0,0,59, 241,89,0,0,0,59,241,89,0,0,0,59,241,89,7,206,166,0,0,175,166,0,7,206,125, 0,175,125,175,166,0,138,201,0,0,0,175,255,251,89,0,0,0,59,245,166,241,89, 0,0,0,0,0,89,247,34,0,12,228,34,0,0,0,89,201,0,0,0,0,12,228,34,12,235,201, 0,0,0,59,245,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,59,215,21,175,125, 0,7,206,125,7,199,34,0,138,201,0,12,235,125,0,59,245,255,255,255,247,34, 0,59,241,89,0,0,0,0,0,59,241,89,0,0,0,59,241,89,59,245,255,255,255,255, 127,59,245,255,255,255,255,127,59,241,89,0,0,0,0,0,0,59,245,255,255,255, 255,255,251,89,0,59,241,89,0,0,0,59,241,89,59,245,255,247,34,0,0,0,59,241, 89,0,0,0,0,59,241,89,138,201,175,166,59,241,89,59,241,89,12,235,125,59, 241,89,59,241,89,0,0,0,12,235,125,59,245,255,255,255,201,0,0,59,241,89, 0,0,0,12,235,125,59,245,255,255,255,125,0,0,0,0,59,245,255,255,125,0,0, 0,59,241,89,0,0,0,59,241,89,0,0,0,59,241,89,0,138,225,21,59,241,89,0,0, 175,201,7,202,89,89,201,0,175,166,0,0,0,12,235,166,0,0,0,0,0,138,255,166, 0,0,0,0,0,59,245,125,0,0,12,228,34,0,0,0,12,228,34,0,0,0,12,228,34,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,59,215,21,175,125,0,7, 206,125,7,199,34,7,206,125,0,0,175,201,0,59,241,89,0,0,89,247,34,59,241, 89,0,0,0,0,0,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,0,59,241,89,0,0, 0,0,59,241,89,0,59,245,255,251,89,59,241,89,0,0,0,59,241,89,0,59,241,89, 0,0,0,59,241,89,59,241,89,175,225,21,0,0,59,241,89,0,0,0,0,59,241,89,12, 235,247,34,59,241,89,59,241,89,0,89,247,94,241,89,59,241,89,0,0,0,59,241, 89,59,241,89,0,0,0,0,0,59,241,89,0,0,0,59,241,89,59,241,89,12,235,166,0, 0,0,0,0,0,0,138,251,89,0,0,59,241,89,0,0,0,59,241,89,0,0,0,59,241,89,0, 12,232,89,138,225,21,0,0,89,225,81,215,21,12,228,47,232,89,0,0,0,175,255, 251,89,0,0,0,0,59,241,89,0,0,0,0,7,206,201,0,0,0,12,228,34,0,0,0,0,175, 125,0,0,0,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 12,228,34,89,201,0,7,206,125,59,215,21,59,245,255,255,255,255,247,34,59, 241,89,0,0,59,241,89,7,206,166,0,0,0,0,0,59,241,89,0,0,0,138,225,21,59, 241,89,0,0,0,0,59,241,89,0,0,0,0,7,206,166,0,0,0,59,241,89,59,241,89,0, 0,0,59,241,89,0,59,241,89,0,0,0,59,241,89,59,241,89,7,206,201,0,0,59,241, 89,0,0,0,0,59,241,89,0,175,166,0,59,241,89,59,241,89,0,7,206,200,241,89, 12,235,166,0,0,0,89,247,34,59,241,89,0,0,0,0,0,12,235,166,0,0,0,89,247, 34,59,241,89,0,59,245,125,0,0,0,0,0,0,12,232,89,0,0,59,241,89,0,0,0,12, 232,89,0,0,0,59,238,34,0,0,175,171,206,166,0,0,0,12,232,159,201,0,7,202, 132,215,21,0,0,89,247,34,175,225,21,0,0,0,59,241,89,0,0,0,0,138,225,21, 0,0,0,12,228,34,0,0,0,0,89,201,0,0,0,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,138,201,7,206,255,251,226,255,255,166,0, 138,201,0,0,0,12,235,125,59,241,89,0,0,138,247,34,0,89,255,125,0,0,59,192, 59,241,89,0,0,138,251,89,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,89,255, 125,0,0,59,241,89,59,241,89,0,0,0,59,241,89,0,59,241,89,0,0,0,89,247,34, 59,241,89,0,12,235,166,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,59,241,89, 59,241,89,0,0,59,245,251,89,0,138,251,89,0,59,245,166,0,59,241,89,0,0,0, 0,0,0,138,251,89,0,59,245,166,0,59,241,89,0,0,138,251,89,0,89,166,0,0,89, 247,34,0,0,59,241,89,0,0,0,0,138,225,21,0,7,206,166,0,0,0,89,255,251,89, 0,0,0,7,206,255,125,0,0,138,255,201,0,0,12,235,125,0,12,235,166,0,0,0,59, 241,89,0,0,0,89,251,89,0,0,0,0,12,228,34,0,0,0,0,12,228,34,0,0,12,228,34, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,7,206,225,21,0, 0,0,0,0,0,7,206,125,0,0,0,0,175,201,59,245,255,255,255,247,34,0,0,0,59, 245,255,255,251,89,59,245,255,255,255,225,21,0,0,59,245,255,255,255,255, 127,81,241,89,0,0,0,0,0,0,59,245,255,255,255,201,0,59,241,89,0,0,0,59,241, 89,89,255,255,255,138,235,255,255,125,0,59,241,89,0,0,89,255,201,59,245, 255,255,255,255,166,59,241,89,0,0,0,0,59,241,89,59,241,89,0,0,0,175,251, 89,0,0,138,255,255,255,166,0,0,59,241,89,0,0,0,0,0,0,0,138,255,255,255, 166,0,0,59,241,89,0,0,0,175,251,89,12,235,255,255,251,89,0,0,0,59,241,89, 0,0,0,0,0,59,245,255,251,89,0,0,0,0,12,235,201,0,0,0,0,0,138,251,89,0,0, 89,255,125,0,7,206,225,21,0,0,89,255,125,0,0,59,241,89,0,0,0,175,255,255, 255,255,255,127,0,228,34,0,0,0,0,0,175,125,0,0,12,228,34,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,89,255,255,255,255,125,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, 228,34,0,0,0,0,0,89,201,0,0,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,138,255,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,255,125,0,0,0,12,228, 124,255,255,247,34,0,0,0,0,0,0,0,0,0,245,255,255,255,255,255,255,0,0,0, 0,0,0,0,0,0,0,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,0,127, 127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,127,0,89,255,125,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,89,255,255,166,0,0,0,0,0, 0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,255,201,0,12,228, 34,0,0,89,255,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,116,116, 4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,0,59,241,89,0,0,0,0,0,0,0,0,0,59,241,89,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0, 0,0,0,59,241,89,0,0,0,0,59,241,89,0,89,251,89,59,241,89,0,0,0,0,59,241, 89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,225, 21,0,0,12,228,34,0,0,0,0,138,201,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4, 4,4,28,244,252,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59, 241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,59,241,89,0, 0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,59,241, 89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166, 0,0,0,12,228,34,0,0,0,0,89,225,21,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4, 4,180,252,164,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,7,206,255,255,255, 125,0,59,241,194,255,251,89,0,0,7,206,255,255,201,0,12,235,255,255,251, 89,0,12,235,255,251,89,7,206,255,255,247,34,0,12,235,255,255,251,89,59, 241,194,255,255,125,0,59,241,89,89,255,251,89,59,241,89,0,138,251,89,59, 241,89,59,241,159,255,255,125,89,255,255,166,0,59,241,194,255,255,125,0, 0,0,12,235,255,247,34,0,59,241,194,255,255,125,0,0,12,235,255,255,251,89, 59,241,159,255,201,0,138,255,255,247,34,206,255,255,255,166,59,241,89,0, 59,241,97,206,166,0,0,12,235,125,175,201,0,7,206,166,0,7,206,133,206,225, 21,0,89,255,255,166,0,0,12,235,125,138,255,255,255,255,166,0,0,138,166, 0,0,0,12,228,34,0,0,0,0,89,225,21,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4, 76,252,244,20,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,89,247,34, 59,245,166,0,138,225,21,7,206,201,0,0,0,7,206,166,0,59,241,89,7,206,125, 0,89,225,21,59,241,89,0,0,7,206,166,0,59,241,89,59,245,166,0,89,247,34, 59,241,89,0,59,241,89,59,241,89,138,225,21,0,59,241,89,59,245,201,0,89, 255,201,0,89,247,34,59,245,166,0,89,247,34,0,7,206,166,0,138,225,21,59, 245,166,0,138,247,34,7,206,166,0,59,241,89,59,245,201,0,0,59,238,34,0,130, 34,59,241,89,0,0,59,241,89,0,59,241,89,89,247,34,0,89,247,34,138,225,21, 12,235,225,21,12,232,89,7,206,166,12,235,125,89,247,34,0,89,247,34,0,0, 0,89,247,34,0,0,138,166,0,0,0,12,228,34,0,0,0,0,89,225,21,0,0,7,206,247, 34,0,0,89,201,0,0,4,4,68,12,4,4,4,220,252,108,4,4,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,0,0,0,0,0,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,0,0,59, 241,89,0,59,241,89,59,238,34,0,59,238,34,59,241,89,0,0,59,241,89,0,59,241, 89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,159,201,0,0,0,59, 241,89,59,241,89,0,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,59,241, 89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0, 0,59,241,89,0,0,0,59,241,89,0,0,59,241,89,0,59,241,89,12,235,125,0,175, 166,0,59,238,34,89,171,202,89,89,225,21,0,59,241,226,201,0,12,235,125,0, 175,166,0,0,0,12,235,125,0,0,59,238,34,0,0,0,12,228,34,0,0,0,0,7,206,125, 0,7,202,89,12,235,166,0,175,125,0,0,4,60,244,172,4,4,132,252,212,4,4,4, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,89,255,255,255,251,89,59,241,89, 0,59,241,89,59,238,34,0,0,0,59,238,34,0,59,241,89,59,245,255,255,255,251, 0,59,241,89,0,0,59,238,34,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0, 59,241,89,59,245,255,225,21,0,0,59,241,89,59,241,89,0,59,241,89,0,59,241, 89,59,241,89,0,59,241,89,0,59,238,34,0,12,232,89,59,241,89,0,12,232,89, 59,238,34,0,59,241,89,59,241,89,0,0,0,175,255,255,201,0,59,241,89,0,0,59, 241,89,0,59,241,89,0,175,201,12,232,89,0,7,206,125,172,89,138,166,138,201, 0,0,0,138,247,34,0,0,175,201,12,232,89,0,0,7,206,166,0,0,175,225,21,0,0, 0,0,12,228,34,0,0,0,0,0,0,175,225,34,206,21,0,0,175,255,166,0,0,0,4,52, 244,252,140,36,244,252,60,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,59, 241,89,0,59,241,89,59,241,89,0,59,238,34,59,241,89,0,0,0,59,241,89,0,59, 241,89,59,238,34,0,0,0,0,59,241,89,0,0,59,241,89,0,59,241,89,59,241,89, 0,59,241,89,59,241,89,0,59,241,89,59,241,97,206,201,0,0,59,241,89,59,241, 89,0,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,59,241,89,0,59,241,89, 59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,0,0,0,0,59,245, 125,59,241,89,0,0,59,241,89,0,59,241,89,0,59,238,124,225,21,0,0,175,176, 206,21,59,215,187,125,0,0,59,245,255,201,0,0,89,247,124,225,21,0,0,138, 225,21,0,0,0,59,241,89,0,0,0,12,228,34,0,0,0,0,12,235,125,0,0,0,0,0,0,0, 0,0,0,0,0,4,4,76,252,252,220,252,164,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,0,0,0,0,0,89,247,34,0,89,251,89,59,241,89,0,175,201,0,7,206,201,0,0,0, 7,206,166,0,138,251,89,7,206,166,0,7,199,34,59,241,89,0,0,7,206,166,0,138, 251,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,12,235,166, 0,59,241,89,59,241,89,0,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,7, 206,166,0,138,225,21,59,241,89,0,138,225,21,7,206,166,0,89,251,89,59,241, 89,0,0,89,125,0,12,232,89,12,232,89,0,12,12,235,125,0,175,251,89,0,7,206, 255,125,0,0,0,89,255,201,0,7,206,247,34,0,7,206,166,59,245,125,0,7,206, 255,125,0,0,59,241,89,0,0,0,0,0,138,166,0,0,0,12,228,34,0,0,0,0,89,225, 21,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,100,252,252,244,28,4,4,4,4,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,127,0,0,0,0,0,0,0,0,175,255,255,232,241,89,59,245,255,255,247,34, 0,0,12,235,255,255,201,0,59,245,255,200,241,89,0,12,235,255,251,89,0,59, 241,89,0,0,0,12,235,255,200,241,89,59,241,89,0,59,241,89,59,241,89,0,59, 241,89,59,241,89,0,59,245,201,59,241,89,59,241,89,0,59,241,89,0,59,241, 89,59,241,89,0,59,241,89,0,0,12,235,255,247,34,0,59,245,166,255,247,34, 0,0,59,245,255,166,241,89,59,241,89,0,0,59,245,255,255,166,0,0,138,255, 255,125,0,89,255,255,166,241,89,0,0,138,247,34,0,0,0,59,245,125,0,0,138, 225,21,7,206,225,21,0,138,251,0,0,138,247,34,0,0,175,255,255,255,255,166, 0,0,138,166,0,0,0,12,228,34,0,0,0,0,89,225,21,0,0,0,0,0,0,0,0,0,0,0,0,4, 4,4,4,132,252,108,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,89,247,34,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0, 0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,232,89,0,0,0,0,0,0,0,0,0,0,0,138, 201,0,0,0,12,228,34,0,0,0,0,138,201,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4, 116,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,166,255,255, 247,34,0,0,0,0,0,0,0,0,0,0,0,255,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,59, 241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,7,206,255, 201,0,12,228,34,0,0,89,255,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4, 4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,0,127,127,127,0,127,127,127, 127,127,127,0,127,127,0,127,127,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,0,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,89,247,34,138,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,59,238,34,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255, 225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12,235,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,238,34,138,201,0,0,0,0,0, 0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,199,34,0,0,0,0,0,7,199,34,0,0,0,0,138,255, 201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,251,89,0,0,138,255,251,97,206,201,0,0,138, 251,102,235,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255, 201,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0,7,206,166,12,232,89,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,166,12,235,127,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,0,175,255,255,255,225,21,59,245,255,255,255, 255,255,125,0,0,0,0,0,0,0,7,206,255,247,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,7,199,34,0,0,0,0,0,7,199,34,0,0,0,138,225,21,175,166,0,0,175,255,255, 166,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,59,245,255,255,201,0,0,0,0,0,0,0,0, 59,245,255,255,255,255,255,255,255,255,125,0,59,245,255,255,255,255,255, 125,0,0,89,255,255,255,255,255,225,21,59,245,255,255,255,255,255,125,0, 0,0,59,245,255,255,255,255,255,125,7,206,166,0,0,175,171,206,166,89,247, 34,0,175,201,59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12,228,34,175,255,125,0,0,89,255,255,255,125,175,251,89,89,255,125,0,7, 206,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,255,255,255, 255,255,125,0,0,7,206,255,125,59,245,125,0,0,0,89,251,89,0,0,0,0,0,0,0, 127,7,206,225,21,0,0,0,0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,0,175,201,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,255,255,255,255,125,0,59,245,255, 255,255,255,125,0,0,0,0,0,0,0,89,247,34,12,228,34,0,138,166,0,0,0,0,0,0, 0,0,0,0,12,235,125,0,7,176,21,0,0,0,0,0,0,138,251,89,0,0,138,201,0,0,0, 0,0,0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,7,206,166,0,59,115,0,0,0,0,59,115, 0,0,0,59,115,0,0,0,0,59,115,0,89,201,0,12,232,89,89,201,7,202,89,12,232, 89,138,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,7,199,34,0,172,132,196,199,163,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,0,89,247,34,0,7, 206,125,0,0,0,0,0,0,0,0,127,89,247,34,0,0,0,0,0,59,115,0,0,0,0,59,115,0, 0,0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,199,34,0, 0,0,0,0,7,199,34,0,0,0,0,0,0,0,0,0,89,225,21,7,202,89,12,228,34,0,0,0,0, 0,0,0,0,0,0,59,238,34,0,0,0,0,0,0,0,130,34,59,241,89,0,0,0,138,201,0,0, 0,0,0,0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,175,225,21,0,59,115,0,0,0,0,59, 115,0,0,0,59,115,0,0,0,0,59,115,0,12,228,34,59,192,0,12,228,34,138,166, 59,215,21,175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,7,199,34,0,172,89,175,166,138,125,0,138,255,255,247,34,12, 146,0,0,0,0,89,255,255,255,125,12,235,255,255,125,0,0,0,59,115,0,0,0,0, 59,115,0,138,255,255,255,255,127,0,175,201,0,138,225,21,0,0,0,0,0,0,0,0, 127,245,255,255,255,255,255,125,0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,12, 232,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,199,34,0,0,0,0,0,7,199, 34,0,0,0,0,0,0,0,0,0,89,247,34,12,228,34,138,166,0,0,0,0,0,0,0,0,0,0,0, 12,235,166,0,0,0,0,0,0,175,225,21,138,225,21,0,0,0,138,201,0,0,0,0,0,0, 59,115,0,0,0,0,59,115,0,0,0,0,0,89,247,34,0,0,59,115,0,0,0,0,59,115,0,0, 0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,166, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,199,34,0,172, 89,0,0,138,125,59,238,34,0,130,34,7,206,201,0,0,59,241,89,0,12,235,255, 125,0,59,241,89,0,0,59,115,0,0,0,0,59,115,0,0,0,0,89,247,34,0,59,245,166, 241,89,0,0,0,0,0,0,0,0,0,127,138,225,21,0,0,0,0,0,59,115,0,0,0,0,59,115, 0,0,0,0,0,89,255,255,255,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,199, 34,0,0,0,0,0,7,199,34,0,0,0,0,0,0,0,0,0,0,175,255,255,166,59,215,21,175, 255,255,125,0,89,255,255,201,0,0,0,59,245,255,255,125,0,12,235,166,0,0, 138,225,21,0,0,0,138,255,255,255,255,247,34,0,59,115,0,0,0,0,59,115,0,0, 0,0,59,245,125,0,0,0,59,115,0,0,0,0,59,115,0,0,0,59,115,0,0,0,0,59,115, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,255,251,102,0,255,255,255,255, 255,0,245,255,255,255,255,255,255,255,255,255,255,127,21,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,59,241,89,0,0,0,0,0,138,247,34,138,201,0,0,0,175, 201,0,0,0,175,166,0,0,59,115,0,0,0,0,59,115,0,0,0,12,235,125,0,0,0,138, 255,166,0,0,0,0,0,0,0,0,0,0,127,245,255,255,255,255,225,21,0,59,115,0,0, 0,0,59,115,0,0,0,0,0,0,89,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,7,199,34,0,0,0,59,245,255,255,255,255,125,0,0,0,0,0,0,0,0,0,0,0,0,175, 125,89,225,21,59,238,47,232,89,7,206,125,0,0,0,0,0,138,251,89,12,235,166, 0,0,138,225,21,0,0,0,138,201,0,0,0,0,0,0,59,115,0,0,0,0,59,115,0,0,0,7, 206,201,0,0,0,0,59,115,0,0,0,0,59,115,0,0,0,59,115,0,0,0,0,59,115,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,255,251,89,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,255,255,201,0, 0,0,138,247,34,175,201,0,0,0,138,255,255,255,255,255,166,0,0,59,115,0,0, 0,0,59,115,0,0,7,206,166,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,127,89,251, 89,0,0,0,0,0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,138,201,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,7,199,34,0,0,0,0,0,7,199,34,0,0,0,0,0,0,0,0,0, 0,0,0,0,59,215,21,138,201,0,12,228,47,228,34,0,175,166,0,0,0,0,0,12,232, 89,0,0,175,225,21,59,241,89,0,0,0,138,201,0,0,0,0,0,0,59,115,0,0,0,0,59, 115,0,0,0,138,225,21,0,0,0,0,59,115,0,0,0,0,59,115,0,0,0,59,115,0,0,0,0, 59,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,166,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59, 245,125,7,206,201,0,0,138,201,0,0,0,175,201,0,0,0,0,0,0,0,59,115,0,0,0, 0,59,115,0,0,138,225,21,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,127,7,206, 247,34,0,0,0,0,59,115,0,0,0,0,59,115,0,59,245,125,0,0,175,166,0,0,0,59, 245,125,175,225,29,206,166,0,89,247,34,7,206,166,0,0,0,7,199,34,0,0,0,0, 0,7,199,34,0,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,89,225,21,59,238,47,232,89, 7,206,125,0,89,166,0,0,89,247,34,0,0,0,130,34,0,138,255,125,0,0,138,201, 0,0,0,0,0,0,59,115,0,0,0,0,59,115,0,0,89,251,89,0,0,0,0,0,59,115,0,0,0, 0,59,115,0,0,0,59,115,0,0,0,0,59,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,89,125,0,12,232,89,12,146,0,0,0,59,241,89,0,12,235,247, 34,0,0,89,125,0,0,59,115,0,0,0,0,59,115,0,59,241,89,0,0,0,0,0,59,241,89, 0,0,0,0,0,0,0,0,0,0,127,0,0,175,255,255,255,225,21,59,245,255,255,255,255, 255,125,0,138,225,21,0,12,235,125,0,0,0,138,225,34,235,125,7,206,166,0, 89,247,34,7,206,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 138,201,0,0,0,175,255,255,125,0,89,255,255,201,0,0,12,235,255,255,251,89, 0,0,0,0,0,0,0,0,89,255,255,255,255,255,255,255,255,255,125,0,59,245,255, 255,255,255,255,125,0,0,175,255,255,255,255,255,247,34,59,245,255,255,255, 255,255,125,0,0,0,59,245,255,255,255,255,255,125,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,255,255,166,0,0,0,0,0,0,0,89,255,255, 255,125,59,245,255,255,201,0,0,0,59,245,255,255,255,255,255,125,0,175,255, 255,255,255,127,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,175,166,0,255,255,201,0,0,0,0,175,166,59,238,34,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,228,34,0,0, 0,0,0,0,0,12,228,34,138,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,0,127,127,127,0,127,127,127,127,127, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,0, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,127,0,127,127,0,127,127,0,127,127,127,127,0, 127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,245,255,255,255,255,255, 251,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21, 0,0,0,138,125,0,0,0,0,59,245,255,255,125,0,0,0,0,0,0,0,0,138,225,21,0,0, 175,166,0,12,228,34,0,0,59,245,255,255,247,34,0,89,225,29,206,166,0,0,0, 0,0,89,255,255,255,255,125,0,0,0,7,206,255,255,247,34,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255,255,255,255,125,0,0,0,0,0,0,0, 0,0,0,0,0,138,255,255,166,0,0,0,0,7,202,89,0,0,0,0,0,12,235,255,125,0,0, 175,255,255,225,21,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,138,255,255,255, 255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,228,34,0,0,89,255,255,225,21,0,0, 0,0,0,0,0,0,0,0,0,138,166,0,0,0,89,225,21,0,0,0,0,0,138,166,0,0,0,89,225, 21,0,0,0,12,235,255,255,166,0,0,7,206,125,0,0,0,0,0,0,89,247,34,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21,0,0,0,138,125,0,0,0,12, 235,125,0,59,115,0,0,0,0,0,0,0,0,7,206,125,0,59,215,21,0,12,228,34,0,12, 235,125,0,0,168,34,0,0,0,0,0,0,0,0,0,0,175,225,21,0,0,0,175,225,21,0,0, 0,0,0,138,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,225, 21,0,0,0,175,225,21,0,0,0,0,0,0,0,0,0,59,238,34,7,206,125,0,0,0,7,202,89, 0,0,0,0,7,199,34,59,238,34,0,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,89,255,255,255,125,175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,247,34,0, 59,241,89,0,175,201,0,0,0,0,0,0,0,0,0,7,206,255,166,0,0,12,232,89,0,0,0, 0,7,206,255,166,0,0,12,232,89,0,0,0,0,0,0,0,59,215,21,0,89,201,0,0,0,0, 0,0,0,89,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,7, 206,255,255,251,89,0,59,241,89,0,0,0,138,201,0,0,0,138,201,0,0,89,225,21, 175,125,0,0,12,228,34,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166,0, 89,255,255,247,34,89,201,0,0,89,255,255,255,166,0,0,0,0,168,34,7,151,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166,7,206,255,255,225,21,89,201,0,0,0, 0,0,0,0,0,0,89,166,0,0,138,166,0,0,0,7,202,89,0,0,0,0,0,0,0,59,238,34,0, 7,206,255,125,0,0,0,0,0,0,0,0,0,59,238,34,0,0,175,166,0,175,255,255,255, 125,175,125,0,138,247,34,0,0,0,0,0,0,0,0,0,0,12,228,34,0,89,201,0,0,89, 225,0,81,115,0,134,89,0,0,0,0,0,138,166,0,0,138,166,0,0,0,0,0,0,0,138,166, 0,0,138,166,0,0,0,0,0,0,59,245,247,34,0,12,232,89,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,201,0,7,206,201,138,125, 138,125,0,59,241,89,0,0,0,0,175,255,255,255,225,21,0,0,7,206,166,215,21, 0,0,12,228,34,0,0,138,255,255,251,89,0,0,0,0,0,0,0,0,0,12,206,21,59,241, 89,0,134,89,0,172,89,59,238,34,0,138,166,0,0,7,206,201,12,235,125,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,12,206,21,7,202,89,12,235,125,0,172,89,0,0,0,0, 0,0,0,0,59,238,34,7,206,125,12,235,255,255,255,255,255,255,125,0,0,0,12, 235,125,0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,59,238,34,0,0,175,166,0,175,255, 255,255,125,175,125,0,138,247,34,0,0,0,0,0,0,0,0,0,0,12,228,34,0,89,201, 0,0,89,225,0,29,206,166,59,245,125,0,0,0,0,138,166,0,12,228,34,0,175,225, 21,0,0,0,138,166,0,12,228,42,206,255,255,166,0,0,0,0,12,228,34,138,166, 0,89,247,34,0,0,0,0,59,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0, 0,0,138,201,0,59,241,89,138,125,0,0,59,245,255,255,255,125,0,0,138,166, 0,89,201,0,0,0,0,89,255,125,0,0,0,0,0,0,0,7,206,125,0,138,251,89,0,0,0, 0,0,0,0,0,89,166,0,138,201,0,0,0,0,0,89,166,59,215,21,0,175,166,0,59,245, 125,89,251,89,0,0,12,235,255,255,255,255,255,255,125,138,255,255,251,89, 127,166,0,7,202,89,12,232,89,0,89,166,0,0,0,0,0,0,0,0,0,138,255,255,166, 0,0,0,0,7,202,89,0,0,0,0,0,59,241,89,0,0,0,0,0,7,206,125,0,0,0,0,0,0,0, 0,59,238,34,0,0,175,166,0,89,255,255,255,125,175,125,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,12,228,34,0,59,241,89,0,175,201,0,0,0,175,201,7,206,201,0,0,0, 138,166,0,175,166,0,138,200,215,21,0,0,0,138,166,0,175,166,7,151,0,89,247, 34,0,0,0,59,238,47,228,34,59,219,209,34,0,0,0,89,255,125,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21,59,238,34,138,125,0,0,0,59, 241,89,0,0,0,0,138,166,0,89,201,0,0,59,245,255,255,255,255,125,0,0,0,0, 0,59,238,34,0,7,206,125,0,0,0,0,0,0,0,0,89,166,0,138,201,0,0,0,0,0,89,166, 0,175,255,255,223,166,0,12,235,125,59,241,89,0,0,0,0,0,0,0,0,0,175,125, 0,0,0,0,0,138,125,0,7,206,255,255,125,0,0,59,157,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,7,202,89,0,0,0,0,7,206,255,255,255,166,7,206,255,255,201,0, 0,0,0,0,0,0,0,0,59,238,34,0,0,175,166,0,0,89,255,255,125,175,125,0,0,0, 0,0,0,0,0,0,0,0,0,0,89,255,255,251,89,0,89,255,255,225,21,0,0,0,175,225, 29,206,166,0,0,0,138,166,59,215,21,59,215,81,215,21,0,0,0,138,166,59,215, 21,0,0,0,89,225,21,59,245,255,255,125,138,166,7,202,97,199,34,0,0,89,251, 89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225,21,59,241, 89,138,125,0,0,0,89,247,34,0,0,0,0,175,255,255,255,225,21,0,0,0,12,232, 89,0,0,0,12,228,34,0,12,235,225,21,59,215,21,0,0,0,0,0,0,0,0,12,206,21, 59,241,89,0,134,89,0,172,89,0,0,0,0,0,0,0,0,7,206,201,12,235,125,0,0,0, 0,0,0,0,0,175,125,0,0,0,0,0,12,206,21,7,202,89,7,206,125,0,172,89,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,59,238,34,0,0,175,166,0,0,0,0,175,125,175,125,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,166,59,245,125,0,0,0,0,0,0, 175,125,12,228,34,59,215,21,0,0,0,0,0,175,125,0,0,0,12,232,89,0,0,0,0,0, 59,238,34,175,125,7,199,34,0,0,175,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,127,0,0,0,0,0,138,225,21,7,206,201,138,125,138,125,7,202,89,0,0,0, 0,138,201,0,0,0,138,166,0,0,0,12,232,89,0,0,0,12,228,34,0,0,0,175,255,255, 166,0,0,0,0,0,0,0,0,0,0,138,166,0,89,255,255,247,34,89,201,0,0,0,0,0,0, 0,0,0,0,0,168,34,7,151,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0,0,138,166,7,202, 89,0,89,247,124,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,255,255,255, 255,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,125,0,7,206, 166,0,0,0,0,175,125,175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,59,115,0,134,89,0,0,0,0,0,0,59,215,21,59,245,255,255,255,225,21,0, 0,0,59,215,21,0,0,59,238,34,0,0,0,0,0,0,175,125,7,206,255,255,255,251,89, 0,138,247,34,0,59,157,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,225, 21,0,7,206,255,255,251,89,138,255,255,255,255,255,166,0,0,0,0,0,0,0,0,0, 0,12,232,89,0,0,0,12,228,34,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,175, 225,21,0,0,0,175,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,175,225,21,0,0,0,175,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,238,198, 255,251,194,166,0,0,0,0,175,125,175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,125,0,0,0,0,89,225,21,0,0,0, 7,206,125,0,0,12,235,255,255,255,166,0,0,0,89,225,21,0,0,0,12,228,34,0, 0,0,175,255,255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0, 0,0,0,0,138,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,228, 34,0,7,176,21,0,89,247,34,0,0,0,0,0,0,0,0,0,0,0,89,255,255,255,255,125, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89, 255,255,255,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,238,34,0,0,0,0,0,0,0,0,175, 125,175,125,0,0,0,0,0,0,0,0,59,215,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 0,0,0,0,0,0,0,138,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12,228,34,0,7,206,255,255,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,238,34,0,0,0,0,0,0,0,0,175,125,175,125, 0,0,0,0,0,0,59,245,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,0,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,0, 127,127,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,89, 255,125,0,0,0,0,0,0,12,235,201,0,0,0,0,12,235,251,89,0,0,0,0,175,255,125, 89,201,0,0,0,0,0,0,0,0,0,0,0,59,245,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,89,255,125,0,0,0,0,0,0,138,251,89,0,0,0,12,235,251, 89,0,0,0,0,0,0,0,0,7,206,225,21,0,0,0,89,255,125,0,89,255,225,21,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,247,34,172,89,0,0,0,0,7,206,225,21,0,0, 0,0,0,0,0,89,255,125,0,0,0,0,0,0,89,255,225,21,0,0,0,0,12,235,247,34,172, 89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89, 255,125,0,0,0,0,0,0,0,7,206,225,21,0,0,0,0,89,255,225,21,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,89,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0, 0,89,247,34,0,0,0,0,0,175,166,0,0,0,0,7,206,125,59,241,89,0,0,89,201,12, 235,247,34,0,0,7,206,166,59,241,89,0,0,12,228,34,59,215,21,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,238,34,0,0,0,0,89,247,34,0,0,0,7, 206,125,59,241,89,0,7,206,166,59,238,34,0,0,175,166,0,0,59,241,89,0,89, 247,34,138,201,59,238,34,138,201,0,0,0,0,0,0,0,0,0,0,0,175,125,89,255,201, 0,0,0,0,0,0,0,175,201,0,0,0,0,0,0,12,232,89,0,0,0,0,0,0,59,238,34,138,225, 21,0,0,0,175,125,89,255,201,0,0,0,0,59,238,34,138,201,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,247,34,0,0,0,0,0,0,138,201,0,0,0,0, 0,59,238,34,138,225,21,0,0,0,59,238,34,138,201,0,0,0,0,12,232,89,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,228,34,59,215,21,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,255,125,0, 0,0,0,127,0,0,12,235,225,21,0,0,0,0,12,235,225,21,0,0,0,0,12,235,225,21, 0,0,0,0,12,235,225,21,0,0,0,0,12,235,225,21,0,0,0,0,12,235,225,21,0,0,0, 0,0,175,255,255,255,255,255,255,255,166,0,0,138,255,255,255,251,89,59,245, 255,255,255,255,127,81,245,255,255,255,255,225,21,59,245,255,255,255,255, 127,81,245,255,255,255,255,127,111,255,255,255,125,89,255,255,255,125,89, 255,255,255,125,89,255,255,255,125,7,206,255,255,255,255,125,0,0,59,245, 247,34,0,0,59,241,89,0,0,0,138,255,255,255,166,0,0,0,0,138,255,255,255, 166,0,0,0,0,0,138,255,255,255,166,0,0,0,0,138,255,255,255,166,0,0,0,0,138, 255,255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,255,255,210,235,166, 59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59, 241,89,59,241,89,0,0,0,59,241,132,245,125,0,0,0,89,251,89,12,232,89,0,0, 0,0,7,206,166,0,89,251,89,0,0,0,127,0,0,89,232,241,89,0,0,0,0,89,232,241, 89,0,0,0,0,89,232,241,89,0,0,0,0,89,232,241,89,0,0,0,0,89,232,241,89,0, 0,0,0,89,232,241,89,0,0,0,0,12,232,89,89,225,21,0,0,0,0,0,175,247,34,0, 0,59,192,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,0,0,59,241, 89,0,0,0,0,0,59,241,89,0,0,59,241,89,0,0,59,241,89,0,0,59,241,89,0,7,206, 166,0,0,59,245,201,0,59,245,255,201,0,0,59,241,89,0,0,138,251,89,0,12,235, 166,0,0,138,251,89,0,12,235,166,0,0,0,138,251,89,0,12,235,166,0,0,138,251, 89,0,12,235,166,0,0,138,251,89,0,12,235,166,0,0,0,138,166,0,0,0,12,228, 34,0,0,175,247,34,0,0,175,225,21,59,241,89,0,0,0,59,241,89,59,241,89,0, 0,0,59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,89,247, 34,0,7,206,125,0,12,232,89,0,0,0,0,59,241,89,0,12,232,89,0,0,0,127,0,7, 206,166,175,166,0,0,0,7,206,166,175,166,0,0,0,7,206,166,175,166,0,0,0,7, 206,166,175,166,0,0,0,7,206,166,175,166,0,0,0,0,175,166,175,166,0,0,0,0, 138,225,21,89,225,21,0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,0,0,59,241, 89,0,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,59,241, 89,0,0,59,241,89,0,0,59,241,89,0,7,206,166,0,0,0,59,245,125,59,241,132, 241,89,0,59,241,89,0,12,235,166,0,0,0,89,247,34,12,235,166,0,0,0,89,247, 34,0,12,235,166,0,0,0,89,247,34,12,235,166,0,0,0,89,247,34,12,235,166,0, 0,0,89,247,34,0,0,12,235,125,0,12,235,125,0,0,59,241,89,0,0,138,176,235, 166,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0, 59,241,89,59,241,89,0,0,0,59,241,89,0,175,201,0,138,225,21,0,12,235,255, 255,255,225,21,59,238,34,0,138,225,21,0,0,0,127,0,59,238,34,89,247,34,0, 0,59,238,34,89,247,34,0,0,59,238,34,89,247,34,0,0,59,238,34,89,247,34,0, 0,59,238,34,89,247,34,0,0,59,241,89,89,225,21,0,0,7,206,125,0,89,225,21, 0,0,0,0,138,225,21,0,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,59,241, 89,0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,59,241,89,0,0,59,241,89,0, 0,59,241,89,0,7,206,166,0,0,0,7,206,166,59,241,89,138,225,21,59,241,89, 0,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,0,59,241,89,0,0,0, 59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,0,0,0,12, 235,138,235,125,0,0,0,138,225,21,0,59,215,21,175,201,59,241,89,0,0,0,59, 241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0, 0,0,59,241,89,0,59,245,166,241,89,0,0,12,232,89,0,0,175,225,59,238,47,235, 225,21,0,0,0,0,127,0,138,201,0,12,235,125,0,0,138,201,0,12,235,125,0,0, 138,201,0,12,235,125,0,0,138,201,0,12,235,125,0,0,138,201,0,12,235,125, 0,0,138,225,21,12,235,125,0,0,89,247,34,0,89,255,255,255,255,251,89,138, 225,21,0,0,0,0,0,59,245,255,255,255,255,127,59,245,255,255,255,255,166, 0,59,245,255,255,255,255,127,59,245,255,255,255,255,127,0,59,241,89,0,0, 59,241,89,0,0,59,241,89,0,0,59,241,89,7,206,255,255,255,166,0,0,175,201, 59,241,89,12,235,125,59,241,89,0,59,241,89,0,0,0,12,235,125,59,241,89,0, 0,0,12,235,125,0,59,241,89,0,0,0,12,235,125,59,241,89,0,0,0,12,235,125, 59,241,89,0,0,0,12,235,125,0,0,0,0,12,235,125,0,0,0,0,138,225,21,7,199, 34,0,138,225,81,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,59,241, 89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,0,0,138,255,166,0,0,0,12,232, 89,0,0,89,247,59,238,34,0,59,245,125,0,0,0,127,7,206,125,0,0,175,201,0, 7,206,125,0,0,175,201,0,7,206,125,0,0,175,201,0,7,206,125,0,0,175,201,0, 7,206,125,0,0,175,201,0,7,206,125,0,0,175,201,0,7,206,255,255,255,255,225, 21,0,0,0,0,138,225,21,0,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,59, 241,89,0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,59,241,89,0,0,59,241,89, 0,0,59,241,89,0,7,206,166,0,0,0,7,206,166,59,241,89,0,89,247,94,241,89, 0,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,0,59,241,89,0,0,0, 59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,0,0,0,12, 235,138,235,125,0,0,0,138,225,21,175,125,0,0,175,201,59,241,89,0,0,0,59, 241,89,59,241,89,0,0,0,59,241,89,59,241,89,0,0,0,59,241,89,59,241,89,0, 0,0,59,241,89,0,0,59,241,89,0,0,0,12,232,89,0,7,206,201,59,238,34,0,0,138, 201,0,0,0,127,59,245,255,255,255,255,247,34,59,245,255,255,255,255,247, 34,59,245,255,255,255,255,247,34,59,245,255,255,255,255,247,34,59,245,255, 255,255,255,247,34,59,245,255,255,255,255,247,34,59,241,89,0,0,89,225,21, 0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,59,241, 89,0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,59,241,89,0,0,59,241,89,0, 0,59,241,89,0,7,206,166,0,0,0,59,241,89,59,241,89,0,7,206,200,241,89,0, 12,235,166,0,0,0,89,247,34,12,235,166,0,0,0,89,247,34,0,12,235,166,0,0, 0,89,247,34,12,235,166,0,0,0,89,247,34,12,235,166,0,0,0,89,247,34,0,0,12, 235,125,0,12,235,125,0,0,59,241,159,166,0,0,12,235,166,12,232,89,0,0,0, 59,238,34,12,232,89,0,0,0,59,238,34,12,232,89,0,0,0,59,238,34,12,232,89, 0,0,0,59,238,34,0,0,59,241,89,0,0,0,12,235,255,255,255,201,0,59,238,34, 0,0,138,201,0,0,0,127,138,201,0,0,0,12,235,125,138,201,0,0,0,12,235,125, 138,201,0,0,0,12,235,125,138,201,0,0,0,12,235,125,138,201,0,0,0,12,235, 125,138,201,0,0,0,12,235,125,175,201,0,0,0,89,225,21,0,0,0,0,0,175,247, 34,0,0,59,192,59,241,89,0,0,0,0,59,241,89,0,0,0,0,0,59,241,89,0,0,0,0,59, 241,89,0,0,0,0,0,59,241,89,0,0,59,241,89,0,0,59,241,89,0,0,59,241,89,0, 7,206,166,0,0,59,245,201,0,59,241,89,0,0,59,245,251,89,0,0,138,251,89,0, 59,245,166,0,0,138,251,89,0,59,245,166,0,0,0,138,251,89,0,59,245,166,0, 0,138,251,89,0,59,245,166,0,0,138,251,89,0,59,245,166,0,0,0,138,166,0,0, 0,12,228,34,0,0,175,247,34,0,7,206,225,21,0,138,225,21,0,7,206,166,0,0, 138,225,21,0,7,206,166,0,0,138,225,21,0,7,206,166,0,0,138,225,21,0,7,206, 166,0,0,0,59,241,89,0,0,0,12,232,89,0,0,0,0,59,238,34,0,12,235,125,0,0, 0,127,206,125,0,0,0,0,175,206,206,125,0,0,0,0,175,206,206,125,0,0,0,0,175, 206,206,125,0,0,0,0,175,206,206,125,0,0,0,0,175,206,206,125,0,0,0,0,175, 232,245,125,0,0,0,89,255,255,255,255,255,166,0,0,138,255,255,255,251,89, 59,245,255,255,255,255,127,81,245,255,255,255,255,225,21,59,245,255,255, 255,255,127,81,245,255,255,255,255,127,111,255,255,255,125,89,255,255,255, 125,89,255,255,255,125,89,255,255,255,125,7,206,255,255,255,255,125,0,0, 59,241,89,0,0,0,175,251,89,0,0,0,138,255,255,255,166,0,0,0,0,138,255,255, 255,166,0,0,0,0,0,138,255,255,255,166,0,0,0,0,138,255,255,255,166,0,0,0, 0,138,255,255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,7,202,194,255,255,255,201, 0,0,0,0,59,245,255,251,89,0,0,0,0,59,245,255,251,89,0,0,0,0,59,245,255, 251,89,0,0,0,0,59,245,255,251,89,0,0,0,0,59,241,89,0,0,0,12,232,89,0,0, 0,0,59,238,47,235,255,166,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138, 166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,166,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127, 127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,0, 0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,201,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,7,206, 225,21,0,0,0,0,0,12,235,201,0,0,0,138,255,201,0,0,0,59,245,225,29,202,89, 0,0,0,0,0,0,0,0,138,166,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 7,206,225,21,0,0,0,0,0,12,235,201,0,0,0,89,255,225,21,0,0,0,0,0,0,0,0,175, 247,34,0,12,235,255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,59,245,225,29,202,89, 0,0,138,251,89,0,0,0,0,0,7,206,225,21,0,0,0,89,255,225,21,0,0,59,245,225, 29,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,225, 21,0,0,0,0,0,89,255,125,0,0,0,89,255,225,21,0,0,0,0,0,0,0,0,0,0,0,0,138, 251,89,0,59,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,175, 166,0,0,0,0,7,206,166,0,0,0,89,225,21,175,201,0,7,202,89,138,255,166,0, 0,89,247,34,175,166,0,0,138,166,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,7,206,166,0,0,0,0,0,175,166,0,0,0,89,247,34,138,201,0,0,89,247, 34,175,201,0,0,138,201,0,175,200,215,34,235,247,47,232,0,138,255,225,111, 225,21,0,0,172,89,138,255,166,0,0,0,0,89,225,21,0,0,0,0,175,201,0,0,0,0, 89,247,34,138,201,0,0,172,89,138,255,166,0,0,59,238,34,138,201,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,166,0,0,0,0,59,241,89,0,0,0,89, 247,34,138,201,0,0,0,59,238,34,138,201,0,0,0,89,247,34,0,0,59,238,34,0, 0,0,0,0,138,225,29,206,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,201,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,225,21,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,12,235,166,0,0,0,0,0,0,0,0,89,166,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,238,34,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,7,206,255,255,255,125,0,7,206,255,255,255, 125,0,7,206,255,255,255,125,0,7,206,255,255,255,125,0,7,206,255,255,255, 125,0,12,235,255,255,251,89,0,12,235,255,255,251,89,59,245,255,166,0,0, 59,245,255,255,201,0,12,235,255,251,89,0,0,12,235,255,251,89,0,0,12,235, 255,251,89,0,0,12,235,255,251,89,0,59,238,34,59,238,34,59,238,34,59,238, 34,0,59,241,89,175,225,21,0,59,241,194,255,255,125,0,0,12,235,255,247,34, 0,0,12,235,255,247,34,0,0,0,12,235,255,247,34,0,0,12,235,255,247,34,0,0, 12,235,255,247,34,0,0,0,0,0,12,235,166,0,0,0,0,7,206,255,255,225,21,0,59, 241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,59,241, 89,0,59,241,97,206,166,0,0,12,235,125,59,238,163,255,255,201,7,206,166, 0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,89,247,34,0,0,0,0,89,247, 34,0,0,0,0,89,247,34,0,0,0,0,89,247,34,0,0,0,0,89,247,34,0,0,0,0,138,225, 21,0,0,0,0,89,255,225,21,0,138,201,59,245,125,0,0,0,7,206,125,0,89,225, 21,7,206,125,0,89,225,21,7,206,125,0,89,225,21,7,206,125,0,89,225,21,59, 238,34,59,238,34,59,238,34,59,238,34,0,0,0,0,12,235,125,0,59,245,166,0, 89,247,34,7,206,166,0,138,225,21,7,206,166,0,138,225,21,0,7,206,166,0,138, 225,21,7,206,166,0,138,225,21,7,206,166,0,138,225,21,0,0,0,0,0,0,0,0,0, 0,12,232,89,0,138,251,89,0,59,241,89,0,59,241,89,59,241,89,0,59,241,89, 59,241,89,0,59,241,89,0,59,241,89,0,59,241,89,89,247,34,0,89,247,34,59, 245,166,0,7,206,166,89,247,34,0,89,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 59,241,89,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0,59,241,89,0,0,0,0, 59,241,89,0,0,0,0,59,238,34,0,0,0,0,12,232,89,0,0,59,238,127,225,21,0,0, 0,59,238,34,0,59,238,34,59,238,34,0,59,238,34,59,238,34,0,59,238,34,59, 238,34,0,59,238,34,59,238,34,59,238,34,59,238,34,59,238,34,0,138,255,255, 255,255,201,0,59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59, 241,89,0,59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59,241, 89,0,12,235,255,255,255,255,255,255,166,138,201,0,59,157,175,201,0,59,241, 89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,59,241,89, 0,59,241,89,12,235,125,0,175,166,0,59,238,34,0,0,138,225,34,235,125,0,175, 166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,127,0,89,255,255,255,251,89,0,89,255,255,255,251, 89,0,89,255,255,255,251,89,0,89,255,255,255,251,89,0,89,255,255,255,251, 89,0,138,255,255,255,247,34,0,175,255,255,255,255,255,255,255,255,251,127, 201,0,0,0,0,59,245,255,255,255,251,89,59,245,255,255,255,251,89,59,245, 255,255,255,251,89,59,245,255,255,255,251,89,59,238,34,59,238,34,59,238, 34,59,238,34,138,247,34,0,0,138,201,0,59,241,89,0,59,241,89,59,238,34,0, 12,232,89,59,238,34,0,12,232,89,0,59,238,34,0,12,232,89,59,238,34,0,12, 232,89,59,238,34,0,12,232,89,0,0,0,0,0,0,0,0,0,0,175,201,7,176,21,138,201, 0,59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,59, 241,89,0,59,241,89,0,175,201,12,232,89,0,59,238,34,0,0,138,225,21,175,201, 12,232,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,59,241,89,0,59,241,89,59,241,89,0,59, 241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89, 138,247,34,0,59,238,34,138,225,21,0,12,232,89,0,0,0,0,138,201,0,0,0,0,59, 238,34,0,0,0,0,59,238,34,0,0,0,0,59,238,34,0,0,0,0,59,238,34,0,0,0,0,59, 238,34,59,238,34,59,238,34,59,238,34,175,201,0,0,0,138,166,0,59,241,89, 0,59,241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,59,241,89,0,59, 241,89,59,241,89,0,59,241,89,59,241,89,0,59,241,89,0,0,0,0,12,235,166,0, 0,0,138,201,134,89,0,175,166,0,59,241,89,0,59,241,89,59,241,89,0,59,241, 89,59,241,89,0,59,241,89,0,59,241,89,0,59,241,89,0,89,247,124,225,21,0, 59,238,34,0,0,138,201,0,89,247,124,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,89,247, 34,0,89,251,89,89,247,34,0,89,251,89,89,247,34,0,89,251,89,89,247,34,0, 89,251,89,89,247,34,0,89,251,89,175,201,0,0,175,247,34,175,201,0,0,59,245, 225,21,0,7,199,94,245,125,0,0,0,7,206,166,0,7,199,34,7,206,166,0,7,199, 34,7,206,166,0,7,199,34,7,206,166,0,7,199,34,59,238,34,59,238,34,59,238, 34,59,238,34,138,247,34,0,12,232,89,0,59,241,89,0,59,241,89,7,206,166,0, 138,225,21,7,206,166,0,138,225,21,0,7,206,166,0,138,225,21,7,206,166,0, 138,225,21,7,206,166,0,138,225,21,0,0,0,0,12,235,166,0,0,0,59,245,166,0, 59,241,89,0,12,235,125,0,175,251,89,12,235,125,0,175,251,89,12,235,125, 0,175,251,89,0,12,235,125,0,175,251,89,0,7,206,255,125,0,0,59,238,34,0, 12,235,125,0,7,206,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,175,255,255,232, 241,89,0,175,255,255,232,241,89,0,175,255,255,232,241,89,0,175,255,255, 232,241,89,0,175,255,255,232,241,89,12,235,255,255,166,238,34,12,235,255, 255,225,21,89,255,255,251,89,0,89,255,255,255,201,0,12,235,255,251,89,0, 0,12,235,255,251,89,0,0,12,235,255,251,89,0,0,12,235,255,251,89,0,59,238, 34,59,238,34,59,238,34,59,238,34,0,138,255,255,255,125,0,0,59,241,89,0, 59,241,89,0,12,235,255,247,34,0,0,12,235,255,247,34,0,0,0,12,235,255,247, 34,0,0,12,235,255,247,34,0,0,12,235,255,247,34,0,0,0,0,0,0,0,0,0,0,0,7, 206,255,255,225,21,0,0,0,89,255,255,166,241,89,0,89,255,255,166,241,89, 0,89,255,255,166,241,89,0,0,89,255,255,166,241,89,0,0,138,247,34,0,0,59, 245,166,255,255,166,0,0,0,138,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,215,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,232,89,0,0,0,59,238,34,0,0,0,0,0, 12,232,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,12,235,255,125,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,138,225,21,0,0,0,59,238,34,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,0,127,127,0,127,127, 0,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // Large font anti-aliased const int FONT2AA_BM_W = 276; const int FONT2AA_BM_H = 120; static const unsigned char s_Font2AA[] = { 127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, 4,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,0,0,0,0,0,0,0,0, 0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,59,245,125,175,225,21, 0,0,0,0,0,0,0,0,0,0,0,0,0,138,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,59,241,89,0,0,12,235,201,89,255,166,0,0,0,0,0,172,89,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,225,21,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,0, 0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,138,247,34,0,12, 232,89,138,225,21,0,0,0,0,138,125,7,199,34,0,0,0,0,138,125,0,0,0,0,138, 255,255,201,0,0,0,59,215,21,0,0,0,0,59,245,255,255,166,0,0,0,59,241,89, 0,7,206,201,0,0,89,251,89,0,59,215,21,172,89,59,192,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,166,0,0,138,255,251,89,0,0,0,0,0, 138,201,0,0,0,7,206,255,255,255,166,0,0,7,206,255,255,255,201,0,0,0,0,0, 0,138,251,89,0,0,175,255,255,255,255,225,21,0,0,12,235,255,255,125,89,255, 255,255,255,255,251,89,0,12,235,255,255,225,21,0,0,59,245,255,255,166,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,59,245,255,255,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, 4,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,89,247, 34,0,12,232,89,138,201,0,0,0,0,7,202,89,59,215,21,0,0,12,235,255,255,255, 166,0,59,241,89,12,235,125,0,0,172,89,0,0,0,0,7,206,166,0,89,251,89,0,0, 12,228,34,0,89,247,34,0,0,0,175,201,0,0,89,251,191,194,247,34,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,232,89,0,175,201,0,12,235, 125,0,0,138,255,255,201,0,0,0,12,182,0,0,59,245,125,0,12,206,21,0,12,235, 166,0,0,0,0,89,255,251,89,0,0,175,201,0,0,0,0,0,0,89,255,125,0,0,0,0,0, 0,0,0,89,251,89,12,235,166,0,7,206,201,0,59,245,125,0,12,235,166,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,89,166,0,0,138,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,0, 0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,89,247,34,0,12, 228,34,89,201,0,0,0,0,12,206,21,89,166,0,0,12,235,125,138,125,59,192,0, 89,247,34,7,206,166,0,89,201,0,0,0,0,0,12,235,125,0,12,232,89,0,0,12,228, 34,0,175,201,0,0,0,0,59,241,89,0,0,7,206,166,0,0,0,0,0,0,0,138,166,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,225,21,59,241,89,0,0,138,225,21,0, 0,0,175,201,0,0,0,0,0,0,0,7,206,201,0,0,0,0,0,0,175,201,0,0,0,59,241,132, 241,89,0,0,175,201,0,0,0,0,0,7,206,166,0,0,0,0,0,0,0,0,7,206,201,0,59,241, 89,0,0,138,225,21,138,225,21,0,0,138,225,21,89,255,125,0,0,89,255,125,0, 0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,138,201,0,0,0,0,0,0,0,0, 0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,0,0,0,0,0, 0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,89,247,34,0,0,0,0,0,0,0, 0,89,255,255,255,255,255,255,255,125,59,238,34,138,125,0,0,0,89,247,34, 7,206,166,7,202,89,0,0,0,0,0,0,175,225,21,138,225,21,0,0,0,0,0,12,235,125, 0,0,0,0,7,206,125,0,89,251,191,194,247,34,0,0,0,0,0,138,166,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,138,166,0,89,247,34,0,0,89,247,34,0,0,0,175,201, 0,0,0,0,0,0,0,12,235,166,0,0,0,0,0,59,245,125,0,0,12,235,125,59,241,89, 0,0,175,201,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,89,247,34,0,12,235,201, 0,0,175,201,0,138,225,21,0,0,89,247,34,89,255,125,0,0,89,255,125,0,0,0, 0,0,12,235,255,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,175,255,251,89,0,0,0,0, 0,0,0,0,138,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,0,0,0, 0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,89,247,34,0,0,0,0,0, 0,0,0,0,0,175,125,7,199,34,0,0,12,235,166,138,125,0,0,0,59,241,89,12,235, 125,89,201,12,235,255,251,89,0,0,7,206,255,166,0,59,241,89,0,0,0,59,238, 34,0,0,0,0,0,175,166,59,215,21,172,89,59,192,0,0,0,0,0,138,166,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,125,0,138,247,34,0,0,89,247,34,0,0,0, 175,201,0,0,0,0,0,0,0,89,251,89,0,0,0,89,255,247,34,0,0,7,206,166,0,59, 241,89,0,0,175,255,255,255,225,21,0,89,251,226,255,255,247,34,0,0,0,7,206, 166,0,0,0,12,235,255,255,201,0,0,89,255,125,0,0,138,247,34,0,0,0,0,0,0, 0,0,0,0,0,89,255,255,166,0,0,0,0,0,175,255,255,255,255,255,255,225,21,0, 0,0,0,59,245,255,201,0,0,0,0,0,175,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0, 0,0,89,225,21,0,0,0,0,0,0,0,0,0,7,199,34,59,215,21,0,0,0,59,245,255,255, 201,0,0,0,138,255,255,201,12,228,34,175,166,0,138,201,0,12,235,125,89,255, 125,59,241,89,0,0,0,59,238,34,0,0,0,0,0,138,201,0,0,0,172,89,0,0,0,7,206, 255,255,255,255,255,255,247,34,0,0,0,0,89,255,255,255,166,0,0,0,0,0,59, 238,34,0,138,247,34,0,0,89,247,34,0,0,0,175,201,0,0,0,0,0,0,59,245,166, 0,0,0,0,0,0,12,235,166,0,138,201,0,0,59,241,89,0,0,0,0,0,12,235,201,0,138, 251,89,0,0,175,225,21,0,0,89,247,34,0,0,7,206,166,0,175,255,166,0,0,89, 255,255,255,223,247,34,0,0,0,0,0,0,0,0,0,0,175,247,34,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,225,21,0,0,175,225,21,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0, 0,0,127,0,0,0,0,0,59,215,21,0,0,0,0,0,0,0,12,235,255,255,255,255,255,255, 166,0,0,0,0,138,125,175,225,21,0,0,0,0,0,138,166,7,206,125,0,89,247,34, 138,225,21,0,89,255,166,215,21,0,0,0,59,238,34,0,0,0,0,0,138,201,0,0,0, 0,0,0,0,0,0,0,0,0,138,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,201,0, 0,89,247,34,0,0,89,247,34,0,0,0,175,201,0,0,0,0,0,12,235,201,0,0,0,0,0, 0,0,0,138,225,21,175,255,255,255,255,255,255,125,0,0,0,0,0,138,247,34,89, 247,34,0,0,59,241,89,0,7,206,166,0,0,0,138,247,34,0,0,138,247,34,0,0,0, 0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,89,255,255,166,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,59,245,255,201,0,0,0,0,175,201,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0, 127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,166,0,175,125,0,0,0,0,0,0,138, 125,89,247,34,0,0,0,0,12,228,34,7,206,125,0,89,247,34,138,247,34,0,0,89, 255,166,0,0,0,0,59,238,34,0,0,0,0,0,175,166,0,0,0,0,0,0,0,0,0,0,0,0,138, 166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,125,0,0,59,241,89,0,0,138,225, 21,0,0,0,175,201,0,0,0,0,12,235,201,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0, 0,59,241,89,0,0,0,0,0,0,138,225,21,59,241,89,0,0,59,241,89,0,89,247,34, 0,0,0,138,247,34,0,0,89,251,89,0,0,0,0,7,206,166,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,12,235,255,225,21,0,0,175,255,255,255,255,255,255,225,21,0,0,175, 255,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,89,247, 34,0,0,0,0,0,0,0,0,0,175,125,7,199,34,0,0,0,89,201,0,138,125,175,201,0, 0,0,0,0,138,166,0,0,175,166,0,138,201,0,89,255,166,0,0,89,255,255,125,0, 0,0,12,235,125,0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,0,0,0,0,138,166,0,0,0, 0,0,138,255,125,0,0,0,0,0,0,175,247,34,59,238,34,0,0,0,175,201,0,12,235, 125,0,0,0,0,175,201,0,0,0,12,235,166,0,0,0,0,0,89,166,0,0,59,245,166,0, 0,0,0,0,59,241,89,0,59,215,21,0,12,235,166,0,7,206,201,0,0,175,225,21,7, 206,166,0,0,0,0,59,245,166,0,7,206,225,21,0,0,0,0,175,225,21,0,89,255,125, 0,0,12,235,201,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,138,201, 0,0,0,0,0,0,0,0,0,175,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0,0,0,89,247, 34,0,0,0,0,0,0,0,0,7,199,34,59,215,21,0,0,0,12,235,255,255,255,201,0,0, 0,0,0,59,215,21,0,0,12,235,255,251,89,0,0,89,255,255,255,201,0,89,255,0, 0,0,0,175,201,0,0,0,0,59,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175, 201,0,0,0,0,0,0,0,175,247,34,138,201,0,0,0,0,0,138,255,251,89,0,0,0,138, 255,255,255,255,166,0,89,255,255,255,255,255,247,34,12,235,255,255,255, 166,0,0,0,0,0,0,59,241,89,0,12,235,255,255,255,166,0,0,0,7,206,255,255, 225,21,0,138,247,34,0,0,0,0,0,59,245,255,255,201,0,0,0,175,255,255,201, 0,0,0,89,255,125,0,0,89,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,175,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,4,4,4,4,4,4,4,4,52,4,4,4,4,4,4,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,125,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,247,34,0,0,0,175,201,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,232,89,0,0,0,0,0,0,0,0,0,0,175,125, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,125,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,201,0,0,89,251,89,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,201,0,0,0,0,0,0,0,0,0,0,12,232,89, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,232,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,0,0,0,0,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,201,0,0,201,201,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,127,127,127,0,127,127,127, 127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,0,127,127,0,127,127,127,127,0,127,127, 127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 127,0,127,127,127,0,127,127,127,127,0,127,127,127,0,127,127,127,127,0,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,255, 201,0,138,201,0,0,0,0,89,255,255,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,127,0,0,0,0,175,255,255,255,247,34,0,0,0,0,0,7,206,251,89,0,0,12,0, 235,255,255,255,255,201,0,0,0,0,59,245,255,255,255,201,12,0,235,255,255, 255,255,166,0,0,0,12,235,255,255,255,255,255,127,12,235,255,255,255,255, 251,89,0,0,12,235,255,255,255,251,89,12,235,166,0,0,0,12,235,125,89,255, 255,255,201,0,0,175,255,255,225,21,12,235,166,0,0,7,206,251,102,0,235,166, 0,0,0,0,12,235,251,89,0,0,0,89,255,225,21,12,235,251,89,0,0,12,235,125, 0,0,0,138,255,255,166,0,0,0,12,235,255,255,255,251,89,0,0,0,0,175,255,255, 201,0,0,0,12,235,255,255,255,251,89,0,0,0,12,235,255,255,255,247,47,235, 255,255,255,255,255,255,255,138,0,235,125,0,0,0,59,245,133,206,166,0,0, 0,0,59,245,255,133,201,0,0,0,138,251,89,0,0,12,235,133,206,247,34,0,0,0, 175,229,216,225,21,0,0,0,138,247,124,255,255,255,255,255,255,125,7,206, 125,0,0,0,59,238,34,0,0,0,0,0,12,235,125,0,0,0,0,175,247,34,0,0,0,0,0,0, 0,0,0,0,127,0,0,59,245,166,0,0,0,59,245,166,0,0,0,0,59,245,255,166,0,0, 12,0,235,166,0,0,59,245,125,0,0,138,255,125,0,0,7,202,102,0,235,166,0,0, 59,245,225,21,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,0,89,255,166, 0,0,0,89,127,12,235,166,0,0,0,12,235,125,0,12,235,125,0,0,0,0,0,138,225, 21,12,235,166,0,7,206,225,21,12,0,235,166,0,0,0,0,12,235,255,166,0,0,7, 206,255,225,21,12,235,255,201,0,0,12,235,125,0,59,245,166,0,0,138,251,89, 0,12,235,166,0,0,138,251,89,0,89,255,125,0,0,89,255,125,0,12,235,166,0, 0,138,251,89,0,12,235,166,0,0,7,202,89,0,0,0,138,225,21,0,0,12,0,235,125, 0,0,0,59,245,125,138,225,21,0,0,0,138,225,151,34,247,34,0,0,175,255,125, 0,0,89,247,34,12,235,166,0,0,89,247,34,59,245,125,0,0,59,245,125,0,0,0, 0,0,138,247,34,7,206,125,0,0,0,7,206,125,0,0,0,0,0,12,235,125,0,0,0,138, 225,187,201,0,0,0,0,0,0,0,0,0,0,127,0,12,232,89,0,0,0,0,0,12,232,89,0,0, 0,138,225,151,225,21,0,12,0,235,166,0,0,12,235,166,0,12,235,166,0,0,0,0, 0,12,0,235,166,0,0,0,12,235,166,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0, 0,0,12,235,166,0,0,0,0,0,0,12,235,166,0,0,0,12,235,125,0,12,235,125,0,0, 0,0,0,138,225,21,12,235,166,0,175,225,21,0,12,0,235,166,0,0,0,0,12,235, 166,238,34,0,59,215,187,225,21,12,235,166,245,125,0,12,235,125,12,235,125, 0,0,0,0,138,247,34,12,235,166,0,0,12,235,166,12,235,125,0,0,0,0,138,247, 34,12,235,166,0,0,12,235,166,0,89,247,34,0,0,0,0,0,0,0,0,138,225,21,0,0, 12,0,235,125,0,0,0,59,245,125,59,241,89,0,0,7,206,166,59,0,241,89,0,12, 232,194,201,0,0,138,225,21,0,89,251,89,12,235,166,0,0,138,247,34,7,206, 201,0,0,0,0,0,59,245,125,0,7,206,125,0,0,0,0,138,201,0,0,0,0,0,12,235,125, 0,0,59,241,89,12,235,166,0,0,0,0,0,0,0,0,0,127,0,175,166,0,59,245,255,255, 247,34,138,201,0,0,7,206,166,59,241,89,0,12,0,235,166,0,0,89,251,89,0,89, 247,34,0,0,0,0,0,12,0,235,166,0,0,0,0,138,225,21,12,235,166,0,0,0,0,0,12, 235,166,0,0,0,0,0,89,247,34,0,0,0,0,0,0,12,235,166,0,0,0,12,235,125,0,12, 235,125,0,0,0,0,0,138,225,21,12,235,166,175,247,34,0,0,12,0,235,166,0,0, 0,0,12,235,133,206,166,0,175,166,175,225,21,12,235,125,138,225,21,12,235, 125,89,247,34,0,0,0,0,59,245,125,12,235,166,0,0,12,235,166,89,247,34,0, 0,0,0,59,245,125,12,235,166,0,0,12,235,125,0,89,255,125,0,0,0,0,0,0,0,0, 138,225,21,0,0,12,0,235,125,0,0,0,59,245,125,7,206,201,0,0,59,241,89,7, 0,206,166,0,59,215,111,225,21,7,206,166,0,0,0,175,225,187,225,21,0,0,12, 235,166,89,247,34,0,0,0,0,7,206,201,0,0,7,206,125,0,0,0,0,89,225,21,0,0, 0,0,12,235,125,0,12,235,166,0,0,59,241,89,0,0,0,0,0,0,0,0,127,0,202,89, 12,235,125,0,12,228,34,59,215,0,0,59,241,89,7,206,166,0,12,0,235,255,255, 255,255,166,0,0,138,225,21,0,0,0,0,0,12,0,235,166,0,0,0,0,89,247,34,12, 235,255,255,255,255,247,34,12,235,255,255,255,255,247,0,163,225,21,0,0, 0,0,0,0,12,235,255,255,255,255,255,255,125,0,12,235,125,0,0,0,0,0,138,225, 21,12,235,255,247,34,0,0,0,12,0,235,166,0,0,0,0,12,235,125,89,225,34,228, 34,175,225,21,12,235,125,12,235,125,12,235,125,138,225,21,0,0,0,0,12,235, 166,12,235,166,0,0,175,247,34,138,225,21,0,0,0,0,12,235,166,12,235,166, 0,0,175,225,21,0,0,175,255,255,225,21,0,0,0,0,0,138,225,21,0,0,12,0,235, 125,0,0,0,59,245,125,0,138,247,34,0,138,225,21,0,0,175,201,0,138,201,12, 232,89,12,235,125,0,0,0,12,235,251,89,0,0,0,0,89,255,255,125,0,0,0,0,0, 138,247,34,0,0,7,206,125,0,0,0,0,12,232,89,0,0,0,0,12,235,125,7,206,201, 0,0,0,0,138,251,89,0,0,0,0,0,0,0,127,7,228,34,89,225,21,0,12,228,34,12, 228,0,0,138,225,21,0,138,225,21,12,0,235,166,0,0,12,235,201,0,138,225,21, 0,0,0,0,0,12,0,235,166,0,0,0,0,89,247,34,12,235,166,0,0,0,0,0,12,235,166, 0,0,0,0,0,138,225,21,0,12,235,255,255,127,12,235,166,0,0,0,12,235,125,0, 12,235,125,0,0,0,0,0,138,225,21,12,235,229,216,225,21,0,0,12,0,235,166, 0,0,0,0,12,235,125,12,235,223,201,0,175,225,21,12,235,125,0,138,225,34, 235,125,138,225,21,0,0,0,0,12,235,166,12,235,255,255,255,247,34,0,138,225, 21,0,0,0,0,12,235,166,12,235,255,255,255,166,0,0,0,0,0,0,89,255,255,247, 34,0,0,0,138,225,21,0,0,12,0,235,125,0,0,0,59,245,125,0,59,245,125,7,206, 166,0,0,0,89,247,34,175,125,7,206,125,89,247,34,0,0,0,12,235,251,89,0,0, 0,0,7,206,225,21,0,0,0,0,59,245,125,0,0,0,7,206,125,0,0,0,0,0,175,166,0, 0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,12,228,34,89,225, 21,0,12,228,34,59,215,0,7,206,255,255,255,255,251,89,12,0,235,166,0,0,0, 138,247,0,124,247,34,0,0,0,0,0,12,0,235,166,0,0,0,0,138,225,21,12,235,166, 0,0,0,0,0,12,235,166,0,0,0,0,0,89,247,34,0,0,0,0,175,127,12,235,166,0,0, 0,12,235,125,0,12,235,125,0,0,0,0,0,138,225,21,12,235,166,59,245,201,0, 0,12,0,235,166,0,0,0,0,12,235,125,0,138,251,89,0,175,225,21,12,235,125, 0,12,235,138,235,125,89,247,34,0,0,0,0,59,245,125,12,235,166,0,0,0,0,0, 89,247,34,0,0,0,0,59,245,125,12,235,166,0,175,247,34,0,0,0,0,0,0,0,59,245, 166,0,0,0,138,225,21,0,0,12,0,235,125,0,0,0,59,241,89,0,7,206,201,59,241, 89,0,0,0,59,241,102,232,89,0,138,201,138,225,21,0,0,0,175,201,175,225,21, 0,0,0,0,175,225,21,0,0,0,7,206,201,0,0,0,0,7,206,125,0,0,0,0,0,89,225,21, 0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,12,232,89,59,241, 89,0,89,247,34,89,201,0,59,241,89,0,0,7,206,166,12,0,235,166,0,0,0,138, 225,0,81,245,166,0,0,0,0,0,12,0,235,166,0,0,0,12,235,166,0,12,235,166,0, 0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,175,127,12,235,166,0,0, 0,12,235,125,0,12,235,125,0,0,0,0,0,138,225,21,12,235,166,0,89,255,166, 0,12,0,235,166,0,0,0,0,12,235,125,0,12,182,0,0,175,225,21,12,235,125,0, 0,138,232,245,125,12,235,125,0,0,0,0,138,247,34,12,235,166,0,0,0,0,0,12, 235,125,0,0,0,0,138,247,34,12,235,166,0,7,206,225,21,0,0,0,0,0,0,12,235, 166,0,0,0,138,225,21,0,0,12,0,235,166,0,0,0,89,251,89,0,0,138,247,163,225, 21,0,0,0,7,206,200,215,21,0,89,225,187,166,0,0,0,89,251,89,12,235,166,0, 0,0,0,175,225,21,0,0,0,138,247,34,0,0,0,0,7,206,125,0,0,0,0,0,12,232,89, 0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,12,175,166,0,89, 255,255,210,235,255,255,125,0,138,225,21,0,0,0,138,247,47,0,235,166,0,0, 59,245,166,0,0,138,255,125,0,0,7,202,102,0,235,166,0,0,12,235,225,21,0, 12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,0,138,255,125,0,0,0,175,127,12, 235,166,0,0,0,12,235,125,0,12,235,125,0,0,0,0,7,206,201,0,12,235,166,0, 0,138,255,125,12,0,235,166,0,0,0,12,0,235,125,0,0,0,0,0,175,225,21,12,235, 125,0,0,12,235,255,125,0,89,255,125,0,0,89,251,89,0,12,235,166,0,0,0,0, 0,0,89,255,125,0,0,89,255,125,0,12,235,166,0,0,12,235,201,0,138,166,0,0, 0,138,251,89,0,0,0,138,225,21,0,0,0,0,138,247,34,0,7,206,225,21,0,0,12, 235,255,166,0,0,0,0,0,175,255,201,0,0,12,235,255,125,0,0,12,235,166,0,0, 138,251,89,0,0,0,175,225,21,0,0,89,251,89,0,0,0,0,0,7,206,125,0,0,0,0,0, 0,175,166,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,59,241, 89,0,0,0,0,0,0,0,0,7,206,166,0,0,0,0,59,245,138,0,235,255,255,255,255,125, 0,0,0,0,59,245,255,255,255,201,12,0,235,255,255,255,255,166,0,0,0,12,235, 255,255,255,255,255,127,12,235,166,0,0,0,0,0,0,0,59,245,255,255,255,225, 21,12,235,166,0,0,0,12,235,125,89,255,255,255,210,127,235,255,255,225,21, 0,12,235,166,0,0,0,175,255,127,0,235,255,255,255,247,47,0,235,125,0,0,0, 0,0,175,225,21,12,235,125,0,0,0,138,255,125,0,0,0,175,255,255,201,0,0,0, 12,235,166,0,0,0,0,0,0,0,0,175,255,255,201,0,0,0,12,235,166,0,0,0,89,255, 225,34,235,255,255,255,247,34,0,0,0,0,138,225,21,0,0,0,0,0,138,255,255, 255,201,0,0,0,0,0,175,251,89,0,0,0,0,0,89,255,166,0,0,7,206,247,34,0,7, 206,225,21,0,0,7,206,225,21,0,0,175,225,21,0,0,138,255,255,255,255,255, 255,166,7,206,125,0,0,0,0,0,0,138,201,0,0,0,12,235,125,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,127,0,0,89,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,201,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,7,206,125,0,0,0,0,0,0,59,238,34,0,0,12,235,125,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,0,0,0,7,206,255,255,255,225,21,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,251,89,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,7,206,125,0,0,0,0,0,0,7,206,125,0,0,12,235,125,0,0,0, 0,0,0,0,0,0,0,245,255,255,255,255,255,255,127,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138, 255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,255,201,0,0,0,0,0,0,89,89,255,255, 255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,59,245,166,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,89,247,34,0,0,0,0,0,0,0,0,0,0,12,235, 125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,12,235, 255,247,0,0,0,0,0,0,0,12,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125, 0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,255,251,89,0,7,206,125,0,89,255,251,89, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,84,84,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,7,206, 125,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138, 225,21,0,0,0,0,0,0,0,0,0,175,201,0,0,0,0,0,0,0,0,0,12,12,235,125,0,0,0, 0,0,59,245,102,0,89,247,34,12,235,125,0,0,0,0,0,12,235,125,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 59,241,89,0,0,0,7,206,125,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4,4,4,4,4,4,4,4,100,252,252,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, 235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,12,0, 235,125,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125, 0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235, 125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,247,34,0,0,0,7,206,125,0,0,0,59,238, 34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,20,236,252,164,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,0,0,0,0,0,0,12,235,255,255,255,166,0,12,235,166,245,255,247,34,0,0,12, 235,255,255,247,34,0,34,235,255,255,255,225,21,0,12,235,255,255,225,29, 0,206,255,255,255,127,0,12,235,255,255,255,225,21,12,235,138,235,255,247, 34,0,12,235,102,175,255,247,34,12,235,125,0,59,245,201,0,12,235,125,12, 0,235,166,245,255,225,29,206,255,251,89,0,12,235,138,235,255,247,34,0,0, 12,235,255,255,201,0,0,12,235,166,245,255,251,89,0,0,12,235,255,255,255, 225,21,12,235,138,235,247,127,34,138,255,255,255,206,0,206,255,255,255, 201,59,241,89,0,0,89,247,42,206,201,0,0,0,138,225,187,201,0,0,138,225,21, 0,59,241,187,226,247,34,0,7,206,206,206,201,0,0,0,138,225,151,255,255,255, 255,247,0,0,89,247,34,0,0,0,7,206,125,0,0,0,59,238,34,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,4,4,4,4,4,4,4,148,252,236,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,12,206, 21,0,59,245,125,12,235,247,34,0,138,225,21,12,235,166,0,0,134,102,0,235, 166,0,0,138,225,21,12,235,125,0,0,175,201,12,0,235,125,0,0,12,235,166,0, 0,138,225,21,12,235,247,34,0,175,201,0,12,235,102,0,89,247,34,12,235,125, 12,235,166,0,0,12,235,125,12,0,235,225,21,12,235,251,89,0,175,201,0,12, 235,247,34,0,175,201,0,12,235,166,0,7,206,201,0,12,235,225,21,0,175,225, 21,12,235,166,0,0,138,225,21,12,235,247,34,0,0,89,247,34,0,12,206,34,0, 235,125,0,0,59,241,89,0,0,89,247,34,89,247,34,0,7,206,166,138,225,21,7, 206,251,89,0,89,225,138,34,235,201,0,138,225,21,89,247,34,0,7,206,166,0, 0,0,7,206,166,0,0,89,225,21,0,0,0,7,206,125,0,0,0,59,241,89,0,0,0,0,138, 251,89,0,0,7,202,89,0,0,4,4,4,4,4,4,52,252,252,108,4,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0, 0,0,0,0,0,0,0,0,7,206,102,12,235,125,0,0,59,241,89,138,225,21,0,0,0,34, 89,225,21,0,0,138,225,21,89,225,21,0,0,89,247,47,0,235,125,0,0,89,225,21, 0,0,138,225,21,12,235,125,0,0,89,247,34,12,235,102,0,89,247,34,12,235,138, 235,166,0,0,0,12,235,125,12,0,235,125,0,7,206,166,0,0,138,225,21,12,235, 125,0,0,89,247,34,138,225,21,0,0,59,238,34,12,235,125,0,0,59,241,89,89, 225,21,0,0,138,225,21,12,235,125,0,0,0,138,225,21,0,0,0,12,0,235,125,0, 0,59,241,89,0,0,89,247,34,12,235,125,0,59,241,89,59,238,34,12,228,198,166, 0,175,166,59,0,89,251,132,241,89,0,12,235,125,0,59,238,34,0,0,0,138,225, 21,0,12,235,166,0,0,0,0,7,206,125,0,0,0,0,175,201,0,0,0,138,166,12,235, 166,0,12,232,89,0,0,12,84,4,4,4,4,204,252,204,4,4,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0, 0,0,0,59,245,255,255,255,102,12,235,125,0,0,12,235,125,175,201,0,0,0,0, 0,175,201,0,0,0,138,225,21,175,255,255,255,255,255,247,47,0,235,125,0,0, 175,201,0,0,0,138,225,21,12,235,125,0,0,89,247,34,12,235,102,0,89,247,34, 12,235,255,225,21,0,0,0,12,235,125,12,0,235,125,0,7,206,166,0,0,138,225, 21,12,235,125,0,0,89,247,34,175,201,0,0,0,12,232,89,12,235,125,0,0,12,235, 125,175,201,0,0,0,138,225,21,12,235,125,0,0,0,59,245,255,247,34,0,12,0, 235,125,0,0,59,241,89,0,0,89,247,34,0,175,201,0,138,201,0,12,235,125,89, 201,89,225,29,206,125,12,0,0,175,255,166,0,0,0,175,201,0,138,201,0,0,0, 89,251,89,0,138,247,34,0,0,0,0,0,7,206,125,0,0,0,0,0,89,255,125,7,202,89, 0,89,251,89,89,201,0,0,0,172,252,84,4,4,100,252,252,60,4,4,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,0,0,0,0,0,0,89,255,166,0,7,206,102,12,235,125,0,0,12,235,125,175,201, 0,0,0,0,0,175,201,0,0,0,138,225,21,175,201,0,0,0,0,0,12,0,235,125,0,0,175, 201,0,0,0,138,225,21,12,235,125,0,0,89,247,34,12,235,102,0,89,247,34,12, 235,138,235,201,0,0,0,12,235,125,12,0,235,125,0,7,206,166,0,0,138,225,21, 12,235,125,0,0,89,247,34,175,201,0,0,0,12,232,89,12,235,125,0,0,12,235, 125,175,201,0,0,0,138,225,21,12,235,125,0,0,0,0,0,138,255,255,201,12,0, 235,125,0,0,59,241,89,0,0,89,247,34,0,89,247,42,206,125,0,0,175,166,175, 125,12,232,102,232,89,0,0,0,175,255,201,0,0,0,89,247,47,235,125,0,0,12, 235,166,0,0,0,12,235,125,0,0,0,0,7,206,125,0,0,0,0,138,201,0,0,12,232,89, 0,0,59,245,225,21,0,0,0,196,252,244,60,20,236,252,156,4,4,4,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,0,0,0,0,0,0,175,201,0,0,7,206,102,12,235,125,0,0,59,241,89,138,225,21, 0,0,0,34,89,225,21,0,0,138,225,21,138,247,34,0,0,0,0,12,0,235,125,0,0,138, 225,21,0,0,138,225,21,12,235,125,0,0,89,247,34,12,235,102,0,89,247,34,12, 235,125,59,245,125,0,0,12,235,125,12,0,235,125,0,7,206,166,0,0,138,225, 21,12,235,125,0,0,89,247,34,138,225,21,0,0,89,247,34,12,235,125,0,0,59, 241,89,138,225,21,0,0,138,225,21,12,235,125,0,0,0,0,0,0,0,89,247,47,0,235, 125,0,0,59,241,89,0,0,89,247,34,0,12,235,166,238,34,0,0,138,210,228,34, 0,175,166,215,21,0,0,89,251,159,251,89,0,0,12,235,191,247,34,0,0,175,225, 21,0,0,0,0,138,225,21,0,0,0,7,206,125,0,0,0,12,232,89,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,20,220,252,236,180,252,244,28,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0, 138,225,21,0,138,255,102,12,235,125,0,7,206,201,0,12,235,166,0,0,134,132, 0,245,125,0,59,245,225,21,12,235,201,0,0,12,206,34,0,235,125,0,0,59,245, 125,0,12,235,225,21,12,235,125,0,0,89,247,34,12,235,102,0,89,247,34,12, 235,125,0,138,251,89,0,12,235,125,12,0,235,125,0,7,206,166,0,0,138,225, 21,12,235,125,0,0,89,247,34,12,235,166,0,7,206,201,0,12,235,125,0,7,206, 201,0,59,245,125,0,12,235,225,21,12,235,125,0,0,0,138,125,0,0,138,225,29, 0,206,166,0,0,7,206,166,0,59,245,247,34,0,0,175,255,201,0,0,0,59,245,225, 21,0,89,255,201,0,0,12,235,166,0,175,225,21,0,0,138,255,166,0,0,89,251, 89,0,0,0,0,0,89,247,34,0,0,0,7,206,125,0,0,0,59,238,34,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,4,36,236,252,252,252,108,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0, 7,206,255,255,171,206,102,12,232,226,255,255,225,21,0,0,12,235,255,255, 247,34,0,89,255,255,247,163,225,21,0,7,206,255,255,247,34,12,0,235,125, 0,0,0,89,255,255,247,163,225,21,12,235,125,0,0,89,247,34,12,235,102,0,89, 247,34,12,235,125,0,0,175,251,34,0,235,125,12,0,235,125,0,7,206,166,0,0, 138,225,21,12,235,125,0,0,89,247,34,0,12,235,255,255,201,0,0,12,235,255, 255,255,225,21,0,0,89,255,255,247,163,225,21,12,235,125,0,0,0,89,255,255, 255,247,34,0,0,89,255,255,127,0,59,245,255,225,111,247,34,0,0,59,245,125, 0,0,0,12,235,166,0,0,59,245,125,7,0,206,225,21,0,12,235,201,0,0,59,241, 89,0,0,175,255,255,255,255,247,0,0,89,247,34,0,0,0,7,206,125,0,0,0,59,238, 34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,60,252,252,204,4,4,4,4,4,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,201,0,0,0,0,0,0,0,0,0,0,0,0,0, 89,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,89,247,34,0,0,0,7, 206,125,0,0,0,59,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,76,252,60,4,4, 4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,199,34,0,12,232,89,0,0, 0,0,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0, 0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,166,0,0,0,0,0,0,0,0, 0,0,0,12,235,125,0,0,0,7,206,125,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12,235,255,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,255,251,89,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235, 125,0,0,0,0,0,0,0,0,0,0,138,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89, 247,34,0,0,0,0,0,0,0,0,0,0,0,0,89,255,251,89,0,7,206,125,0,89,255,247,34, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,0,127,127,127,0,127,127,127,127,127,127,127,0, 127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127, 127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,125,0,175,166,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,206,125,0,175,166, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,225,21,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,125,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,125,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,166,0,138,201,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,166,0,138,201,0,7,206,166,12,235, 125,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0,175,125, 0,0,0,0,0,175,171,206,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255,125,0, 31,206,130,255,166,175,247,34,0,0,89,255,125,175,247,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,247,34,138,166,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,59,241,132,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,59,241,132,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0, 59,245,255,255,255,125,0,12,235,255,255,255,255,255,225,21,0,0,0,0,0,0, 0,0,175,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,0,0, 0,0,175,125,0,0,0,0,89,225,21,59,238,34,0,0,138,255,255,201,0,0,0,59,215, 21,0,0,0,0,0,0,0,0,0,12,235,255,255,255,247,34,0,0,0,0,0,0,0,12,235,255, 255,255,255,255,255,255,255,251,89,0,12,235,255,255,255,255,255,225,21, 0,89,255,255,255,255,255,255,125,0,12,235,255,255,255,255,255,225,21,0, 0,12,235,255,255,255,255,255,225,21,7,206,201,0,50,206,56,255,201,12,235, 125,0,0,138,225,29,206,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,7,202,89,89,255,225,21,0,89,255,255,255,225,81,245,201,0,138,251, 89,0,0,138,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,255, 255,255,255,225,21,0,0,0,138,255,166,7,206,225,21,0,0,0,138,247,34,0,0, 0,0,127,0,89,255,125,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,0,89, 247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0,175, 125,0,0,0,0,0,0,0,0,0,0,0,59,241,89,12,235,125,0,0,172,89,0,0,0,0,0,0,0, 0,0,12,235,166,0,0,7,202,89,0,0,0,0,0,0,89,255,201,0,0,12,235,125,0,0,0, 0,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,138,247,34,0,12,146,0,0,0,0,0, 144,21,0,0,12,146,0,0,0,0,0,144,21,0,89,225,21,71,157,22,191,225,21,175, 201,0,7,206,125,59,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,59,196,199,47,206,184,89,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0, 0,0,0,59,245,125,0,0,59,245,125,0,0,0,0,0,127,12,235,166,0,0,0,0,0,0,12, 146,0,0,0,0,0,144,21,0,0,0,0,0,0,0,175,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,12,235,255,255,255,255,127,34,235,255,255,255,255,225,21,0, 0,0,0,0,0,0,0,89,247,34,7,206,166,0,89,201,0,0,0,0,0,0,0,0,0,0,89,247,34, 0,0,0,0,0,0,0,0,59,115,12,235,166,0,0,0,12,235,125,0,0,0,0,0,0,12,146,0, 0,0,0,0,144,21,0,0,0,0,0,59,245,125,0,0,12,146,0,0,0,0,0,144,21,0,0,12, 146,0,0,0,0,0,144,21,0,7,202,89,117,104,0,29,202,89,59,215,21,59,215,21, 138,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,175,125,0,59,192,89,223,125,172,89,0,138,255,255,255,201,12,182, 0,0,0,0,0,175,255,255,125,0,89,255,255,247,34,0,0,12,146,0,0,0,0,0,144, 21,0,138,255,255,255,255,247,34,138,247,34,7,206,201,0,0,0,0,0,0,127,89, 251,89,0,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,7,206,166,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0,175,125,0,0,0, 0,0,0,0,0,0,0,0,89,247,34,7,206,166,7,202,89,0,0,0,0,0,0,0,0,0,0,89,255, 125,0,0,0,0,0,0,0,89,255,125,89,247,34,0,0,0,12,235,125,0,0,0,0,0,0,12, 146,0,0,0,0,0,144,21,0,0,0,0,7,206,201,0,0,0,12,146,0,0,0,0,0,144,21,0, 0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245, 255,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175, 125,0,59,192,12,228,34,172,89,89,247,34,0,12,206,29,206,201,0,0,7,206,166, 0,7,206,255,225,21,0,89,247,34,0,12,146,0,0,0,0,0,144,21,0,0,0,0,7,206, 166,0,12,235,166,89,247,34,0,0,0,0,0,0,127,245,255,255,255,255,255,201, 0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,59,245,255,255,255,127,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0,175,125,0,0,0,0,0,0,0, 0,0,0,0,59,241,89,12,235,125,89,201,12,235,255,251,89,0,89,255,255,225, 21,0,175,255,255,225,21,0,0,0,89,251,89,0,138,225,21,0,0,0,12,235,255,255, 255,255,225,21,0,12,146,0,0,0,0,0,144,21,0,0,0,0,138,247,34,0,0,0,12,146, 0,0,0,0,0,144,21,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,12,235,255,255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,59,192,0,0,0,172,89,138,225,21,0,0,0, 0,7,206,225,21,138,225,21,0,0,89,251,89,0,0,12,235,125,0,12,146,0,0,0,0, 0,144,21,0,0,0,0,138,225,21,0,0,89,255,255,125,0,0,0,0,0,0,0,127,138,225, 21,0,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,59,241,89,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,0,12,235,255,255,255,255, 225,21,0,0,0,0,0,0,0,0,0,138,255,255,201,12,228,34,175,166,0,138,201,7, 206,125,7,206,166,0,0,0,89,255,255,247,34,59,241,89,0,0,138,225,21,0,0, 0,12,235,125,0,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,0,59,245,125,0,0,0, 0,12,146,0,0,0,0,0,144,21,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,59,245,255,255,255,207,235,255,255,255,255,255,255, 207,235,255,255,255,255,255,255,255,255,255,255,255,225,21,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,59,245,255,247,34,0,0,0,0,175,166,175,201,0,0,0, 59,245,255,255,255,255,255,125,0,12,146,0,0,0,0,0,144,21,0,0,0,89,251,89, 0,0,0,7,206,225,21,0,0,0,0,0,0,0,127,245,255,255,255,255,255,125,0,0,12, 146,0,0,0,0,0,144,21,0,0,0,0,0,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0,175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,138,166,7,206,125,0,89,247,94,241,89,0,138,201,0,0,0,0,0,59,245,166, 0,89,251,89,0,89,247,34,0,0,0,12,235,125,0,0,0,0,0,0,12,146,0,0,0,0,0,144, 21,0,0,7,206,201,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,12,146,0,0,0,0,0, 144,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,255,255,166,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,138,255,255,201,0,7,206,225,21,175,201,0,0,0,59,241,89,0,0,0,0, 0,0,12,146,0,0,0,0,0,144,21,0,0,12,235,166,0,0,0,0,0,175,225,21,0,0,0,0, 0,0,0,127,89,255,125,0,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,89, 247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,125,0,0,0,0,0, 175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,228,34,7,206,125,0,89,247,94,241, 89,0,138,201,0,0,0,0,0,12,235,166,0,0,89,255,125,12,235,166,0,0,0,12,235, 125,0,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,138,247,34,0,0,0,0,0,12,146, 0,0,0,0,0,144,21,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,59,245,255,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,247,42,206,201,0,0,89, 225,21,0,0,89,255,125,0,0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,0,175,225,21, 0,0,0,0,0,175,225,21,0,0,0,0,0,0,0,127,0,175,251,89,0,0,0,0,0,12,146,0, 0,0,0,0,144,21,0,59,245,166,0,0,138,225,21,0,0,0,59,245,166,138,251,89, 7,206,201,0,12,235,125,0,59,241,89,0,0,0,175,125,0,0,0,0,0,175,125,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,138,166,0,0,175,166,0,138,201,7,206,125,7,206, 166,138,166,0,0,0,138,251,89,0,0,0,59,115,0,89,255,201,0,0,12,235,125,0, 0,0,0,0,0,12,146,0,0,0,0,0,144,21,0,89,251,89,0,0,0,0,0,0,12,146,0,0,0, 0,0,144,21,0,0,12,146,0,0,0,0,0,144,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,138,125,0,0,138,225,34,182,0,0,0,7,206,166,0, 7,206,255,247,34,0,0,175,125,0,12,146,0,0,0,0,0,144,21,0,89,251,89,0,0, 0,0,0,0,175,225,21,0,0,0,0,0,0,0,127,0,0,138,255,255,255,255,125,0,12,235, 255,255,255,255,255,225,21,0,138,247,34,0,7,206,166,0,0,0,0,89,247,34,175, 201,0,7,206,201,0,12,235,125,0,59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,59,215,21,0,0,12,235,255,251,89,0,89,255,255,225, 21,12,235,255,255,255,247,34,0,0,0,0,0,0,0,0,12,235,255,255,255,255,255, 255,255,255,251,89,0,12,235,255,255,255,255,255,225,21,0,138,255,255,255, 255,255,255,166,0,12,235,255,255,255,255,255,225,21,0,0,12,235,255,255, 255,255,255,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,89,255,255,255,247,34,0,0,0,0,0,0,0,175,255,255,125,0,138,255,255, 255,125,0,0,12,235,255,255,255,255,255,225,21,0,175,255,255,255,255,247, 0,0,0,175,225,21,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,175,166,0,255,255,201,0,0,0,0,0,175,166,12,232,89,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, 228,34,0,0,0,0,0,0,0,0,12,232,89,59,215,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127,0,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,0,127,127,127,0,127,127,0,127,127,127,127,127,0,127,127,127,127, 127,0,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127, 0,127,127,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,245,255,255,255,255,255,255,225,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,225,21,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,247, 34,0,0,0,0,59,192,0,0,0,0,0,7,206,255,255,225,21,0,0,0,0,0,0,0,0,138,247, 34,0,0,89,251,89,0,7,206,125,0,0,7,206,255,255,255,166,0,89,251,89,138, 247,34,0,0,0,0,7,206,255,255,255,247,34,0,0,0,0,175,255,255,251,89,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,255,255,247, 34,0,0,0,0,0,0,0,0,0,0,0,0,89,255,255,247,34,0,0,0,0,0,0,0,0,0,0,0,0,12, 235,255,247,34,0,0,7,206,255,251,89,0,0,7,206,125,0,0,0,0,0,0,0,0,0,0,0, 0,89,255,255,255,255,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,0, 59,245,255,247,34,0,0,0,0,0,0,0,0,0,0,0,89,201,0,0,0,0,175,166,0,0,0,0, 0,0,89,201,0,0,0,0,175,166,0,0,0,0,0,59,245,255,201,0,0,0,59,241,89,0,0, 0,0,0,59,245,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,247,34, 0,0,0,0,59,192,0,0,0,0,0,175,201,0,0,144,21,0,0,0,0,0,0,0,0,7,206,166,0, 7,206,166,0,0,7,206,125,0,7,206,201,0,0,89,166,0,0,0,0,0,0,0,0,0,0,89,255, 125,0,0,0,59,245,166,0,0,0,0,0,0,12,206,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,89,255,125,0,0,0,59,245,166,0,0,0,0,0,0,0,0,0,0,59, 241,89,0,138,201,0,0,0,0,0,138,166,0,0,0,0,0,168,34,7,206,166,0,0,172,89, 0,175,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255,255,255,166,89,225,21, 0,0,0,0,0,0,0,0,0,0,0,0,0,89,255,251,89,0,0,12,235,125,0,138,225,21,0,0, 0,0,0,0,0,0,7,206,255,201,0,0,0,89,225,21,0,0,0,0,7,206,255,201,0,0,0,89, 225,21,0,0,0,0,12,206,21,12,235,125,0,0,175,166,0,0,0,0,0,0,59,245,125, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,175,255,255,255, 166,0,0,12,235,125,0,0,0,0,89,225,21,0,0,12,232,89,0,89,247,34,89,247,34, 0,0,7,206,125,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,89,225,21,0,0,0,0, 0,7,206,125,0,0,7,206,255,255,247,34,0,0,0,85,89,0,85,89,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,89,225,21,0,0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,0,89,201, 0,0,12,228,34,0,0,0,0,138,166,0,0,0,0,0,0,0,7,206,125,0,0,7,206,255,166, 0,0,0,0,0,0,0,0,0,12,235,125,0,0,89,247,34,175,255,255,255,166,89,225,21, 0,89,255,125,0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,89,225,21,0,12,232,89,59, 115,0,59,115,0,0,0,0,0,89,201,0,0,7,206,125,0,0,0,0,0,0,0,89,201,0,0,7, 206,125,0,0,0,0,0,0,0,0,12,232,89,0,59,238,34,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,225,21,0,0,138,247,94,192,12,182, 0,0,12,235,125,0,0,0,0,0,175,255,255,255,255,166,0,0,7,206,171,206,166, 0,0,0,7,206,125,0,7,206,251,89,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,59,245, 255,255,201,0,12,228,34,12,235,166,0,12,228,34,0,0,138,251,89,138,247,34, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,202,89,0,138,255,255,255,125,0,12,228,34, 0,0,0,0,0,0,0,0,59,241,89,0,138,201,0,0,0,0,0,138,166,0,0,0,0,0,0,0,175, 201,0,0,0,0,0,0,175,201,0,0,0,0,0,0,0,0,12,235,125,0,0,89,247,34,175,255, 255,255,166,89,225,21,0,89,255,125,0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,138, 225,21,0,12,235,125,12,235,166,59,245,166,0,0,0,0,89,201,0,0,89,225,21, 0,0,0,0,0,0,0,89,201,0,0,89,225,21,0,0,0,0,0,0,12,235,255,125,0,0,175,125, 0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89, 225,21,0,12,235,125,59,192,0,0,0,0,12,235,125,0,0,0,0,0,59,215,21,59,238, 34,0,0,0,89,255,247,34,0,0,0,7,206,125,0,0,7,206,255,255,247,34,0,0,0,0, 0,0,0,0,59,192,0,12,235,166,0,7,176,21,0,175,125,59,238,34,0,12,228,34, 0,138,247,34,138,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,192,0,0,138, 201,0,89,247,34,0,175,125,0,0,0,0,0,0,0,0,0,89,255,255,225,21,0,7,206,255, 255,255,255,255,255,247,34,0,12,235,125,0,0,0,7,176,21,0,175,201,0,0,0, 0,0,0,0,0,12,235,125,0,0,89,247,34,89,255,255,255,166,89,225,21,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,7,202,89,0,0,89,225,21,0,12,232,89,0,12,235,166,12, 235,166,0,0,0,89,201,0,7,206,125,0,12,235,166,0,0,0,0,89,201,0,7,206,125, 89,255,255,255,125,0,0,0,0,7,206,125,89,225,21,0,138,225,21,0,0,0,138,255, 125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,247,34,0,59,241,89,59, 192,0,0,0,12,235,255,255,255,225,21,0,0,138,166,0,7,202,89,0,0,0,7,206, 166,0,0,0,0,0,0,0,0,7,206,125,0,12,235,201,0,0,0,0,0,0,0,0,89,166,0,89, 247,34,0,0,0,0,0,89,166,12,232,89,0,138,247,34,89,247,34,59,238,34,0,0, 12,235,255,255,255,255,255,255,247,34,89,255,255,255,166,89,166,0,0,138, 201,0,138,225,21,0,89,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166, 0,0,0,0,7,206,255,255,255,247,34,0,59,245,255,247,34,0,0,0,0,0,0,0,0,12, 235,125,0,0,89,247,34,0,89,255,255,166,89,225,21,0,0,0,0,0,0,0,0,0,0,0, 0,0,89,255,255,255,166,0,12,235,125,0,138,225,21,0,0,12,235,125,12,235, 125,0,0,89,201,0,89,201,0,7,206,223,166,0,0,0,0,89,201,0,89,201,0,89,125, 0,138,225,21,12,182,0,7,206,133,206,125,0,89,232,215,21,0,7,206,247,34, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,247,34,0,59,241,89,59, 192,0,0,0,0,12,235,125,0,0,0,0,0,59,215,21,59,238,34,0,59,245,255,255,255, 255,225,21,0,0,0,0,0,59,241,89,0,0,138,225,21,0,0,0,0,0,0,0,89,166,0,89, 247,34,0,0,0,0,0,89,166,0,138,255,255,176,228,34,0,138,247,34,138,247,34, 0,0,0,0,0,0,0,0,59,238,34,0,0,0,0,0,89,166,0,0,138,255,255,225,21,0,0,89, 166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,89,247,34,0,0,0,138,166,89,225, 21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,255,247,34,0,0,12,235, 166,12,235,166,0,0,0,0,0,12,232,89,0,175,166,138,166,0,0,0,0,0,0,12,232, 89,0,0,0,0,138,201,0,0,89,255,255,201,89,225,21,89,225,81,215,21,0,138, 247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,247,34,0,12,235, 125,59,192,0,0,0,0,59,241,89,0,0,0,0,0,175,255,255,255,255,166,0,0,0,7, 206,166,0,0,0,0,7,206,125,0,12,235,201,0,7,206,166,0,0,0,0,0,0,0,0,59,192, 0,12,235,166,0,7,176,21,0,175,125,0,0,0,0,0,0,0,0,0,138,251,89,138,247, 34,0,0,0,0,0,0,0,59,238,34,0,0,0,0,0,59,192,0,0,138,201,59,245,166,0,0, 175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,166,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,89,247,34,0,0,0,138,166, 89,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,166, 59,245,166,0,0,0,0,0,0,138,201,0,138,201,0,138,166,0,0,0,0,0,0,138,201, 0,0,0,0,89,247,34,0,0,0,0,0,7,206,125,59,238,34,59,215,21,0,175,225,21, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,89,247,34,0,0,175,225,81, 192,12,182,0,7,206,125,0,0,0,0,0,89,225,21,0,0,12,232,89,0,0,7,206,166, 0,0,0,0,7,206,125,0,0,59,245,255,255,166,0,0,0,0,0,0,0,0,0,7,202,89,0,59, 245,255,255,166,0,12,228,34,0,0,0,0,0,0,0,0,0,0,85,89,0,85,89,0,0,0,0,0, 0,0,59,238,34,0,0,0,0,0,7,202,89,0,138,201,0,59,245,225,34,228,34,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,255,255,255,255,255,247,34,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,201,0,0,175,247,34,0,0,0,138,166, 89,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,115,0, 59,115,0,0,0,0,0,0,12,232,89,0,175,255,255,255,255,201,0,0,0,0,12,232,89, 0,0,0,138,201,0,0,0,0,0,0,0,89,201,0,89,255,255,255,255,247,34,138,251, 89,0,7,176,21,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,138,247,34,0,0,0, 175,255,255,255,166,0,89,255,255,255,255,255,247,34,0,0,0,0,0,0,0,0,0,0, 7,206,166,0,0,0,0,7,206,125,0,0,0,0,0,138,255,166,0,0,0,0,0,0,0,0,0,89, 225,21,0,0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,59,238,34,0,0,0,0,0,0,89,225,21,0,0,0,0,0,7,206,125,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,12,235,191,255,255,166,238,34,0,0,0,138,166,89,225,21,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,201,0,0, 0,0,0,138,166,0,0,0,0,0,175,201,0,0,0,89,255,255,255,255,125,0,0,0,12,232, 89,0,0,0,0,59,215,21,0,0,138,255,255,255,225,21,0,0,0,0,0,0,0,0,0,0,0,0, 0,127,0,0,0,0,0,0,0,0,0,0,0,0,59,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,7,206,125,0,0,0,0,0,0,175,201,0,0,0,0,0,0,0,0,0,0, 89,255,125,0,0,0,59,245,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,89,255,125,0,0,0,59,245,166,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,12,235,125,0,0,0,0,0,0,0,0,138,166,89,225,21,0,0,0,0,0,0,0,0,0,175, 125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,59,192,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,125,0,7,199,34, 0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,7,206,255,255,255,247,34,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,255, 255,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0,0,138,166, 89,225,21,0,0,0,0,0,0,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,7,206,125,0,7,206,255,255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,12,235,255,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127, 127,127,0,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,0,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,0,127, 127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,0,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,138,225, 21,0,0,0,0,0,12,235,125,0,0,0,0,19,172,255,190,11,0,0,0,0,138,255,201,7, 202,89,0,0,0,0,0,0,0,0,0,0,7,206,255,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,59,138,225,21,0,0,0,0,0,0,59,245,201,0,0,0,19,172, 255,190,11,0,0,0,0,0,0,0,0,0,7,206,225,21,0,0,0,59,245,201,19,172,255,190, 11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,251,89,89,201,0,0,0,0,0,175, 201,0,0,0,0,0,0,0,0,7,206,225,21,0,0,0,0,0,19,172,255,190,11,0,0,0,0,0, 175,255,166,12,228,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,89,255,125,0,0,0,0,0,0,0,12,175,247,34,0,0,0,19,172,255, 190,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,247,34,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,127,0,0,0,7,206,125,0,0,0,0,0,138,201,0,0,0,0,0,136,190, 45,196,145,0,0,0,59,215,21,175,255,166,0,0,0,175,225,29,206,166,0,0,7,202, 89,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,209,125, 0,0,0,0,0,0,138,225,21,0,0,0,136,190,45,196,145,0,0,0,175,225,29,206,166, 0,0,12,235,125,0,0,12,138,225,21,136,190,45,196,145,159,251,89,138,247, 34,0,0,0,0,0,0,0,0,0,0,0,175,125,59,245,247,34,0,0,0,0,0,12,232,89,0,0, 0,0,0,0,0,175,166,0,0,0,0,0,0,12,136,190,45,196,145,0,0,0,0,138,166,12, 235,255,125,0,0,0,0,7,206,166,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,12,232,89,0,0,0,0,0,0,138,201,0,0,0,0,0,136,190,45, 196,145,34,0,0,0,89,251,89,138,247,34,0,0,0,0,0,138,201,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,202,89,7,202,89,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,255, 255,125,0,0,0,0,127,0,0,7,206,251,89,0,0,0,0,7,206,251,89,0,0,0,0,7,206, 251,89,0,0,0,0,0,7,206,251,89,0,0,0,0,7,206,251,89,0,0,0,0,12,235,255,125, 0,0,0,0,0,89,255,255,255,255,255,255,255,255,125,0,0,0,59,245,255,255,255, 201,12,235,255,255,255,255,255,125,12,235,255,255,255,255,255,125,12,235, 255,255,255,255,255,125,12,235,255,255,255,255,255,125,89,255,255,255,201, 89,255,255,255,201,89,255,255,255,201,89,255,255,255,201,0,175,255,255, 255,255,201,0,0,0,12,235,251,89,0,0,12,235,125,0,0,0,138,255,255,166,0, 0,0,0,0,0,138,255,255,166,0,0,0,0,0,0,138,255,255,166,0,0,0,0,0,0,138,255, 255,166,0,0,0,0,0,0,138,255,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138, 255,255,201,89,251,89,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59,245, 125,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59,245,125,7,206,225,21, 0,0,0,138,247,0,235,166,0,0,0,0,0,0,138,225,21,7,206,166,0,0,0,127,0,0, 59,245,255,166,0,0,0,0,59,245,255,166,0,0,0,0,59,245,255,166,0,0,0,0,0, 59,245,255,166,0,0,0,0,59,245,255,166,0,0,0,0,59,245,255,166,0,0,0,0,0, 175,201,7,206,166,0,0,0,0,0,0,0,138,255,125,0,0,7,202,102,235,166,0,0,0, 0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,0,12, 235,125,0,0,12,235,125,0,0,12,235,125,0,0,12,235,125,0,0,175,201,0,0,7, 206,251,89,0,12,235,255,201,0,0,12,235,125,0,59,245,166,0,0,138,251,89, 0,0,59,245,166,0,0,138,251,89,0,0,59,245,166,0,0,138,251,89,0,0,59,245, 166,0,0,138,251,89,0,0,59,245,166,0,0,138,251,89,0,0,0,0,0,0,0,0,0,0,0, 0,59,245,166,0,0,89,255,166,0,12,235,125,0,0,0,59,245,125,12,235,125,0, 0,0,59,245,125,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59,245,125, 0,59,245,125,0,0,59,245,125,12,235,166,0,0,0,0,0,12,235,125,0,0,175,201, 0,0,0,127,0,0,138,225,151,225,21,0,0,0,138,225,151,225,21,0,0,0,138,225, 151,225,21,0,0,0,0,138,225,151,225,21,0,0,0,138,225,151,225,21,0,0,0,138, 225,151,225,21,0,0,0,59,241,89,7,206,166,0,0,0,0,0,0,12,235,166,0,0,0,0, 0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235, 166,0,0,0,0,0,0,12,235,125,0,0,12,235,125,0,0,12,235,125,0,0,12,235,125, 0,0,175,201,0,0,0,0,175,225,21,12,235,166,245,125,0,12,235,125,12,235,125, 0,0,0,0,138,247,34,12,235,125,0,0,0,0,138,247,34,12,235,125,0,0,0,0,138, 247,34,12,235,125,0,0,0,0,138,247,34,12,235,125,0,0,0,0,138,247,34,0,138, 225,21,0,0,0,175,201,0,12,235,125,0,0,7,202,159,247,34,12,235,125,0,0,0, 59,245,125,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59,245,125,12,235, 125,0,0,0,59,245,125,0,0,138,247,34,7,206,201,0,12,235,255,255,255,251, 89,0,12,235,125,0,12,235,125,0,0,0,127,0,7,206,166,59,241,89,0,0,7,206, 166,59,241,89,0,0,7,206,166,59,241,89,0,0,0,7,206,166,59,241,89,0,0,7,206, 166,59,241,89,0,0,7,206,166,59,241,89,0,0,0,138,225,21,7,206,166,0,0,0, 0,0,0,89,247,34,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12, 235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,0,12,235,125,0,0,12,235,125,0,0, 12,235,125,0,0,12,235,125,0,0,175,201,0,0,0,0,59,241,89,12,235,125,138, 225,21,12,235,125,89,247,34,0,0,0,0,59,245,125,89,247,34,0,0,0,0,59,245, 125,89,247,34,0,0,0,0,59,245,125,89,247,34,0,0,0,0,59,245,125,89,247,34, 0,0,0,0,59,245,125,0,0,175,225,21,0,175,225,21,0,89,247,34,0,0,138,166, 12,235,125,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59,245,125,12,235, 125,0,0,0,59,245,125,12,235,125,0,0,0,59,245,125,0,0,12,235,166,89,247, 34,0,12,235,166,0,0,138,251,89,12,235,133,206,255,125,0,0,0,0,127,0,59, 241,89,7,206,166,0,0,59,241,89,7,206,166,0,0,59,241,89,7,206,166,0,0,0, 59,241,89,7,206,166,0,0,59,241,89,7,206,166,0,0,59,241,89,7,206,166,0,0, 12,235,125,0,7,206,255,255,255,255,247,34,0,138,225,21,0,0,0,0,0,12,235, 255,255,255,255,247,34,12,235,255,255,255,255,247,34,12,235,255,255,255, 255,247,34,12,235,255,255,255,255,247,34,0,12,235,125,0,0,12,235,125,0, 0,12,235,125,0,0,12,235,125,0,206,255,255,255,247,34,0,12,235,125,12,235, 125,12,235,125,12,235,125,138,225,21,0,0,0,0,12,235,166,138,225,21,0,0, 0,0,12,235,166,138,225,21,0,0,0,0,12,235,166,138,225,21,0,0,0,0,12,235, 166,138,225,21,0,0,0,0,12,235,166,0,0,0,175,225,187,225,21,0,0,138,225, 21,0,59,215,21,7,206,166,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59, 245,125,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59,245,125,0,0,0,89, 255,255,125,0,0,12,235,166,0,0,12,235,166,12,235,125,0,7,206,201,0,0,0, 127,0,138,225,21,0,138,225,21,0,138,225,21,0,138,225,21,0,138,225,21,0, 138,225,21,0,0,138,225,21,0,138,225,21,0,138,225,21,0,138,225,21,0,138, 225,21,0,138,225,21,0,89,255,255,255,255,255,166,0,0,0,0,0,0,138,225,21, 0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0, 0,12,235,166,0,0,0,0,0,0,12,235,125,0,0,12,235,125,0,0,12,235,125,0,0,12, 235,125,0,0,175,201,0,0,0,0,12,235,125,12,235,125,0,138,225,34,235,125, 138,225,21,0,0,0,0,12,235,166,138,225,21,0,0,0,0,12,235,166,138,225,21, 0,0,0,0,12,235,166,138,225,21,0,0,0,0,12,235,166,138,225,21,0,0,0,0,12, 235,166,0,0,0,0,175,225,21,0,0,0,138,225,21,7,202,89,0,7,206,166,12,235, 125,0,0,0,59,245,125,12,235,125,0,0,0,59,245,125,12,235,125,0,0,0,59,245, 125,12,235,125,0,0,0,59,245,125,0,0,0,7,206,225,21,0,0,12,235,166,0,0,12, 235,166,12,235,125,0,0,59,241,89,0,0,127,7,206,255,255,255,255,251,89,7, 206,255,255,255,255,251,89,7,206,255,255,255,255,251,89,0,7,206,255,255, 255,255,251,89,7,206,255,255,255,255,251,89,7,206,255,255,255,255,251,89, 7,206,166,0,0,7,206,166,0,0,0,0,0,0,89,247,34,0,0,0,0,0,12,235,166,0,0, 0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,0, 12,235,125,0,0,12,235,125,0,0,12,235,125,0,0,12,235,125,0,0,175,201,0,0, 0,0,59,241,89,12,235,125,0,12,235,138,235,125,89,247,34,0,0,0,0,59,245, 125,89,247,34,0,0,0,0,59,245,125,89,247,34,0,0,0,0,59,245,125,89,247,34, 0,0,0,0,59,245,125,89,247,34,0,0,0,0,59,245,125,0,0,0,175,225,187,225,21, 0,0,138,247,34,175,125,0,0,12,235,125,12,235,125,0,0,0,59,241,89,12,235, 125,0,0,0,59,241,89,12,235,125,0,0,0,59,241,89,12,235,125,0,0,0,59,241, 89,0,0,0,0,175,225,21,0,0,12,235,166,0,0,175,247,34,12,235,125,0,0,12,235, 125,0,0,127,59,241,89,0,0,7,206,166,59,241,89,0,0,7,206,166,59,241,89,0, 0,7,206,166,0,59,241,89,0,0,7,206,166,59,241,89,0,0,7,206,166,59,241,89, 0,0,7,206,166,59,241,89,0,0,7,206,166,0,0,0,0,0,0,59,245,166,0,0,0,0,0, 12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235,166, 0,0,0,0,0,0,12,235,125,0,0,12,235,125,0,0,12,235,125,0,0,12,235,125,0,0, 175,201,0,0,0,0,175,225,21,12,235,125,0,0,138,232,245,125,12,235,125,0, 0,0,0,138,247,34,12,235,125,0,0,0,0,138,247,34,12,235,125,0,0,0,0,138,247, 34,12,235,125,0,0,0,0,138,247,34,12,235,125,0,0,0,0,138,247,34,0,0,175, 225,21,0,175,225,21,0,59,245,191,201,0,0,0,89,225,21,12,235,166,0,0,0,89, 251,89,12,235,166,0,0,0,89,251,89,12,235,166,0,0,0,89,251,89,12,235,166, 0,0,0,89,251,89,0,0,0,0,175,225,21,0,0,12,235,255,255,255,247,34,0,12,235, 125,0,0,59,241,89,0,0,127,138,225,21,0,0,0,138,247,163,225,21,0,0,0,138, 247,163,225,21,0,0,0,138,247,34,138,225,21,0,0,0,138,247,163,225,21,0,0, 0,138,247,163,225,21,0,0,0,138,247,198,225,21,0,0,7,206,166,0,0,0,0,0,0, 0,138,255,125,0,0,7,202,102,235,166,0,0,0,0,0,12,235,166,0,0,0,0,0,12,235, 166,0,0,0,0,0,12,235,166,0,0,0,0,0,0,12,235,125,0,0,12,235,125,0,0,12,235, 125,0,0,12,235,125,0,0,175,201,0,0,7,206,251,89,0,12,235,125,0,0,12,235, 255,125,0,89,255,125,0,0,89,251,89,0,0,89,255,125,0,0,89,251,89,0,0,89, 255,125,0,0,89,251,89,0,0,89,255,125,0,0,89,251,89,0,0,89,255,125,0,0,89, 251,89,0,0,138,225,21,0,0,0,175,201,0,0,138,251,89,0,0,89,251,89,0,0,138, 247,34,0,7,206,225,21,0,138,247,34,0,7,206,225,21,0,138,247,34,0,7,206, 225,21,0,138,247,34,0,7,206,225,21,0,0,0,0,175,225,21,0,0,12,235,166,0, 0,0,0,0,12,235,125,0,0,175,225,21,0,0,127,206,166,0,0,0,0,59,245,255,166, 0,0,0,0,59,245,255,166,0,0,0,0,59,245,133,206,166,0,0,0,0,59,245,255,166, 0,0,0,0,59,245,255,166,0,0,0,0,59,245,255,125,0,0,0,7,206,255,255,255,255, 255,125,0,0,0,59,245,255,255,255,201,12,235,255,255,255,255,255,125,12, 235,255,255,255,255,255,125,12,235,255,255,255,255,255,125,12,235,255,255, 255,255,255,125,89,255,255,255,201,89,255,255,255,201,89,255,255,255,201, 89,255,255,255,201,0,175,255,255,255,255,225,21,0,0,12,235,125,0,0,0,138, 255,125,0,0,0,175,255,255,201,0,0,0,0,0,0,175,255,255,201,0,0,0,0,0,0,175, 255,255,201,0,0,0,0,0,0,175,255,255,201,0,0,0,0,0,0,175,255,255,201,0,0, 0,0,0,0,0,0,0,0,0,0,0,7,202,97,206,255,255,201,0,0,0,0,0,138,255,255,255, 201,0,0,0,0,138,255,255,255,201,0,0,0,0,138,255,255,255,201,0,0,0,0,138, 255,255,255,201,0,0,0,0,0,0,175,225,21,0,0,12,235,166,0,0,0,0,0,12,235, 133,206,255,225,21,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,138,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,138,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,175,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,225,21, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,127,127,127,127,127,0, 127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,0,127,127,127,127,0,127,127,127,127,0,127,127,127, 127,0,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,127,0,127,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,7,206,225,21, 0,0,0,0,0,12,235,225,21,0,0,89,255,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,7,206,255,247,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,247, 34,0,0,0,0,0,0,0,138,251,89,0,0,59,245,247,34,0,0,0,0,0,0,0,0,0,175,247, 34,0,0,175,0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,225,21, 0,0,0,0,0,0,0,138,255,125,0,0,0,12,235,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,251,89,0,0,0,0,0,0, 7,206,225,21,0,0,0,7,206,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,59,245,166,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,59,241,89,0,0,0,0, 0,89,247,34,0,0,7,206,138,235,125,0,0,89,255,225,21,175,125,0,0,0,0,0,0, 0,0,0,138,201,0,138,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12, 235,125,0,0,0,0,0,0,12,235,125,0,0,0,175,171,206,166,0,0,0,0,0,0,0,0,0, 7,206,166,0,59,245,255,166,238,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,125,59, 215,21,0,0,59,241,89,0,0,0,0,0,0,7,206,166,0,0,0,0,138,201,175,201,0,0, 0,12,235,251,89,89,201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,7,206,166,0,0,0,0,0,0,89,247,34,0,0,0,0,89,225,151,201,0,0,0,0, 0,0,0,0,0,0,0,0,0,175,201,0,12,235,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,127,0,0,0,138,201,0,0,0,0,7,206,125,0,0,0,138,201,0,89,225,21, 12,228,34,138,255,201,0,0,0,138,247,34,175,225,21,0,138,201,0,138,201,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,225,21,0,0,0,0,0,89,225, 21,0,0,89,247,34,59,241,89,0,59,241,89,89,247,34,0,0,89,225,21,175,127, 215,21,206,247,42,206,0,138,255,247,42,206,125,0,0,138,166,12,235,251,89, 0,0,0,0,138,201,0,0,0,0,0,0,89,225,21,0,0,0,59,241,89,12,235,125,0,0,175, 125,59,245,247,34,0,0,12,235,125,89,251,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,59,238,34,0,0,0,0,0,175,166,0,0,0,0,12,232,89,7,206,125,0, 0,12,235,166,59,245,125,0,0,0,59,238,34,0,12,235,125,0,0,0,0,0,0,89,247, 34,138,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,255,247,34,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,251,89,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,199,34,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,235,125,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,12,235,255,255,255,166,0,12,235,255, 255,255,166,0,12,235,255,255,255,166,0,12,235,255,255,255,166,0,0,12,235, 255,255,255,166,0,12,235,255,255,255,166,0,12,235,255,255,255,166,0,175, 255,255,125,0,0,12,235,255,255,125,0,0,12,235,255,255,225,21,0,0,12,235, 255,255,225,21,0,12,235,255,255,225,21,0,12,235,255,255,225,21,0,12,235, 125,12,235,125,12,235,125,12,235,125,0,12,235,125,89,251,89,0,12,235,138, 235,255,247,34,0,0,12,235,255,255,201,0,0,0,12,235,255,255,201,0,0,0,12, 235,255,255,201,0,0,0,12,235,255,255,201,0,0,0,12,235,255,255,201,0,0,0, 0,0,0,175,247,34,0,0,0,12,235,255,255,255,166,0,59,241,89,0,0,89,247,34, 59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,42, 206,201,0,0,0,138,232,245,166,245,255,251,89,7,206,201,0,0,0,138,225,21, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,127,12,206,21,0,59,245,125,12,206,21,0,59,245,125,12,206, 21,0,59,245,125,12,206,21,0,59,245,125,0,12,206,21,0,59,245,125,12,206, 21,0,59,245,125,12,206,21,0,12,235,255,125,0,7,206,166,12,235,166,0,0,172, 102,0,235,125,0,0,175,201,0,12,235,125,0,0,175,201,12,235,125,0,0,175,201, 12,235,125,0,0,175,201,0,12,235,125,12,235,125,12,235,125,12,235,125,0, 0,0,0,0,175,201,0,12,235,247,34,0,175,201,0,12,235,166,0,7,206,201,0,12, 235,166,0,7,206,201,0,12,235,166,0,7,206,201,0,12,235,166,0,7,206,201,0, 12,235,166,0,7,206,201,0,0,0,0,0,175,247,34,0,0,12,235,166,0,12,235,201, 0,59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,34,59,241,89,0,0,89,247, 34,59,241,89,0,0,89,247,34,89,247,34,0,7,206,176,235,225,21,0,175,225,21, 89,247,34,0,7,206,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,7,206,166,0,0,0,0,7, 206,166,0,0,0,0,7,206,166,0,0,0,0,7,206,166,0,0,0,0,0,7,206,166,0,0,0,0, 7,206,166,0,0,0,0,0,175,201,0,0,0,89,225,138,225,21,0,0,0,0,89,225,21,0, 0,89,247,34,89,225,21,0,0,89,247,124,225,21,0,0,89,247,124,225,21,0,0,89, 247,34,12,235,125,12,235,125,12,235,125,12,235,125,0,89,255,255,255,255, 247,34,12,235,125,0,0,89,247,34,138,225,21,0,0,59,238,34,138,225,21,0,0, 59,238,34,138,225,21,0,0,59,238,34,138,225,21,0,0,59,238,34,138,225,21, 0,0,59,238,34,0,0,0,0,0,0,0,0,0,138,225,21,0,172,132,238,34,59,241,89,0, 0,89,247,34,59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,34,59,241,89,0, 0,89,247,34,12,235,125,0,59,238,47,235,125,0,0,59,241,89,12,235,125,0,59, 238,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,59,245,255,255,255,166,0,59,245,255,255, 255,166,0,59,245,255,255,255,166,0,59,245,255,255,255,166,0,0,59,245,255, 255,255,166,0,59,245,255,255,255,166,0,89,255,255,255,255,255,255,255,255, 255,247,175,201,0,0,0,0,0,175,255,255,255,255,255,247,34,175,255,255,255, 255,255,247,198,255,255,255,255,255,247,198,255,255,255,255,255,247,34, 12,235,125,12,235,125,12,235,125,12,235,125,89,251,89,0,0,59,241,89,12, 235,125,0,0,89,247,34,175,201,0,0,0,12,232,89,175,201,0,0,0,12,232,89,175, 201,0,0,0,12,232,89,175,201,0,0,0,12,232,89,175,201,0,0,0,12,232,89,7,206, 255,255,255,255,255,255,251,226,201,0,89,166,12,232,89,59,241,89,0,0,89, 247,34,59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,34,59,241,89,0,0,89, 247,34,0,175,201,0,138,201,12,235,125,0,0,12,235,125,0,175,201,0,138,201, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,127,89,255,166,0,7,206,166,89,255,166,0,7,206,166,89, 255,166,0,7,206,166,89,255,166,0,7,206,166,0,89,255,166,0,7,206,166,89, 255,166,0,7,206,166,138,255,125,0,0,175,201,0,0,0,0,0,175,201,0,0,0,0,0, 175,201,0,0,0,0,0,0,175,201,0,0,0,0,0,175,201,0,0,0,0,0,175,201,0,0,0,0, 0,0,12,235,125,12,235,125,12,235,125,12,235,125,175,201,0,0,0,59,241,89, 12,235,125,0,0,89,247,34,175,201,0,0,0,12,232,89,175,201,0,0,0,12,232,89, 175,201,0,0,0,12,232,89,175,201,0,0,0,12,232,89,175,201,0,0,0,12,232,89, 0,0,0,0,0,0,0,0,0,175,201,7,176,21,12,232,89,59,241,89,0,0,89,247,34,59, 241,89,0,0,89,247,34,59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,34,0, 89,247,47,235,125,12,235,125,0,0,12,235,125,0,89,247,47,235,125,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,127,175,201,0,0,7,206,166,175,201,0,0,7,206,166,175,201,0,0, 7,206,166,175,201,0,0,7,206,166,0,175,201,0,0,7,206,166,175,201,0,0,7,206, 166,175,201,0,0,0,138,225,21,0,0,0,0,138,225,21,0,0,0,0,138,247,34,0,0, 0,0,0,138,247,34,0,0,0,0,138,247,34,0,0,0,0,138,247,34,0,0,0,0,0,12,235, 125,12,235,125,12,235,125,12,235,125,175,201,0,0,0,89,247,34,12,235,125, 0,0,89,247,34,138,225,21,0,0,89,247,34,138,225,21,0,0,89,247,34,138,225, 21,0,0,89,247,34,138,225,21,0,0,89,247,34,138,225,21,0,0,89,247,34,0,0, 0,0,175,247,34,0,0,138,225,151,125,0,89,247,34,59,241,89,0,0,89,247,34, 59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,34,59,241,89,0,0,89,247,34, 0,12,235,191,247,34,12,235,125,0,0,59,241,89,0,12,235,191,247,34,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,127,138,225,21,0,138,255,166,138,225,21,0,138,255,166,138, 225,21,0,138,255,166,138,225,21,0,138,255,166,0,138,225,21,0,138,255,166, 138,225,21,0,138,255,166,89,247,34,0,89,255,255,166,0,0,12,206,12,235,166, 0,0,127,102,0,235,201,0,0,12,206,21,12,235,201,0,0,12,206,34,235,201,0, 0,12,206,34,235,201,0,0,12,206,21,12,235,125,12,235,125,12,235,125,12,235, 125,89,255,125,0,7,206,166,0,12,235,125,0,0,89,247,34,12,235,166,0,7,206, 201,0,12,235,166,0,7,206,201,0,12,235,166,0,7,206,201,0,12,235,166,0,7, 206,201,0,12,235,166,0,7,206,201,0,0,0,0,0,175,247,34,0,0,12,235,201,0, 7,206,201,0,7,206,166,0,59,245,247,34,7,206,166,0,59,245,247,34,7,206,166, 0,59,245,247,34,7,206,166,0,59,245,247,34,0,0,138,255,166,0,12,235,125, 0,7,206,201,0,0,0,138,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,7,206,255,255,171, 206,166,7,206,255,255,171,206,166,7,206,255,255,171,206,166,7,206,255,255, 171,206,166,0,7,206,255,255,171,206,166,7,206,255,255,171,206,166,0,89, 255,255,201,0,0,175,255,255,247,34,0,12,235,255,255,166,0,0,7,206,255,255, 247,34,0,0,7,206,255,255,247,34,0,7,206,255,255,247,34,0,7,206,255,255, 247,34,0,12,235,125,12,235,125,12,235,125,12,235,125,0,89,255,255,255,201, 0,0,12,235,125,0,0,89,247,34,0,12,235,255,255,201,0,0,0,12,235,255,255, 201,0,0,0,12,235,255,255,201,0,0,0,12,235,255,255,201,0,0,0,12,235,255, 255,201,0,0,0,0,0,0,0,0,0,0,0,7,206,255,255,255,201,0,0,0,59,245,255,225, 111,247,34,0,59,245,255,225,111,247,34,0,59,245,255,225,111,247,34,0,59, 245,255,225,111,247,34,0,0,59,241,89,0,12,235,255,255,255,225,21,0,0,0, 59,241,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,175,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,138,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,225,21,0,12,235,125,0,0,0,0,0,0,0, 138,225,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,7,202,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,206,166,0,0,12,235,125,0,0,0,0,0,0,7,206, 166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12,235,255,166,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,247,34,0,0,12,235,125,0,0,0,0,0,0,89,247, 34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,0,127,127,0,127,127,0,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127, 127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127, 127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,127, 0,127,127,127,127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127, 127,127,127,127,0,127,127,127,127,127,127,127,0,127,127,127,127,127,127, 127,0,127,127,127,127,127,127,0,127,127,127,127,127,127,0,127,127,127,127, 127,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0 }; void TwGenerateDefaultFonts() { g_DefaultSmallFont = TwGenerateFont(s_Font0, FONT0_BM_W, FONT0_BM_H); assert(g_DefaultSmallFont && g_DefaultSmallFont->m_NbCharRead==224); g_DefaultNormalFont = TwGenerateFont(s_Font1AA, FONT1AA_BM_W, FONT1AA_BM_H); assert(g_DefaultNormalFont && g_DefaultNormalFont->m_NbCharRead==224); g_DefaultLargeFont = TwGenerateFont(s_Font2AA, FONT2AA_BM_W, FONT2AA_BM_H); assert(g_DefaultLargeFont && g_DefaultLargeFont->m_NbCharRead==224); } // --------------------------------------------------------------------------- void TwDeleteDefaultFonts() { delete g_DefaultSmallFont; g_DefaultSmallFont = NULL; delete g_DefaultNormalFont; g_DefaultNormalFont = NULL; delete g_DefaultLargeFont; g_DefaultLargeFont = NULL; } // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwFonts.h0000644000000000000000000000345212635011627024330 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwFonts.h // @brief Bitmaps fonts // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_FONTS_INCLUDED #define ANT_TW_FONTS_INCLUDED //#include /* A source bitmap includes 224 characters starting from ascii char 32 (i.e. space) to ascii char 255: !"#$%&'()*+,-./0123456789:;<=>? @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ `abcdefghijklmnopqrstuvwxyz{|}~ First column of a source bitmap is a delimiter with color=zero at the end of each line of characters. Last row of a line of characters is a delimiter with color=zero at the last pixel of each character. */ struct CTexFont { unsigned char * m_TexBytes; int m_TexWidth; // power of 2 int m_TexHeight; // power of 2 float m_CharU0[256]; float m_CharV0[256]; float m_CharU1[256]; float m_CharV1[256]; int m_CharWidth[256]; int m_CharHeight; int m_NbCharRead; CTexFont(); ~CTexFont(); }; CTexFont *TwGenerateFont(const unsigned char *_Bitmap, int _BmWidth, int _BmHeight); extern CTexFont *g_DefaultSmallFont; extern CTexFont *g_DefaultNormalFont; extern CTexFont *g_DefaultLargeFont; void TwGenerateDefaultFonts(); void TwDeleteDefaultFonts(); #endif // !defined ANT_TW_FONTS_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwGraph.h0000644000000000000000000000472312635011627024302 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwGraph.h // @brief ITwGraph pure interface // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_GRAPH_INCLUDED #define ANT_TW_GRAPH_INCLUDED #include "TwColors.h" #include "TwFonts.h" // --------------------------------------------------------------------------- #ifdef DrawText // DirectX redefines 'DrawText' !! # undef DrawText #endif // DrawText class ITwGraph { public: virtual int Init() = 0; virtual int Shut() = 0; virtual void BeginDraw(int _WndWidth, int _WndHeight) = 0; virtual void EndDraw() = 0; virtual bool IsDrawing() = 0; virtual void Restore() = 0; virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased=false) = 0; virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color, bool _AntiAliased=false) = 0; virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11) = 0; virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color) = 0; enum Cull { CULL_NONE, CULL_CW, CULL_CCW }; virtual void DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode) = 0; virtual void * NewTextObj() = 0; virtual void DeleteTextObj(void *_TextObj) = 0; virtual void BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth) = 0; virtual void DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor) = 0; virtual void ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY) = 0; virtual void RestoreViewport() = 0; virtual void SetScissor(int _X0, int _Y0, int _Width, int _Height) = 0; virtual ~ITwGraph() {} // required by gcc }; // --------------------------------------------------------------------------- #endif // ANT_TW_GRAPH_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwMgr.cpp0000644000000000000000000072225212635011627024325 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwMgr.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include #include "TwMgr.h" #include "TwBar.h" #include "TwFonts.h" #include "TwOpenGL.h" //#include "TwOpenGLCore.h" #ifdef ANT_WINDOWS # include "TwDirect3D9.h" # include "TwDirect3D10.h" # include "TwDirect3D11.h" # include "resource.h" # ifdef _DEBUG # include # endif // _DEBUG #endif // ANT_WINDOWS #if !defined(ANT_WINDOWS) # define _snprintf snprintf #endif // defined(ANT_WINDOWS) using namespace std; CTwMgr *g_TwMgr = NULL; // current TwMgr bool g_BreakOnError = false; TwErrorHandler g_ErrorHandler = NULL; int g_TabLength = 4; CTwBar * const TW_GLOBAL_BAR = (CTwBar *)(-1); int g_InitWndWidth = -1; int g_InitWndHeight = -1; TwCopyCDStringToClient g_InitCopyCDStringToClient = NULL; TwCopyStdStringToClient g_InitCopyStdStringToClient = NULL; // multi-windows const int TW_MASTER_WINDOW_ID = 0; typedef map CTwWndMap; CTwWndMap g_Wnds; CTwMgr *g_TwMasterMgr = NULL; // error messages extern const char *g_ErrUnknownAttrib; extern const char *g_ErrNoValue; extern const char *g_ErrBadValue; const char *g_ErrInit = "Already initialized"; const char *g_ErrShut = "Already shutdown"; const char *g_ErrNotInit = "Not initialized"; const char *g_ErrUnknownAPI = "Unsupported graph API"; const char *g_ErrBadDevice = "Invalid graph device"; const char *g_ErrBadParam = "Invalid parameter"; const char *g_ErrExist = "Exists already"; const char *g_ErrNotFound = "Not found"; const char *g_ErrNthToDo = "Nothing to do"; const char *g_ErrBadSize = "Bad size"; const char *g_ErrIsDrawing = "Asynchronous drawing detected"; const char *g_ErrIsProcessing="Asynchronous processing detected"; const char *g_ErrOffset = "Offset larger than StructSize"; const char *g_ErrDelStruct = "Cannot delete a struct member"; const char *g_ErrNoBackQuote= "Name cannot include back-quote"; const char *g_ErrStdString = "Debug/Release std::string mismatch"; const char *g_ErrCStrParam = "Value count for TW_PARAM_CSTRING must be 1"; const char *g_ErrOutOfRange = "Index out of range"; const char *g_ErrHasNoValue = "Has no value"; const char *g_ErrBadType = "Incompatible type"; const char *g_ErrDelHelp = "Cannot delete help bar"; char g_ErrParse[512]; void ANT_CALL TwGlobalError(const char *_ErrorMessage); #if defined(ANT_UNIX) || defined(ANT_OSX) #define _stricmp strcasecmp #define _strdup strdup #endif #ifdef ANT_WINDOWS bool g_UseCurRsc = true; // use dll resources for rotoslider cursors #endif // --------------------------------------------------------------------------- const float FLOAT_EPS = 1.0e-7f; const float FLOAT_EPS_SQ = 1.0e-14f; const float FLOAT_PI = 3.14159265358979323846f; const double DOUBLE_EPS = 1.0e-14; const double DOUBLE_EPS_SQ = 1.0e-28; const double DOUBLE_PI = 3.14159265358979323846; inline double DegToRad(double degree) { return degree * (DOUBLE_PI/180.0); } inline double RadToDeg(double radian) { return radian * (180.0/DOUBLE_PI); } // --------------------------------------------------------------------------- // a static global object to verify that Tweakbar module has been properly terminated (in debug mode only) #ifdef _DEBUG static struct CTwVerif { ~CTwVerif() { if( g_TwMgr!=NULL ) g_TwMgr->SetLastError("Tweak bar module has not been terminated properly: call TwTerminate()\n"); } } s_Verif; #endif // _DEBUG // --------------------------------------------------------------------------- // Color ext type // --------------------------------------------------------------------------- void CColorExt::RGB2HLS() { float fH = 0, fL = 0, fS = 0; ColorRGBToHLSf((float)R/255.0f, (float)G/255.0f, (float)B/255.0f, &fH, &fL, &fS); H = (int)fH; if( H>=360 ) H -= 360; else if( H<0 ) H += 360; L = (int)(255.0f*fL + 0.5f); if( L<0 ) L = 0; else if( L>255 ) L = 255; S = (int)(255.0f*fS + 0.5f); if( S<0 ) S = 0; else if( S>255 ) S = 255; } void CColorExt::HLS2RGB() { float fR = 0, fG = 0, fB = 0; ColorHLSToRGBf((float)H, (float)L/255.0f, (float)S/255.0f, &fR, &fG, &fB); R = (int)(255.0f*fR + 0.5f); if( R<0 ) R = 0; else if( R>255 ) R = 255; G = (int)(255.0f*fG + 0.5f); if( G<0 ) G = 0; else if( G>255 ) G = 255; B = (int)(255.0f*fB + 0.5f); if( B<0 ) B = 0; else if( B>255 ) B = 255; } void ANT_CALL CColorExt::InitColor32CB(void *_ExtValue, void *_ClientData) { CColorExt *ext = static_cast(_ExtValue); if( ext ) { ext->m_IsColorF = false; ext->R = 0; ext->G = 0; ext->B = 0; ext->H = 0; ext->L = 0; ext->S = 0; ext->A = 255; ext->m_HLS = false; ext->m_HasAlpha = false; ext->m_CanHaveAlpha = true; if( g_TwMgr && g_TwMgr->m_GraphAPI==TW_DIRECT3D9 ) // D3D10 now use OGL rgba order! ext->m_OGL = false; else ext->m_OGL = true; ext->m_PrevConvertedColor = Color32FromARGBi(ext->A, ext->R, ext->G, ext->B); ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData; } } void ANT_CALL CColorExt::InitColor3FCB(void *_ExtValue, void *_ClientData) { InitColor32CB(_ExtValue, _ClientData); CColorExt *ext = static_cast(_ExtValue); if( ext ) { ext->m_IsColorF = true; ext->m_HasAlpha = false; ext->m_CanHaveAlpha = false; } } void ANT_CALL CColorExt::InitColor4FCB(void *_ExtValue, void *_ClientData) { InitColor32CB(_ExtValue, _ClientData); CColorExt *ext = static_cast(_ExtValue); if( ext ) { ext->m_IsColorF = true; ext->m_HasAlpha = true; ext->m_CanHaveAlpha = true; } } void ANT_CALL CColorExt::CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData) { unsigned int *var32 = static_cast(_VarValue); float *varF = static_cast(_VarValue); CColorExt *ext = (CColorExt *)(_ExtValue); CTwMgr::CMemberProxy *mProxy = static_cast(_ClientData); if( _VarValue && ext ) { if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F ) ext->m_HasAlpha = false; // Synchronize HLS and RGB if( _ExtMemberIndex>=0 && _ExtMemberIndex<=2 ) ext->RGB2HLS(); else if( _ExtMemberIndex>=3 && _ExtMemberIndex<=5 ) ext->HLS2RGB(); else if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent ) { assert( mProxy->m_VarParent->m_Vars.size()==8 ); if( mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS || mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS || mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS || mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS || mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS || mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS ) { mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS; mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS; mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS; mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS; mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS; mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS; mProxy->m_Bar->NotUpToDate(); } if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha ) { mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha; mProxy->m_Bar->NotUpToDate(); } if( static_cast(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly ) { static_cast(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false; mProxy->m_Bar->NotUpToDate(); } } // Convert to color32 color32 col = Color32FromARGBi((ext->m_HasAlpha ? ext->A : 255), ext->R, ext->G, ext->B); if( ext->m_OGL && !ext->m_IsColorF ) col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16); if( ext->m_IsColorF ) Color32ToARGBf(col, (ext->m_HasAlpha ? varF+3 : NULL), varF+0, varF+1, varF+2); else { if( ext->m_HasAlpha ) *var32 = col; else *var32 = ((*var32)&0xff000000) | (col&0x00ffffff); } ext->m_PrevConvertedColor = col; } } void ANT_CALL CColorExt::CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData) { const unsigned int *var32 = static_cast(_VarValue); const float *varF = static_cast(_VarValue); CColorExt *ext = static_cast(_ExtValue); CTwMgr::CMemberProxy *mProxy = static_cast(_ClientData); if( _VarValue && ext ) { if( ext->m_HasAlpha && mProxy && mProxy->m_StructProxy && mProxy->m_StructProxy->m_Type==g_TwMgr->m_TypeColor3F ) ext->m_HasAlpha = false; if( mProxy && _ExtMemberIndex==7 && mProxy->m_VarParent ) { assert( mProxy->m_VarParent->m_Vars.size()==8 ); if( mProxy->m_VarParent->m_Vars[0]->m_Visible != !ext->m_HLS || mProxy->m_VarParent->m_Vars[1]->m_Visible != !ext->m_HLS || mProxy->m_VarParent->m_Vars[2]->m_Visible != !ext->m_HLS || mProxy->m_VarParent->m_Vars[3]->m_Visible != ext->m_HLS || mProxy->m_VarParent->m_Vars[4]->m_Visible != ext->m_HLS || mProxy->m_VarParent->m_Vars[5]->m_Visible != ext->m_HLS ) { mProxy->m_VarParent->m_Vars[0]->m_Visible = !ext->m_HLS; mProxy->m_VarParent->m_Vars[1]->m_Visible = !ext->m_HLS; mProxy->m_VarParent->m_Vars[2]->m_Visible = !ext->m_HLS; mProxy->m_VarParent->m_Vars[3]->m_Visible = ext->m_HLS; mProxy->m_VarParent->m_Vars[4]->m_Visible = ext->m_HLS; mProxy->m_VarParent->m_Vars[5]->m_Visible = ext->m_HLS; mProxy->m_Bar->NotUpToDate(); } if( mProxy->m_VarParent->m_Vars[6]->m_Visible != ext->m_HasAlpha ) { mProxy->m_VarParent->m_Vars[6]->m_Visible = ext->m_HasAlpha; mProxy->m_Bar->NotUpToDate(); } if( static_cast(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly ) { static_cast(mProxy->m_VarParent->m_Vars[7])->m_ReadOnly = false; mProxy->m_Bar->NotUpToDate(); } } color32 col; if( ext->m_IsColorF ) col = Color32FromARGBf((ext->m_HasAlpha ? varF[3] : 1), varF[0], varF[1], varF[2]); else col = *var32; if( ext->m_OGL && !ext->m_IsColorF ) col = (col&0xff00ff00) | (unsigned char)(col>>16) | (((unsigned char)(col))<<16); Color32ToARGBi(col, (ext->m_HasAlpha ? &ext->A : NULL), &ext->R, &ext->G, &ext->B); if( (col & 0x00ffffff)!=(ext->m_PrevConvertedColor & 0x00ffffff) ) ext->RGB2HLS(); ext->m_PrevConvertedColor = col; } } void ANT_CALL CColorExt::SummaryCB(char *_SummaryString, size_t /*_SummaryMaxLength*/, const void *_ExtValue, void * /*_ClientData*/) { // copy var CColorExt *ext = (CColorExt *)(_ExtValue); if( ext && ext->m_StructProxy && ext->m_StructProxy->m_StructData ) { if( ext->m_StructProxy->m_StructGetCallback ) ext->m_StructProxy->m_StructGetCallback(ext->m_StructProxy->m_StructData, ext->m_StructProxy->m_StructClientData); //if( *(unsigned int *)(ext->m_StructProxy->m_StructData)!=ext->m_PrevConvertedColor ) CopyVarToExtCB(ext->m_StructProxy->m_StructData, ext, 99, NULL); } //unsigned int col = 0; //CopyVar32FromExtCB(&col, _ExtValue, 99, _ClientData); //_snprintf(_SummaryString, _SummaryMaxLength, "0x%.8X", col); //(void) _SummaryMaxLength, _ExtValue, _ClientData; _SummaryString[0] = ' '; // required to force background color for this value _SummaryString[1] = '\0'; } void CColorExt::CreateTypes() { if( g_TwMgr==NULL ) return; TwStructMember ColorExtMembers[] = { { "Red", TW_TYPE_INT32, offsetof(CColorExt, R), "min=0 max=255" }, { "Green", TW_TYPE_INT32, offsetof(CColorExt, G), "min=0 max=255" }, { "Blue", TW_TYPE_INT32, offsetof(CColorExt, B), "min=0 max=255" }, { "Hue", TW_TYPE_INT32, offsetof(CColorExt, H), "hide min=0 max=359" }, { "Lightness", TW_TYPE_INT32, offsetof(CColorExt, L), "hide min=0 max=255" }, { "Saturation", TW_TYPE_INT32, offsetof(CColorExt, S), "hide min=0 max=255" }, { "Alpha", TW_TYPE_INT32, offsetof(CColorExt, A), "hide min=0 max=255" }, { "Mode", TW_TYPE_BOOLCPP, offsetof(CColorExt, m_HLS), "true='HLS' false='RGB' readwrite" } }; g_TwMgr->m_TypeColor32 = TwDefineStructExt("COLOR32", ColorExtMembers, 8, sizeof(unsigned int), sizeof(CColorExt), CColorExt::InitColor32CB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 32-bit-encoded color."); g_TwMgr->m_TypeColor3F = TwDefineStructExt("COLOR3F", ColorExtMembers, 8, 3*sizeof(float), sizeof(CColorExt), CColorExt::InitColor3FCB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-floats-encoded RGB color."); g_TwMgr->m_TypeColor4F = TwDefineStructExt("COLOR4F", ColorExtMembers, 8, 4*sizeof(float), sizeof(CColorExt), CColorExt::InitColor4FCB, CColorExt::CopyVarFromExtCB, CColorExt::CopyVarToExtCB, CColorExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-floats-encoded RGBA color."); // Do not name them "TW_COLOR*" because the name is displayed in the help bar. } // --------------------------------------------------------------------------- // Quaternion ext type // --------------------------------------------------------------------------- void ANT_CALL CQuaternionExt::InitQuat4FCB(void *_ExtValue, void *_ClientData) { CQuaternionExt *ext = static_cast(_ExtValue); if( ext ) { ext->Qx = ext->Qy = ext->Qz = 0; ext->Qs = 1; ext->Vx = 1; ext->Vy = ext->Vz = 0; ext->Angle = 0; ext->Dx = ext->Dy = ext->Dz = 0; ext->m_AAMode = false; // Axis & angle mode hidden ext->m_ShowVal = false; ext->m_IsFloat = true; ext->m_IsDir = false; ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0; ext->m_DirColor = 0xffffff00; int i, j; for(i=0; i<3; ++i) for(j=0; j<3; ++j) ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f; ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData; ext->ConvertToAxisAngle(); ext->m_Highlighted = false; ext->m_Rotating = false; if( ext->m_StructProxy!=NULL ) { ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB; ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB; ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB; ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB; } } } void ANT_CALL CQuaternionExt::InitQuat4DCB(void *_ExtValue, void *_ClientData) { CQuaternionExt *ext = static_cast(_ExtValue); if( ext ) { ext->Qx = ext->Qy = ext->Qz = 0; ext->Qs = 1; ext->Vx = 1; ext->Vy = ext->Vz = 0; ext->Angle = 0; ext->Dx = ext->Dy = ext->Dz = 0; ext->m_AAMode = false; // Axis & angle mode hidden ext->m_ShowVal = false; ext->m_IsFloat = false; ext->m_IsDir = false; ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0; ext->m_DirColor = 0xffffff00; int i, j; for(i=0; i<3; ++i) for(j=0; j<3; ++j) ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f; ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData; ext->ConvertToAxisAngle(); ext->m_Highlighted = false; ext->m_Rotating = false; if( ext->m_StructProxy!=NULL ) { ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB; ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB; ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB; ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB; } } } void ANT_CALL CQuaternionExt::InitDir3FCB(void *_ExtValue, void *_ClientData) { CQuaternionExt *ext = static_cast(_ExtValue); if( ext ) { ext->Qx = ext->Qy = ext->Qz = 0; ext->Qs = 1; ext->Vx = 1; ext->Vy = ext->Vz = 0; ext->Angle = 0; ext->Dx = 1; ext->Dy = ext->Dz = 0; ext->m_AAMode = false; // Axis & angle mode hidden ext->m_ShowVal = true; ext->m_IsFloat = true; ext->m_IsDir = true; ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0; ext->m_DirColor = 0xffffff00; int i, j; for(i=0; i<3; ++i) for(j=0; j<3; ++j) ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f; ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData; ext->ConvertToAxisAngle(); ext->m_Highlighted = false; ext->m_Rotating = false; if( ext->m_StructProxy!=NULL ) { ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB; ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB; ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB; ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB; } } } void ANT_CALL CQuaternionExt::InitDir3DCB(void *_ExtValue, void *_ClientData) { CQuaternionExt *ext = static_cast(_ExtValue); if( ext ) { ext->Qx = ext->Qy = ext->Qz = 0; ext->Qs = 1; ext->Vx = 1; ext->Vy = ext->Vz = 0; ext->Angle = 0; ext->Dx = 1; ext->Dy = ext->Dz = 0; ext->m_AAMode = false; // Axis & angle mode hidden ext->m_ShowVal = true; ext->m_IsFloat = false; ext->m_IsDir = true; ext->m_Dir[0] = ext->m_Dir[1] = ext->m_Dir[2] = 0; ext->m_DirColor = 0xffffff00; int i, j; for(i=0; i<3; ++i) for(j=0; j<3; ++j) ext->m_Permute[i][j] = (i==j) ? 1.0f : 0.0f; ext->m_StructProxy = (CTwMgr::CStructProxy *)_ClientData; ext->ConvertToAxisAngle(); ext->m_Highlighted = false; ext->m_Rotating = false; if( ext->m_StructProxy!=NULL ) { ext->m_StructProxy->m_CustomDrawCallback = CQuaternionExt::DrawCB; ext->m_StructProxy->m_CustomMouseButtonCallback = CQuaternionExt::MouseButtonCB; ext->m_StructProxy->m_CustomMouseMotionCallback = CQuaternionExt::MouseMotionCB; ext->m_StructProxy->m_CustomMouseLeaveCallback = CQuaternionExt::MouseLeaveCB; } } } void ANT_CALL CQuaternionExt::CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData) { CQuaternionExt *ext = (CQuaternionExt *)(_ExtValue); CTwMgr::CMemberProxy *mProxy = static_cast(_ClientData); if( _VarValue && ext ) { // Synchronize Quat and AxisAngle if( _ExtMemberIndex>=4 && _ExtMemberIndex<=7 ) { ext->ConvertToAxisAngle(); // show/hide quat values if( _ExtMemberIndex==4 && mProxy && mProxy->m_VarParent ) { assert( mProxy->m_VarParent->m_Vars.size()==16 ); bool visible = ext->m_ShowVal; if( ext->m_IsDir ) { if( mProxy->m_VarParent->m_Vars[13]->m_Visible != visible || mProxy->m_VarParent->m_Vars[14]->m_Visible != visible || mProxy->m_VarParent->m_Vars[15]->m_Visible != visible ) { mProxy->m_VarParent->m_Vars[13]->m_Visible = visible; mProxy->m_VarParent->m_Vars[14]->m_Visible = visible; mProxy->m_VarParent->m_Vars[15]->m_Visible = visible; mProxy->m_Bar->NotUpToDate(); } } else { if( mProxy->m_VarParent->m_Vars[4]->m_Visible != visible || mProxy->m_VarParent->m_Vars[5]->m_Visible != visible || mProxy->m_VarParent->m_Vars[6]->m_Visible != visible || mProxy->m_VarParent->m_Vars[7]->m_Visible != visible ) { mProxy->m_VarParent->m_Vars[4]->m_Visible = visible; mProxy->m_VarParent->m_Vars[5]->m_Visible = visible; mProxy->m_VarParent->m_Vars[6]->m_Visible = visible; mProxy->m_VarParent->m_Vars[7]->m_Visible = visible; mProxy->m_Bar->NotUpToDate(); } } } } else if( _ExtMemberIndex>=8 && _ExtMemberIndex<=11 ) ext->ConvertFromAxisAngle(); else if( mProxy && _ExtMemberIndex==12 && mProxy->m_VarParent && !ext->m_IsDir ) { assert( mProxy->m_VarParent->m_Vars.size()==16 ); bool aa = ext->m_AAMode; if( mProxy->m_VarParent->m_Vars[4]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[5]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[6]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[7]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[8 ]->m_Visible != aa || mProxy->m_VarParent->m_Vars[9 ]->m_Visible != aa || mProxy->m_VarParent->m_Vars[10]->m_Visible != aa || mProxy->m_VarParent->m_Vars[11]->m_Visible != aa ) { mProxy->m_VarParent->m_Vars[4]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[5]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[6]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[7]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[8 ]->m_Visible = aa; mProxy->m_VarParent->m_Vars[9 ]->m_Visible = aa; mProxy->m_VarParent->m_Vars[10]->m_Visible = aa; mProxy->m_VarParent->m_Vars[11]->m_Visible = aa; mProxy->m_Bar->NotUpToDate(); } if( static_cast(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly ) { static_cast(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly = false; mProxy->m_Bar->NotUpToDate(); } } if( ext->m_IsFloat ) { float *var = static_cast(_VarValue); if( ext->m_IsDir ) { var[0] = (float)ext->Dx; var[1] = (float)ext->Dy; var[2] = (float)ext->Dz; } else // quat { var[0] = (float)ext->Qx; var[1] = (float)ext->Qy; var[2] = (float)ext->Qz; var[3] = (float)ext->Qs; } } else { double *var = static_cast(_VarValue); if( ext->m_IsDir ) { var[0] = ext->Dx; var[1] = ext->Dy; var[2] = ext->Dz; } else // quat { var[0] = ext->Qx; var[1] = ext->Qy; var[2] = ext->Qz; var[3] = ext->Qs; } } } } void ANT_CALL CQuaternionExt::CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData) { CQuaternionExt *ext = static_cast(_ExtValue); CTwMgr::CMemberProxy *mProxy = static_cast(_ClientData); (void)mProxy; if( _VarValue && ext ) { if( mProxy && _ExtMemberIndex==12 && mProxy->m_VarParent && !ext->m_IsDir ) { assert( mProxy->m_VarParent->m_Vars.size()==16 ); bool aa = ext->m_AAMode; if( mProxy->m_VarParent->m_Vars[4]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[5]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[6]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[7]->m_Visible != !aa || mProxy->m_VarParent->m_Vars[8 ]->m_Visible != aa || mProxy->m_VarParent->m_Vars[9 ]->m_Visible != aa || mProxy->m_VarParent->m_Vars[10]->m_Visible != aa || mProxy->m_VarParent->m_Vars[11]->m_Visible != aa ) { mProxy->m_VarParent->m_Vars[4]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[5]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[6]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[7]->m_Visible = !aa; mProxy->m_VarParent->m_Vars[8 ]->m_Visible = aa; mProxy->m_VarParent->m_Vars[9 ]->m_Visible = aa; mProxy->m_VarParent->m_Vars[10]->m_Visible = aa; mProxy->m_VarParent->m_Vars[11]->m_Visible = aa; mProxy->m_Bar->NotUpToDate(); } if( static_cast(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly ) { static_cast(mProxy->m_VarParent->m_Vars[12])->m_ReadOnly = false; mProxy->m_Bar->NotUpToDate(); } } else if( mProxy && _ExtMemberIndex==4 && mProxy->m_VarParent ) { assert( mProxy->m_VarParent->m_Vars.size()==16 ); bool visible = ext->m_ShowVal; if( ext->m_IsDir ) { if( mProxy->m_VarParent->m_Vars[13]->m_Visible != visible || mProxy->m_VarParent->m_Vars[14]->m_Visible != visible || mProxy->m_VarParent->m_Vars[15]->m_Visible != visible ) { mProxy->m_VarParent->m_Vars[13]->m_Visible = visible; mProxy->m_VarParent->m_Vars[14]->m_Visible = visible; mProxy->m_VarParent->m_Vars[15]->m_Visible = visible; mProxy->m_Bar->NotUpToDate(); } } else { if( mProxy->m_VarParent->m_Vars[4]->m_Visible != visible || mProxy->m_VarParent->m_Vars[5]->m_Visible != visible || mProxy->m_VarParent->m_Vars[6]->m_Visible != visible || mProxy->m_VarParent->m_Vars[7]->m_Visible != visible ) { mProxy->m_VarParent->m_Vars[4]->m_Visible = visible; mProxy->m_VarParent->m_Vars[5]->m_Visible = visible; mProxy->m_VarParent->m_Vars[6]->m_Visible = visible; mProxy->m_VarParent->m_Vars[7]->m_Visible = visible; mProxy->m_Bar->NotUpToDate(); } } } if( ext->m_IsFloat ) { const float *var = static_cast(_VarValue); if( ext->m_IsDir ) { ext->Dx = var[0]; ext->Dy = var[1]; ext->Dz = var[2]; QuatFromDir(&ext->Qx, &ext->Qy, &ext->Qz, &ext->Qs, var[0], var[1], var[2]); } else { ext->Qx = var[0]; ext->Qy = var[1]; ext->Qz = var[2]; ext->Qs = var[3]; } } else { const double *var = static_cast(_VarValue); if( ext->m_IsDir ) { ext->Dx = var[0]; ext->Dy = var[1]; ext->Dz = var[2]; QuatFromDir(&ext->Qx, &ext->Qy, &ext->Qz, &ext->Qs, var[0], var[1], var[2]); } else { ext->Qx = var[0]; ext->Qy = var[1]; ext->Qz = var[2]; ext->Qs = var[3]; } } ext->ConvertToAxisAngle(); } } void ANT_CALL CQuaternionExt::SummaryCB(char *_SummaryString, size_t _SummaryMaxLength, const void *_ExtValue, void * /*_ClientData*/) { const CQuaternionExt *ext = static_cast(_ExtValue); if( ext ) { if( ext->m_AAMode ) _snprintf(_SummaryString, _SummaryMaxLength, "V={%.2f,%.2f,%.2f} A=%.0f", ext->Vx, ext->Vy, ext->Vz, ext->Angle); else if( ext->m_IsDir ) { //float d[] = {1, 0, 0}; //ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)ext->Qx, (float)ext->Qy, (float)ext->Qz, (float)ext->Qs); _snprintf(_SummaryString, _SummaryMaxLength, "V={%.2f,%.2f,%.2f}", ext->Dx, ext->Dy, ext->Dz); } else _snprintf(_SummaryString, _SummaryMaxLength, "Q={x:%.2f,y:%.2f,z:%.2f,s:%.2f}", ext->Qx, ext->Qy, ext->Qz, ext->Qs); } else { _SummaryString[0] = ' '; // required to force background color for this value _SummaryString[1] = '\0'; } } TwType CQuaternionExt::s_CustomType = TW_TYPE_UNDEF; vector CQuaternionExt::s_SphTri; vector CQuaternionExt::s_SphCol; vector CQuaternionExt::s_SphTriProj; vector CQuaternionExt::s_SphColLight; vector CQuaternionExt::s_ArrowTri[4]; vector CQuaternionExt::s_ArrowNorm[4]; vector CQuaternionExt::s_ArrowTriProj[4]; vector CQuaternionExt::s_ArrowColLight[4]; void CQuaternionExt::CreateTypes() { if( g_TwMgr==NULL ) return; s_CustomType = (TwType)(TW_TYPE_CUSTOM_BASE + (int)g_TwMgr->m_Customs.size()); g_TwMgr->m_Customs.push_back(NULL); // increment custom type number for(int pass=0; pass<2; pass++) // pass 0: create quat types; pass 1: create dir types { const char *quatDefPass0 = "step=0.01 hide"; const char *quatDefPass1 = "step=0.01 hide"; const char *quatSDefPass0 = "step=0.01 min=-1 max=1 hide"; const char *quatSDefPass1 = "step=0.01 min=-1 max=1 hide"; const char *dirDefPass0 = "step=0.01 hide"; const char *dirDefPass1 = "step=0.01"; const char *quatDef = (pass==0) ? quatDefPass0 : quatDefPass1; const char *quatSDef = (pass==0) ? quatSDefPass0 : quatSDefPass1; const char *dirDef = (pass==0) ? dirDefPass0 : dirDefPass1; TwStructMember QuatExtMembers[] = { { "0", s_CustomType, 0, "" }, { "1", s_CustomType, 0, "" }, { "2", s_CustomType, 0, "" }, { "3", s_CustomType, 0, "" }, { "Quat X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qx), quatDef }, // copy of the source quaternion { "Quat Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qy), quatDef }, { "Quat Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qz), quatDef }, { "Quat S", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Qs), quatSDef }, { "Axis X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vx), "step=0.01 hide" }, // axis and angle conversion -> Mode hidden because it is not equivalent to a quat (would have required vector renormalization) { "Axis Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vy), "step=0.01 hide" }, { "Axis Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Vz), "step=0.01 hide" }, { "Angle (degree)", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Angle), "step=1 min=-360 max=360 hide" }, { "Mode", TW_TYPE_BOOLCPP, offsetof(CQuaternionExt, m_AAMode), "true='Axis Angle' false='Quaternion' readwrite hide" }, { "Dir X", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dx), dirDef }, // copy of the source direction { "Dir Y", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dy), dirDef }, { "Dir Z", TW_TYPE_DOUBLE, offsetof(CQuaternionExt, Dz), dirDef } }; if( pass==0 ) { g_TwMgr->m_TypeQuat4F = TwDefineStructExt("QUAT4F", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 4*sizeof(float), sizeof(CQuaternionExt), CQuaternionExt::InitQuat4FCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-floats-encoded quaternion"); g_TwMgr->m_TypeQuat4D = TwDefineStructExt("QUAT4D", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 4*sizeof(double), sizeof(CQuaternionExt), CQuaternionExt::InitQuat4DCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 4-doubles-encoded quaternion"); } else if( pass==1 ) { g_TwMgr->m_TypeDir3F = TwDefineStructExt("DIR4F", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 3*sizeof(float), sizeof(CQuaternionExt), CQuaternionExt::InitDir3FCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-floats-encoded direction"); g_TwMgr->m_TypeDir3D = TwDefineStructExt("DIR4D", QuatExtMembers, sizeof(QuatExtMembers)/sizeof(QuatExtMembers[0]), 3*sizeof(double), sizeof(CQuaternionExt), CQuaternionExt::InitDir3DCB, CQuaternionExt::CopyVarFromExtCB, CQuaternionExt::CopyVarToExtCB, CQuaternionExt::SummaryCB, CTwMgr::CStruct::s_PassProxyAsClientData, "A 3-doubles-encoded direction"); } } CreateSphere(); CreateArrow(); } void CQuaternionExt::ConvertToAxisAngle() { if( fabs(Qs)>(1.0 + FLOAT_EPS) ) { //Vx = Vy = Vz = 0; // no, keep the previous value Angle = 0; } else { double a; if( Qs>=1.0f ) a = 0; // and keep V else if( Qs<=-1.0f ) a = DOUBLE_PI; // and keep V else if( fabs(Qx*Qx+Qy*Qy+Qz*Qz+Qs*Qs)FLOAT_PI ) // Angle -= 2.0f*FLOAT_PI; // else if( Angle<-FLOAT_PI ) // Angle += 2.0f*FLOAT_PI; Angle = RadToDeg(Angle); if( fabs(Angle)FLOAT_EPS_SQ ) { double f = 0.5*DegToRad(Angle); Qs = cos(f); //do not normalize //if( fabs(n - 1.0)>FLOAT_EPS_SQ ) // f = sin(f) * (1.0/sqrt(n)) ; //else // f = sin(f); f = sin(f); Qx = Vx * f; Qy = Vy * f; Qz = Vz * f; } else { Qs = 1.0; Qx = Qy = Qz = 0.0; } } void CQuaternionExt::CopyToVar() { if( m_StructProxy!=NULL ) { if( m_StructProxy->m_StructSetCallback!=NULL ) { if( m_IsFloat ) { if( m_IsDir ) { float d[] = {1, 0, 0}; ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs); float l = (float)sqrt(Dx*Dx + Dy*Dy + Dz*Dz); d[0] *= l; d[1] *= l; d[2] *= l; Dx = d[0]; Dy = d[1]; Dz = d[2]; // update also Dx,Dy,Dz m_StructProxy->m_StructSetCallback(d, m_StructProxy->m_StructClientData); } else { float q[] = { (float)Qx, (float)Qy, (float)Qz, (float)Qs }; m_StructProxy->m_StructSetCallback(q, m_StructProxy->m_StructClientData); } } else { if( m_IsDir ) { float d[] = {1, 0, 0}; ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs); double l = sqrt(Dx*Dx + Dy*Dy + Dz*Dz); double dd[] = {l*d[0], l*d[1], l*d[2]}; Dx = dd[0]; Dy = dd[1]; Dz = dd[2]; // update also Dx,Dy,Dz m_StructProxy->m_StructSetCallback(dd, m_StructProxy->m_StructClientData); } else { double q[] = { Qx, Qy, Qz, Qs }; m_StructProxy->m_StructSetCallback(q, m_StructProxy->m_StructClientData); } } } else if( m_StructProxy->m_StructData!=NULL ) { if( m_IsFloat ) { if( m_IsDir ) { float *d = static_cast(m_StructProxy->m_StructData); ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs); float l = (float)sqrt(Dx*Dx + Dy*Dy + Dz*Dz); d[0] *= l; d[1] *= l; d[2] *= l; Dx = d[0]; Dy = d[1]; Dz = d[2]; // update also Dx,Dy,Dz } else { float *q = static_cast(m_StructProxy->m_StructData); q[0] = (float)Qx; q[1] = (float)Qy; q[2] = (float)Qz; q[3] = (float)Qs; } } else { if( m_IsDir ) { double *dd = static_cast(m_StructProxy->m_StructData); float d[] = {1, 0, 0}; ApplyQuat(d+0, d+1, d+2, 1, 0, 0, (float)Qx, (float)Qy, (float)Qz, (float)Qs); double l = sqrt(Dx*Dx + Dy*Dy + Dz*Dz); dd[0] = l*d[0]; dd[1] = l*d[1]; dd[2] = l*d[2]; Dx = dd[0]; Dy = dd[1]; Dz = dd[2]; // update also Dx,Dy,Dz } else { double *q = static_cast(m_StructProxy->m_StructData); q[0] = Qx; q[1] = Qy; q[2] = Qz; q[3] = Qs; } } } } } void CQuaternionExt::CreateSphere() { const int SUBDIV = 7; s_SphTri.clear(); s_SphCol.clear(); const float A[8*3] = { 1,0,0, 0,0,-1, -1,0,0, 0,0,1, 0,0,1, 1,0,0, 0,0,-1, -1,0,0 }; const float B[8*3] = { 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0 }; const float C[8*3] = { 0,0,1, 1,0,0, 0,0,-1, -1,0,0, 1,0,0, 0,0,-1, -1,0,0, 0,0,1 }; //const color32 COL_A[8] = { 0xffff8080, 0xff000080, 0xff800000, 0xff8080ff, 0xff8080ff, 0xffff8080, 0xff000080, 0xff800000 }; //const color32 COL_B[8] = { 0xff80ff80, 0xff80ff80, 0xff80ff80, 0xff80ff80, 0xff008000, 0xff008000, 0xff008000, 0xff008000 }; //const color32 COL_C[8] = { 0xff8080ff, 0xffff8080, 0xff000080, 0xff800000, 0xffff8080, 0xff000080, 0xff800000, 0xff8080ff }; const color32 COL_A[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff }; const color32 COL_B[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff }; const color32 COL_C[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff }; int i, j, k, l; float xa, ya, za, xb, yb, zb, xc, yc, zc, x, y, z, norm, u[3], v[3]; color32 col; for( i=0; i<8; ++i ) { xa = A[3*i+0]; ya = A[3*i+1]; za = A[3*i+2]; xb = B[3*i+0]; yb = B[3*i+1]; zb = B[3*i+2]; xc = C[3*i+0]; yc = C[3*i+1]; zc = C[3*i+2]; for( j=0; j<=SUBDIV; ++j ) for( k=0; k<=2*(SUBDIV-j); ++k ) { if( k%2==0 ) { u[0] = ((float)j)/(SUBDIV+1); v[0] = ((float)(k/2))/(SUBDIV+1); u[1] = ((float)(j+1))/(SUBDIV+1); v[1] = ((float)(k/2))/(SUBDIV+1); u[2] = ((float)j)/(SUBDIV+1); v[2] = ((float)(k/2+1))/(SUBDIV+1); } else { u[0] = ((float)j)/(SUBDIV+1); v[0] = ((float)(k/2+1))/(SUBDIV+1); u[1] = ((float)(j+1))/(SUBDIV+1); v[1] = ((float)(k/2))/(SUBDIV+1); u[2] = ((float)(j+1))/(SUBDIV+1); v[2] = ((float)(k/2+1))/(SUBDIV+1); } for( l=0; l<3; ++l ) { x = (1.0f-u[l]-v[l])*xa + u[l]*xb + v[l]*xc; y = (1.0f-u[l]-v[l])*ya + u[l]*yb + v[l]*yc; z = (1.0f-u[l]-v[l])*za + u[l]*zb + v[l]*zc; norm = sqrtf(x*x+y*y+z*z); x /= norm; y /= norm; z /= norm; s_SphTri.push_back(x); s_SphTri.push_back(y); s_SphTri.push_back(z); if( u[l]+v[l]>FLOAT_EPS ) col = ColorBlend(COL_A[i], ColorBlend(COL_B[i], COL_C[i], v[l]/(u[l]+v[l])), u[l]+v[l]); else col = COL_A[i]; //if( (j==0 && k==0) || (j==0 && k==2*SUBDIV) || (j==SUBDIV && k==0) ) // col = 0xffff0000; s_SphCol.push_back(col); } } } s_SphTriProj.clear(); s_SphTriProj.resize(2*s_SphCol.size(), 0); s_SphColLight.clear(); s_SphColLight.resize(s_SphCol.size(), 0); } void CQuaternionExt::CreateArrow() { const int SUBDIV = 15; const float CYL_RADIUS = 0.08f; const float CONE_RADIUS = 0.16f; const float CONE_LENGTH = 0.25f; const float ARROW_BGN = -1.1f; const float ARROW_END = 1.15f; int i; for(i=0; i<4; ++i) { s_ArrowTri[i].clear(); s_ArrowNorm[i].clear(); } float x0, x1, y0, y1, z0, z1, a0, a1, nx, nn; for(i=0; iDOUBLE_EPS ) { double f = 0.5*angle; out[3] = cos(f); f = sin(f)/sqrt(n); out[0] = axis[0]*f; out[1] = axis[1]*f; out[2] = axis[2]*f; } else { out[3] = 1.0; out[0] = out[1] = out[2] = 0.0; } } static inline void Vec3Cross(double *out, const double *a, const double *b) { out[0] = a[1]*b[2]-a[2]*b[1]; out[1] = a[2]*b[0]-a[0]*b[2]; out[2] = a[0]*b[1]-a[1]*b[0]; } static inline double Vec3Dot(const double *a, const double *b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } static inline void Vec3RotY(float *x, float *y, float *z) { (void)y; float tmp = *x; *x = - *z; *z = tmp; } static inline void Vec3RotZ(float *x, float *y, float *z) { (void)z; float tmp = *x; *x = - *y; *y = tmp; } void CQuaternionExt::ApplyQuat(float *outX, float *outY, float *outZ, float x, float y, float z, float qx, float qy, float qz, float qs) { float ps = - qx * x - qy * y - qz * z; float px = qs * x + qy * z - qz * y; float py = qs * y + qz * x - qx * z; float pz = qs * z + qx * y - qy * x; *outX = - ps * qx + px * qs - py * qz + pz * qy; *outY = - ps * qy + py * qs - pz * qx + px * qz; *outZ = - ps * qz + pz * qs - px * qy + py * qx; } void CQuaternionExt::QuatFromDir(double *outQx, double *outQy, double *outQz, double *outQs, double dx, double dy, double dz) { // compute a quaternion that rotates (1,0,0) to (dx,dy,dz) double dn = sqrt(dx*dx + dy*dy + dz*dz); if( dnm_Graph==NULL ) return; assert( g_TwMgr->m_Graph->IsDrawing() ); CQuaternionExt *ext = static_cast(_ExtValue); assert( ext!=NULL ); (void)_ClientData; (void)_Bar; // show/hide quat values assert( varGrp->m_Vars.size()==16 ); bool visible = ext->m_ShowVal; if( ext->m_IsDir ) { if( varGrp->m_Vars[13]->m_Visible != visible || varGrp->m_Vars[14]->m_Visible != visible || varGrp->m_Vars[15]->m_Visible != visible ) { varGrp->m_Vars[13]->m_Visible = visible; varGrp->m_Vars[14]->m_Visible = visible; varGrp->m_Vars[15]->m_Visible = visible; _Bar->NotUpToDate(); } } else { if( varGrp->m_Vars[4]->m_Visible != visible || varGrp->m_Vars[5]->m_Visible != visible || varGrp->m_Vars[6]->m_Visible != visible || varGrp->m_Vars[7]->m_Visible != visible ) { varGrp->m_Vars[4]->m_Visible = visible; varGrp->m_Vars[5]->m_Visible = visible; varGrp->m_Vars[6]->m_Visible = visible; varGrp->m_Vars[7]->m_Visible = visible; _Bar->NotUpToDate(); } } // force ext update static_cast(varGrp->m_Vars[4])->ValueToDouble(); assert( s_SphTri.size()>0 ); assert( s_SphTri.size()==3*s_SphCol.size() ); assert( s_SphTriProj.size()==2*s_SphCol.size() ); assert( s_SphColLight.size()==s_SphCol.size() ); if( QuatD(w, h)<=2 ) return; float x, y, z, nx, ny, nz, kx, ky, kz, qx, qy, qz, qs; int i, j, k, l, m; // normalize quaternion float qn = (float)sqrt(ext->Qs*ext->Qs+ext->Qx*ext->Qx+ext->Qy*ext->Qy+ext->Qz*ext->Qz); if( qn>FLOAT_EPS ) { qx = (float)ext->Qx/qn; qy = (float)ext->Qy/qn; qz = (float)ext->Qz/qn; qs = (float)ext->Qs/qn; } else { qx = qy = qz = 0; qs = 1; } double normDir = sqrt(ext->m_Dir[0]*ext->m_Dir[0] + ext->m_Dir[1]*ext->m_Dir[1] + ext->m_Dir[2]*ext->m_Dir[2]); bool drawDir = ext->m_IsDir || (normDir>DOUBLE_EPS); color32 alpha = ext->m_Highlighted ? 0xffffffff : 0xb0ffffff; // check if frame is right-handed ext->Permute(&kx, &ky, &kz, 1, 0, 0); double px[3] = { (double)kx, (double)ky, (double)kz }; ext->Permute(&kx, &ky, &kz, 0, 1, 0); double py[3] = { (double)kx, (double)ky, (double)kz }; ext->Permute(&kx, &ky, &kz, 0, 0, 1); double pz[3] = { (double)kx, (double)ky, (double)kz }; double ez[3]; Vec3Cross(ez, px, py); bool frameRightHanded = (ez[0]*pz[0]+ez[1]*pz[1]+ez[2]*pz[2] >= 0); ITwGraph::Cull cull = frameRightHanded ? ITwGraph::CULL_CW : ITwGraph::CULL_CCW; if( drawDir ) { float dir[] = {(float)ext->m_Dir[0], (float)ext->m_Dir[1], (float)ext->m_Dir[2]}; if( normDirPermute(&x, &y, &z, kx, ky, kz); j = (z>0) ? 3-k : k; assert( s_ArrowTriProj[j].size()==2*(s_ArrowTri[j].size()/3) && s_ArrowColLight[j].size()==s_ArrowTri[j].size()/3 && s_ArrowNorm[j].size()==s_ArrowTri[j].size() ); const int ntri = (int)s_ArrowTri[j].size()/3; const float *tri = &(s_ArrowTri[j][0]); const float *norm = &(s_ArrowNorm[j][0]); int *triProj = &(s_ArrowTriProj[j][0]); color32 *colLight = &(s_ArrowColLight[j][0]); for(i=0; i0 ) x = 2.5f*x - 2.0f; else x += 0.2f; y *= 1.5f; z *= 1.5f; ApplyQuat(&x, &y, &z, x, y, z, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]); ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs); ext->Permute(&x, &y, &z, x, y, z); ApplyQuat(&nx, &ny, &nz, nx, ny, nz, (float)rotDirQuat[0], (float)rotDirQuat[1], (float)rotDirQuat[2], (float)rotDirQuat[3]); ApplyQuat(&nx, &ny, &nz, nx, ny, nz, qx, qy, qz, qs); ext->Permute(&nx, &ny, &nz, nx, ny, nz); triProj[2*i+0] = QuatPX(x, w, h); triProj[2*i+1] = QuatPY(y, w, h); color32 col = (ext->m_DirColor|0xff000000) & alpha; colLight[i] = ColorBlend(0xff000000, col, fabsf(TClamp(nz, -1.0f, 1.0f))); } if( s_ArrowTri[j].size()>=9 ) // 1 tri = 9 floats g_TwMgr->m_Graph->DrawTriangles((int)s_ArrowTri[j].size()/9, triProj, colLight, cull); } } else { /* int px0 = QuatPX(0, w, h)-1, py0 = QuatPY(0, w, h), r0 = (int)(0.5f*QuatD(w, h)-0.5f); color32 col0 = 0x80000000; DrawArc(px0-1, py0, r0, 0, 360, col0); DrawArc(px0+1, py0, r0, 0, 360, col0); DrawArc(px0, py0-1, r0, 0, 360, col0); DrawArc(px0, py0+1, r0, 0, 360, col0); */ // draw arrows & sphere const float SPH_RADIUS = 0.75f; for(m=0; m<2; ++m) // m=0: back, m=1: front { for(l=0; l<3; ++l) // draw 3 arrows { kx = 1; ky = 0; kz = 0; if( l==1 ) Vec3RotZ(&kx, &ky, &kz); else if( l==2 ) Vec3RotY(&kx, &ky, &kz); ApplyQuat(&kx, &ky, &kz, kx, ky, kz, qx, qy, qz, qs); for(k=0; k<4; ++k) // 4 parts of the arrow { // draw order ext->Permute(&x, &y, &z, kx, ky, kz); j = (z>0) ? 3-k : k; bool cone = true; if( (m==0 && z>0) || (m==1 && z<=0) ) { if( j==ARROW_CONE || j==ARROW_CONE_CAP ) // do not draw cone continue; else cone = false; } assert( s_ArrowTriProj[j].size()==2*(s_ArrowTri[j].size()/3) && s_ArrowColLight[j].size()==s_ArrowTri[j].size()/3 && s_ArrowNorm[j].size()==s_ArrowTri[j].size() ); const int ntri = (int)s_ArrowTri[j].size()/3; const float *tri = &(s_ArrowTri[j][0]); const float *norm = &(s_ArrowNorm[j][0]); int *triProj = &(s_ArrowTriProj[j][0]); color32 *colLight = &(s_ArrowColLight[j][0]); for(i=0; i0 ) x = -SPH_RADIUS; nx = norm[3*i+0]; ny = norm[3*i+1]; nz = norm[3*i+2]; if( l==1 ) { Vec3RotZ(&x, &y, &z); Vec3RotZ(&nx, &ny, &nz); } else if( l==2 ) { Vec3RotY(&x, &y, &z); Vec3RotY(&nx, &ny, &nz); } ApplyQuat(&x, &y, &z, x, y, z, qx, qy, qz, qs); ext->Permute(&x, &y, &z, x, y, z); ApplyQuat(&nx, &ny, &nz, nx, ny, nz, qx, qy, qz, qs); ext->Permute(&nx, &ny, &nz, nx, ny, nz); triProj[2*i+0] = QuatPX(x, w, h); triProj[2*i+1] = QuatPY(y, w, h); float fade = ( m==0 && z<0 ) ? TClamp(2.0f*z*z, 0.0f, 1.0f) : 0; float alphaFade = 1.0f; Color32ToARGBf(alpha, &alphaFade, NULL, NULL, NULL); alphaFade *= (1.0f-fade); color32 alphaFadeCol = Color32FromARGBf(alphaFade, 1, 1, 1); color32 col = (l==0) ? 0xffff0000 : ( (l==1) ? 0xff00ff00 : 0xff0000ff ); colLight[i] = ColorBlend(0xff000000, col, fabsf(TClamp(nz, -1.0f, 1.0f))) & alphaFadeCol; } if( s_ArrowTri[j].size()>=9 ) // 1 tri = 9 floats g_TwMgr->m_Graph->DrawTriangles((int)s_ArrowTri[j].size()/9, triProj, colLight, cull); } } if( m==0 ) { const float *tri = &(s_SphTri[0]); int *triProj = &(s_SphTriProj[0]); const color32 *col = &(s_SphCol[0]); color32 *colLight = &(s_SphColLight[0]); const int ntri = (int)s_SphTri.size()/3; for(i=0; iPermute(&x, &y, &z, x, y, z); triProj[2*i+0] = QuatPX(x, w, h); triProj[2*i+1] = QuatPY(y, w, h); colLight[i] = ColorBlend(0xff000000, col[i], fabsf(TClamp(z/SPH_RADIUS, -1.0f, 1.0f))) & alpha; } g_TwMgr->m_Graph->DrawTriangles((int)s_SphTri.size()/9, triProj, colLight, cull); } } // draw x g_TwMgr->m_Graph->DrawLine(w-12, h-36, w-12+5, h-36+5, 0xffc00000, true); g_TwMgr->m_Graph->DrawLine(w-12+5, h-36, w-12, h-36+5, 0xffc00000, true); // draw y g_TwMgr->m_Graph->DrawLine(w-12, h-25, w-12+3, h-25+4, 0xff00c000, true); g_TwMgr->m_Graph->DrawLine(w-12+5, h-25, w-12, h-25+7, 0xff00c000, true); // draw z g_TwMgr->m_Graph->DrawLine(w-12, h-12, w-12+5, h-12, 0xff0000c0, true); g_TwMgr->m_Graph->DrawLine(w-12, h-12+5, w-12+5, h-12+5, 0xff0000c0, true); g_TwMgr->m_Graph->DrawLine(w-12, h-12+5, w-12+5, h-12, 0xff0000c0, true); } // draw borders g_TwMgr->m_Graph->DrawLine(1, 0, w-1, 0, 0x40000000); g_TwMgr->m_Graph->DrawLine(w-1, 0, w-1, h-1, 0x40000000); g_TwMgr->m_Graph->DrawLine(w-1, h-1, 1, h-1, 0x40000000); g_TwMgr->m_Graph->DrawLine(1, h-1, 1, 0, 0x40000000); } bool CQuaternionExt::MouseMotionCB(int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp) { CQuaternionExt *ext = static_cast(structExtValue); if( ext==NULL ) return false; (void)clientData, (void)varGrp; if( mouseX>0 && mouseX0 && mouseYm_Highlighted = true; if( ext->m_Rotating ) { double x = QuatIX(mouseX, w, h); double y = QuatIY(mouseY, w, h); double z = 1; double px, py, pz, ox, oy, oz; ext->PermuteInv(&px, &py, &pz, x, y, z); ext->PermuteInv(&ox, &oy, &oz, ext->m_OrigX, ext->m_OrigY, 1); double n0 = sqrt(ox*ox + oy*oy + oz*oz); double n1 = sqrt(px*px + py*py + pz*pz); if( n0>DOUBLE_EPS && n1>DOUBLE_EPS ) { double v0[] = { ox/n0, oy/n0, oz/n0 }; double v1[] = { px/n1, py/n1, pz/n1 }; double axis[3]; Vec3Cross(axis, v0, v1); double sa = sqrt(Vec3Dot(axis, axis)); double ca = Vec3Dot(v0, v1); double angle = atan2(sa, ca); if( x*x+y*y>1.0 ) angle *= 1.0 + 0.2f*(sqrt(x*x+y*y)-1.0); double qrot[4], qres[4], qorig[4]; QuatFromAxisAngle(qrot, axis, angle); double nqorig = sqrt(ext->m_OrigQuat[0]*ext->m_OrigQuat[0]+ext->m_OrigQuat[1]*ext->m_OrigQuat[1]+ext->m_OrigQuat[2]*ext->m_OrigQuat[2]+ext->m_OrigQuat[3]*ext->m_OrigQuat[3]); if( fabs(nqorig)>DOUBLE_EPS_SQ ) { qorig[0] = ext->m_OrigQuat[0]/nqorig; qorig[1] = ext->m_OrigQuat[1]/nqorig; qorig[2] = ext->m_OrigQuat[2]/nqorig; qorig[3] = ext->m_OrigQuat[3]/nqorig; QuatMult(qres, qrot, qorig); ext->Qx = qres[0]; ext->Qy = qres[1]; ext->Qz = qres[2]; ext->Qs = qres[3]; } else { ext->Qx = qrot[0]; ext->Qy = qrot[1]; ext->Qz = qrot[2]; ext->Qs = qrot[3]; } ext->CopyToVar(); if( bar!=NULL ) bar->NotUpToDate(); ext->m_PrevX = x; ext->m_PrevY = y; } } return true; } bool CQuaternionExt::MouseButtonCB(TwMouseButtonID button, bool pressed, int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp) { CQuaternionExt *ext = static_cast(structExtValue); if( ext==NULL ) return false; (void)clientData; (void)bar, (void)varGrp; if( button==TW_MOUSE_LEFT ) { if( pressed ) { ext->m_OrigQuat[0] = ext->Qx; ext->m_OrigQuat[1] = ext->Qy; ext->m_OrigQuat[2] = ext->Qz; ext->m_OrigQuat[3] = ext->Qs; ext->m_OrigX = QuatIX(mouseX, w, h); ext->m_OrigY = QuatIY(mouseY, w, h); ext->m_PrevX = ext->m_OrigX; ext->m_PrevY = ext->m_OrigY; ext->m_Rotating = true; } else ext->m_Rotating = false; } //printf("Click %x\n", structExtValue); return true; } void CQuaternionExt::MouseLeaveCB(void *structExtValue, void *clientData, TwBar *bar) { CQuaternionExt *ext = static_cast(structExtValue); if( ext==NULL ) return; (void)clientData; (void)bar; //printf("Leave %x\n", structExtValue); ext->m_Highlighted = false; ext->m_Rotating = false; } // --------------------------------------------------------------------------- // Convertion between VC++ Debug/Release std::string // (Needed because VC++ adds some extra info to std::string in Debug mode!) // --------------------------------------------------------------------------- CTwMgr::CClientStdString::CClientStdString() { memset(m_Data, 0, sizeof(m_Data)); } void CTwMgr::CClientStdString::FromLib(const char *libStr) { m_LibStr = libStr; // it is ok to have a local copy here memcpy(m_Data + sizeof(void *), &m_LibStr, sizeof(std::string)); } std::string& CTwMgr::CClientStdString::ToClient() { assert( g_TwMgr!=NULL ); if( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string)+sizeof(void *) ) return *(std::string *)(m_Data); else if( g_TwMgr->m_ClientStdStringStructSize+sizeof(void *)==sizeof(std::string) ) return *(std::string *)(m_Data + 2*sizeof(void *)); else { assert( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string) ); return *(std::string *)(m_Data + sizeof(void *)); } } CTwMgr::CLibStdString::CLibStdString() { memset(m_Data, 0, sizeof(m_Data)); } void CTwMgr::CLibStdString::FromClient(const std::string& clientStr) { assert( g_TwMgr!=NULL ); memcpy(m_Data + sizeof(void *), &clientStr, g_TwMgr->m_ClientStdStringStructSize); } std::string& CTwMgr::CLibStdString::ToLib() { assert( g_TwMgr!=NULL ); if( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string)+sizeof(void *) ) return *(std::string *)(m_Data + 2*sizeof(void *)); else if( g_TwMgr->m_ClientStdStringStructSize+sizeof(void *)==sizeof(std::string) ) return *(std::string *)(m_Data); else { assert( g_TwMgr->m_ClientStdStringStructSize==sizeof(std::string) ); return *(std::string *)(m_Data + sizeof(void *)); } } // --------------------------------------------------------------------------- // Management functions // --------------------------------------------------------------------------- static int TwCreateGraph(ETwGraphAPI _GraphAPI) { assert( g_TwMgr!=NULL && g_TwMgr->m_Graph==NULL ); switch( _GraphAPI ) { case TW_OPENGL: g_TwMgr->m_Graph = new CTwGraphOpenGL; break; /* WIP case TW_OPENGL_CORE: g_TwMgr->m_Graph = new CTwGraphOpenGLCore; break; */ case TW_DIRECT3D9: #ifdef ANT_WINDOWS if( g_TwMgr->m_Device!=NULL ) g_TwMgr->m_Graph = new CTwGraphDirect3D9; else { g_TwMgr->SetLastError(g_ErrBadDevice); return 0; } #endif // ANT_WINDOWS break; case TW_DIRECT3D10: #ifdef ANT_WINDOWS if( g_TwMgr->m_Device!=NULL ) g_TwMgr->m_Graph = new CTwGraphDirect3D10; else { g_TwMgr->SetLastError(g_ErrBadDevice); return 0; } #endif // ANT_WINDOWS break; case TW_DIRECT3D11: #ifdef ANT_WINDOWS if( g_TwMgr->m_Device!=NULL ) g_TwMgr->m_Graph = new CTwGraphDirect3D11; else { g_TwMgr->SetLastError(g_ErrBadDevice); return 0; } #endif // ANT_WINDOWS break; } if( g_TwMgr->m_Graph==NULL ) { g_TwMgr->SetLastError(g_ErrUnknownAPI); return 0; } else return g_TwMgr->m_Graph->Init(); } // --------------------------------------------------------------------------- static inline int TwFreeAsyncDrawing() { if( g_TwMgr && g_TwMgr->m_Graph && g_TwMgr->m_Graph->IsDrawing() ) { const double SLEEP_MAX = 0.25; // wait at most 1/4 second PerfTimer timer; while( g_TwMgr->m_Graph->IsDrawing() && timer.GetTime()m_Graph->IsDrawing() ) { g_TwMgr->SetLastError(g_ErrIsDrawing); return 0; } } return 1; } // --------------------------------------------------------------------------- /* static inline int TwFreeAsyncProcessing() { if( g_TwMgr && g_TwMgr->IsProcessing() ) { const double SLEEP_MAX = 0.25; // wait at most 1/4 second PerfTimer timer; while( g_TwMgr->IsProcessing() && timer.GetTime()IsProcessing() ) { g_TwMgr->SetLastError(g_ErrIsProcessing); return 0; } } return 1; } static inline int TwBeginProcessing() { if( !TwFreeAsyncProcessing() ) return 0; if( g_TwMgr ) g_TwMgr->SetProcessing(true); } static inline int TwEndProcessing() { if( g_TwMgr ) g_TwMgr->SetProcessing(false); } */ // --------------------------------------------------------------------------- static int TwInitMgr() { assert( g_TwMasterMgr!=NULL ); assert( g_TwMgr!=NULL ); g_TwMgr->m_CurrentFont = g_DefaultNormalFont; g_TwMgr->m_Graph = g_TwMasterMgr->m_Graph; g_TwMgr->m_KeyPressedTextObj = g_TwMgr->m_Graph->NewTextObj(); g_TwMgr->m_InfoTextObj = g_TwMgr->m_Graph->NewTextObj(); g_TwMgr->m_HelpBar = TwNewBar("TW_HELP"); if( g_TwMgr->m_HelpBar ) { g_TwMgr->m_HelpBar->m_Label = "~ Help & Shortcuts ~"; g_TwMgr->m_HelpBar->m_PosX = 32; g_TwMgr->m_HelpBar->m_PosY = 32; g_TwMgr->m_HelpBar->m_Width = 400; g_TwMgr->m_HelpBar->m_Height = 200; g_TwMgr->m_HelpBar->m_ValuesWidth = 12*(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2); g_TwMgr->m_HelpBar->m_Color = 0xa05f5f5f; //0xd75f5f5f; g_TwMgr->m_HelpBar->m_DarkText = false; g_TwMgr->m_HelpBar->m_IsHelpBar = true; g_TwMgr->Minimize(g_TwMgr->m_HelpBar); } else return 0; CColorExt::CreateTypes(); CQuaternionExt::CreateTypes(); return 1; } int ANT_CALL TwInit(ETwGraphAPI _GraphAPI, void *_Device) { #if defined(_DEBUG) && defined(ANT_WINDOWS) _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF)); #endif if( g_TwMasterMgr!=NULL ) { g_TwMasterMgr->SetLastError(g_ErrInit); return 0; } assert( g_TwMgr==0 ); assert( g_Wnds.empty() ); g_TwMasterMgr = new CTwMgr(_GraphAPI, _Device, TW_MASTER_WINDOW_ID); g_Wnds[TW_MASTER_WINDOW_ID] = g_TwMasterMgr; g_TwMgr = g_TwMasterMgr; TwGenerateDefaultFonts(); g_TwMgr->m_CurrentFont = g_DefaultNormalFont; int Res = TwCreateGraph(_GraphAPI); if( Res ) Res = TwInitMgr(); if( !Res ) TwTerminate(); return Res; } // --------------------------------------------------------------------------- int ANT_CALL TwSetLastError(const char *_StaticErrorMessage) { if( g_TwMasterMgr!=0 ) { g_TwMasterMgr->SetLastError(_StaticErrorMessage); return 1; } else return 0; } // --------------------------------------------------------------------------- int ANT_CALL TwTerminate() { if( g_TwMgr==NULL ) { //TwGlobalError(g_ErrShut); -> not an error return 0; // already shutdown } // For multi-thread safety if( !TwFreeAsyncDrawing() ) return 0; CTwWndMap::iterator it; for( it=g_Wnds.begin(); it!=g_Wnds.end(); it++ ) { g_TwMgr = it->second; g_TwMgr->m_Terminating = true; TwDeleteAllBars(); if( g_TwMgr->m_CursorsCreated ) g_TwMgr->FreeCursors(); if( g_TwMgr->m_Graph ) { if( g_TwMgr->m_KeyPressedTextObj ) { g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_KeyPressedTextObj); g_TwMgr->m_KeyPressedTextObj = NULL; } if( g_TwMgr->m_InfoTextObj ) { g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_InfoTextObj); g_TwMgr->m_InfoTextObj = NULL; } if (g_TwMgr != g_TwMasterMgr) g_TwMgr->m_Graph = NULL; } if (g_TwMgr != g_TwMasterMgr) { delete g_TwMgr; g_TwMgr = NULL; } } // delete g_TwMasterMgr int Res = 1; g_TwMgr = g_TwMasterMgr; if( g_TwMasterMgr->m_Graph ) { Res = g_TwMasterMgr->m_Graph->Shut(); delete g_TwMasterMgr->m_Graph; g_TwMasterMgr->m_Graph = NULL; } TwDeleteDefaultFonts(); delete g_TwMasterMgr; g_TwMasterMgr = NULL; g_TwMgr = NULL; g_Wnds.clear(); return Res; } // --------------------------------------------------------------------------- int ANT_CALL TwGetCurrentWindow() { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } return g_TwMgr->m_WndID; } int ANT_CALL TwSetCurrentWindow(int wndID) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if (wndID != g_TwMgr->m_WndID) { CTwWndMap::iterator foundWnd = g_Wnds.find(wndID); if (foundWnd == g_Wnds.end()) { // create a new CTwMgr g_TwMgr = new CTwMgr(g_TwMasterMgr->m_GraphAPI, g_TwMasterMgr->m_Device, wndID); g_Wnds[wndID] = g_TwMgr; return TwInitMgr(); } else { g_TwMgr = foundWnd->second; return 1; } } else return 1; } int ANT_CALL TwWindowExists(int wndID) { CTwWndMap::iterator foundWnd = g_Wnds.find(wndID); if (foundWnd == g_Wnds.end()) return 0; else return 1; } // --------------------------------------------------------------------------- int ANT_CALL TwDraw() { PERF( PerfTimer Timer; double DT; ) //CTwFPU fpu; // fpu precision only forced in update (do not modif dx draw calls) if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } assert(g_TwMgr->m_Bars.size()==g_TwMgr->m_Order.size()); // For multi-thread savety if( !TwFreeAsyncDrawing() ) return 0; // Create cursors #if defined(ANT_WINDOWS) || defined(ANT_OSX) if( !g_TwMgr->m_CursorsCreated ) g_TwMgr->CreateCursors(); #elif defined(ANT_UNIX) if( !g_TwMgr->m_CurrentXDisplay ) g_TwMgr->m_CurrentXDisplay = glXGetCurrentDisplay(); if( !g_TwMgr->m_CurrentXWindow ) g_TwMgr->m_CurrentXWindow = glXGetCurrentDrawable(); if( g_TwMgr->m_CurrentXDisplay && !g_TwMgr->m_CursorsCreated ) g_TwMgr->CreateCursors(); #endif // Autorepeat TW_MOUSE_PRESSED double CurrTime = g_TwMgr->m_Timer.GetTime(); double RepeatDT = CurrTime - g_TwMgr->m_LastMousePressedTime; double DrawDT = CurrTime - g_TwMgr->m_LastDrawTime; if( RepeatDT>2.0*g_TwMgr->m_RepeatMousePressedDelay || DrawDT>2.0*g_TwMgr->m_RepeatMousePressedDelay || abs(g_TwMgr->m_LastMousePressedPosition[0]-g_TwMgr->m_LastMouseX)>4 || abs(g_TwMgr->m_LastMousePressedPosition[1]-g_TwMgr->m_LastMouseY)>4 ) { g_TwMgr->m_CanRepeatMousePressed = false; g_TwMgr->m_IsRepeatingMousePressed = false; } if( g_TwMgr->m_CanRepeatMousePressed ) { if( (!g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedDelay) || (g_TwMgr->m_IsRepeatingMousePressed && RepeatDT>g_TwMgr->m_RepeatMousePressedPeriod) ) { g_TwMgr->m_IsRepeatingMousePressed = true; g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime(); TwMouseButton(TW_MOUSE_PRESSED, g_TwMgr->m_LastMousePressedButtonID); } } g_TwMgr->m_LastDrawTime = CurrTime; if( g_TwMgr->m_WndWidth<0 || g_TwMgr->m_WndHeight<0 ) { g_TwMgr->SetLastError(g_ErrBadSize); return 0; } else if( g_TwMgr->m_WndWidth==0 || g_TwMgr->m_WndHeight==0 ) // probably iconified return 1; // nothing to do // count number of bars to draw size_t i, j; int Nb = 0; for( i=0; im_Bars.size(); ++i ) if( g_TwMgr->m_Bars[i]!=NULL && g_TwMgr->m_Bars[i]->m_Visible ) ++Nb; if( Nb>0 ) { PERF( Timer.Reset(); ) g_TwMgr->m_Graph->BeginDraw(g_TwMgr->m_WndWidth, g_TwMgr->m_WndHeight); PERF( DT = Timer.GetTime(); printf("\nBegin=%.4fms ", 1000.0*DT); ) PERF( Timer.Reset(); ) vector TopBarsRects, ClippedBarRects; for( i=0; im_Bars.size(); ++i ) { CTwBar *Bar = g_TwMgr->m_Bars[ g_TwMgr->m_Order[i] ]; if( Bar->m_Visible ) { if( g_TwMgr->m_OverlapContent || Bar->IsMinimized() ) Bar->Draw(); else { // Clip overlapped transparent bars to make them more readable const int Margin = 4; CRect BarRect(Bar->m_PosX - Margin, Bar->m_PosY - Margin, Bar->m_Width + 2*Margin, Bar->m_Height + 2*Margin); TopBarsRects.clear(); for( j=i+1; jm_Bars.size(); ++j ) { CTwBar *TopBar = g_TwMgr->m_Bars[g_TwMgr->m_Order[j]]; if( TopBar->m_Visible && !TopBar->IsMinimized() ) TopBarsRects.push_back(CRect(TopBar->m_PosX, TopBar->m_PosY, TopBar->m_Width, TopBar->m_Height)); } ClippedBarRects.clear(); BarRect.Subtract(TopBarsRects, ClippedBarRects); if( ClippedBarRects.size()==1 && ClippedBarRects[0]==BarRect ) //g_TwMgr->m_Graph->DrawRect(Bar->m_PosX, Bar->m_PosY, Bar->m_PosX+Bar->m_Width-1, Bar->m_PosY+Bar->m_Height-1, 0x70ffffff); // Clipping test Bar->Draw(); // unclipped else { Bar->Draw(CTwBar::DRAW_BG); // draw background only // draw content for each clipped rectangle for( j=0; j1 && ClippedBarRects[j].H>1) { g_TwMgr->m_Graph->SetScissor(ClippedBarRects[j].X+1, ClippedBarRects[j].Y, ClippedBarRects[j].W, ClippedBarRects[j].H-1); //g_TwMgr->m_Graph->DrawRect(0, 0, 1000, 1000, 0x70ffffff); // Clipping test Bar->Draw(CTwBar::DRAW_CONTENT); } g_TwMgr->m_Graph->SetScissor(0, 0, 0, 0); } } } } PERF( DT = Timer.GetTime(); printf("Draw=%.4fms ", 1000.0*DT); ) PERF( Timer.Reset(); ) g_TwMgr->m_Graph->EndDraw(); PERF( DT = Timer.GetTime(); printf("End=%.4fms\n", 1000.0*DT); ) } return 1; } // --------------------------------------------------------------------------- int ANT_CALL TwWindowSize(int _Width, int _Height) { g_InitWndWidth = _Width; g_InitWndHeight = _Height; if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL ) { //TwGlobalError(g_ErrNotInit); -> not an error here return 0; // not initialized } if( _Width<0 || _Height<0 ) { g_TwMgr->SetLastError(g_ErrBadSize); return 0; } // For multi-thread savety if( !TwFreeAsyncDrawing() ) return 0; // Delete the extra text objects if( g_TwMgr->m_KeyPressedTextObj ) { g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_KeyPressedTextObj); g_TwMgr->m_KeyPressedTextObj = NULL; } if( g_TwMgr->m_InfoTextObj ) { g_TwMgr->m_Graph->DeleteTextObj(g_TwMgr->m_InfoTextObj); g_TwMgr->m_InfoTextObj = NULL; } g_TwMgr->m_WndWidth = _Width; g_TwMgr->m_WndHeight = _Height; g_TwMgr->m_Graph->Restore(); // Recreate extra text objects if( g_TwMgr->m_WndWidth!=0 && g_TwMgr->m_WndHeight!=0 ) { if( g_TwMgr->m_KeyPressedTextObj==NULL ) { g_TwMgr->m_KeyPressedTextObj = g_TwMgr->m_Graph->NewTextObj(); g_TwMgr->m_KeyPressedBuildText = true; } if( g_TwMgr->m_InfoTextObj==NULL ) { g_TwMgr->m_InfoTextObj = g_TwMgr->m_Graph->NewTextObj(); g_TwMgr->m_InfoBuildText = true; } } for( std::vector::iterator it=g_TwMgr->m_Bars.begin(); it!=g_TwMgr->m_Bars.end(); ++it ) (*it)->NotUpToDate(); return 1; } // --------------------------------------------------------------------------- CTwMgr::CTwMgr(ETwGraphAPI _GraphAPI, void *_Device, int _WndID) { m_GraphAPI = _GraphAPI; m_Device = _Device; m_WndID = _WndID; m_LastError = NULL; m_CurrentDbgFile = ""; m_CurrentDbgLine = 0; //m_Processing = false; m_Graph = NULL; m_WndWidth = g_InitWndWidth; m_WndHeight = g_InitWndHeight; m_CurrentFont = NULL; // set after by TwIntialize m_NbMinimizedBars = 0; m_HelpBar = NULL; m_HelpBarNotUpToDate = true; m_HelpBarUpdateNow = false; m_LastHelpUpdateTime = 0; m_LastMouseX = -1; m_LastMouseY = -1; m_LastMouseWheelPos = 0; m_IconPos = 0; m_IconAlign = 0; m_IconMarginX = m_IconMarginY = 8; m_FontResizable = true; m_KeyPressedTextObj = NULL; m_KeyPressedBuildText = false; m_KeyPressedTime = 0; m_InfoTextObj = NULL; m_InfoBuildText = true; m_BarInitColorHue = 155; m_PopupBar = NULL; m_TypeColor32 = TW_TYPE_UNDEF; m_TypeColor3F = TW_TYPE_UNDEF; m_TypeColor4F = TW_TYPE_UNDEF; m_LastMousePressedTime = 0; m_LastMousePressedButtonID = TW_MOUSE_MIDDLE; m_LastMousePressedPosition[0] = -1000; m_LastMousePressedPosition[1] = -1000; m_RepeatMousePressedDelay = 0.5; m_RepeatMousePressedPeriod = 0.1; m_CanRepeatMousePressed = false; m_IsRepeatingMousePressed = false; m_LastDrawTime = 0; m_UseOldColorScheme = false; m_Contained = false; m_ButtonAlign = BUTTON_ALIGN_RIGHT; m_OverlapContent = false; m_Terminating = false; m_CursorsCreated = false; #if defined(ANT_UNIX) m_CurrentXDisplay = NULL; m_CurrentXWindow = 0; #endif // defined(ANT_UNIX) m_CopyCDStringToClient = g_InitCopyCDStringToClient; m_CopyStdStringToClient = g_InitCopyStdStringToClient; m_ClientStdStringStructSize = 0; } // --------------------------------------------------------------------------- CTwMgr::~CTwMgr() { } // --------------------------------------------------------------------------- int CTwMgr::FindBar(const char *_Name) const { if( _Name==NULL || strlen(_Name)<=0 ) return -1; int i; for( i=0; i<(int)m_Bars.size(); ++i ) if( m_Bars[i]!=NULL && strcmp(_Name, m_Bars[i]->m_Name.c_str())==0 ) return i; return -1; } // --------------------------------------------------------------------------- int CTwMgr::HasAttrib(const char *_Attrib, bool *_HasValue) const { *_HasValue = true; if( _stricmp(_Attrib, "help")==0 ) return MGR_HELP; else if( _stricmp(_Attrib, "fontsize")==0 ) return MGR_FONT_SIZE; else if( _stricmp(_Attrib, "iconpos")==0 ) return MGR_ICON_POS; else if( _stricmp(_Attrib, "iconalign")==0 ) return MGR_ICON_ALIGN; else if( _stricmp(_Attrib, "iconmargin")==0 ) return MGR_ICON_MARGIN; else if( _stricmp(_Attrib, "fontresizable")==0 ) return MGR_FONT_RESIZABLE; else if( _stricmp(_Attrib, "colorscheme")==0 ) return MGR_COLOR_SCHEME; else if( _stricmp(_Attrib, "contained")==0 ) return MGR_CONTAINED; else if( _stricmp(_Attrib, "buttonalign")==0 ) return MGR_BUTTON_ALIGN; else if( _stricmp(_Attrib, "overlap")==0 ) return MGR_OVERLAP; *_HasValue = false; return 0; // not found } int CTwMgr::SetAttrib(int _AttribID, const char *_Value) { switch( _AttribID ) { case MGR_HELP: if( _Value && strlen(_Value)>0 ) { m_Help = _Value; m_HelpBarNotUpToDate = true; return 1; } else { SetLastError(g_ErrNoValue); return 0; } case MGR_FONT_SIZE: if( _Value && strlen(_Value)>0 ) { int s; int n = sscanf(_Value, "%d", &s); if( n==1 && s>=1 && s<=3 ) { if( s==1 ) SetFont(g_DefaultSmallFont, true); else if( s==2 ) SetFont(g_DefaultNormalFont, true); else if( s==3 ) SetFont(g_DefaultLargeFont, true); return 1; } else { SetLastError(g_ErrBadValue); return 0; } } else { SetLastError(g_ErrNoValue); return 0; } case MGR_ICON_POS: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "bl")==0 || _stricmp(_Value, "lb")==0 || _stricmp(_Value, "bottomleft")==0 || _stricmp(_Value, "leftbottom")==0 ) { m_IconPos = 0; return 1; } else if( _stricmp(_Value, "br")==0 || _stricmp(_Value, "rb")==0 || _stricmp(_Value, "bottomright")==0 || _stricmp(_Value, "rightbottom")==0 ) { m_IconPos = 1; return 1; } else if( _stricmp(_Value, "tl")==0 || _stricmp(_Value, "lt")==0 || _stricmp(_Value, "topleft")==0 || _stricmp(_Value, "lefttop")==0 ) { m_IconPos = 2; return 1; } else if( _stricmp(_Value, "tr")==0 || _stricmp(_Value, "rt")==0 || _stricmp(_Value, "topright")==0 || _stricmp(_Value, "righttop")==0 ) { m_IconPos = 3; return 1; } else { SetLastError(g_ErrBadValue); return 0; } } else { SetLastError(g_ErrNoValue); return 0; } case MGR_ICON_ALIGN: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "vert")==0 || _stricmp(_Value, "vertical")==0 ) { m_IconAlign = 0; return 1; } else if( _stricmp(_Value, "horiz")==0 || _stricmp(_Value, "horizontal")==0 ) { m_IconAlign = 1; return 1; } else { SetLastError(g_ErrBadValue); return 0; } } else { SetLastError(g_ErrNoValue); return 0; } case MGR_ICON_MARGIN: if( _Value && strlen(_Value)>0 ) { int x, y; int n = sscanf(_Value, "%d%d", &x, &y); if( n==2 && x>=0 && y>=0 ) { m_IconMarginX = x; m_IconMarginY = y; return 1; } else { SetLastError(g_ErrBadValue); return 0; } } else { SetLastError(g_ErrNoValue); return 0; } case MGR_FONT_RESIZABLE: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { m_FontResizable = true; return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { m_FontResizable = false; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case MGR_COLOR_SCHEME: if( _Value && strlen(_Value)>0 ) { int s; int n = sscanf(_Value, "%d", &s); if( n==1 && s>=0 && s<=1 ) { if( s==0 ) m_UseOldColorScheme = true; else m_UseOldColorScheme = false; return 1; } else { SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case MGR_CONTAINED: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) m_Contained = true; else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) m_Contained = false; else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } vector::iterator barIt; for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt ) if( (*barIt)!=NULL ) (*barIt)->m_Contained = m_Contained; return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case MGR_BUTTON_ALIGN: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "left")==0 ) m_ButtonAlign = BUTTON_ALIGN_LEFT; else if( _stricmp(_Value, "center")==0 ) m_ButtonAlign = BUTTON_ALIGN_CENTER; else if( _stricmp(_Value, "right")==0 ) m_ButtonAlign = BUTTON_ALIGN_RIGHT; else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } vector::iterator barIt; for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt ) if( (*barIt)!=NULL ) (*barIt)->m_ButtonAlign = m_ButtonAlign; return 1; } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } case MGR_OVERLAP: if( _Value && strlen(_Value)>0 ) { if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 ) { m_OverlapContent = true; return 1; } else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 ) { m_OverlapContent = false; return 1; } else { g_TwMgr->SetLastError(g_ErrBadValue); return 0; } } else { g_TwMgr->SetLastError(g_ErrNoValue); return 0; } default: g_TwMgr->SetLastError(g_ErrUnknownAttrib); return 0; } } ERetType CTwMgr::GetAttrib(int _AttribID, std::vector& outDoubles, std::ostringstream& outString) const { outDoubles.clear(); outString.clear(); switch( _AttribID ) { case MGR_HELP: outString << m_Help; return RET_STRING; case MGR_FONT_SIZE: if( m_CurrentFont==g_DefaultSmallFont ) outDoubles.push_back(1); else if( m_CurrentFont==g_DefaultNormalFont ) outDoubles.push_back(2); else if( m_CurrentFont==g_DefaultLargeFont ) outDoubles.push_back(3); else outDoubles.push_back(0); // should not happened return RET_DOUBLE; case MGR_ICON_POS: if( m_IconPos==0 ) outString << "bottomleft"; else if( m_IconPos==1 ) outString << "bottomright"; else if( m_IconPos==2 ) outString << "topleft"; else if( m_IconPos==3 ) outString << "topright"; else outString << "undefined"; // should not happened return RET_STRING; case MGR_ICON_ALIGN: if( m_IconAlign==0 ) outString << "vertical"; else if( m_IconAlign==1 ) outString << "horizontal"; else outString << "undefined"; // should not happened return RET_STRING; case MGR_ICON_MARGIN: outDoubles.push_back(m_IconMarginX); outDoubles.push_back(m_IconMarginY); return RET_DOUBLE; case MGR_FONT_RESIZABLE: outDoubles.push_back(m_FontResizable); return RET_DOUBLE; case MGR_COLOR_SCHEME: outDoubles.push_back(m_UseOldColorScheme ? 0 : 1); return RET_DOUBLE; case MGR_CONTAINED: { bool contained = m_Contained; /* if( contained ) { vector::iterator barIt; for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt ) if( (*barIt)!=NULL && !(*barIt)->m_Contained ) { contained = false; break; } } */ outDoubles.push_back(contained); return RET_DOUBLE; } case MGR_BUTTON_ALIGN: if( m_ButtonAlign==BUTTON_ALIGN_LEFT ) outString << "left"; else if( m_ButtonAlign==BUTTON_ALIGN_CENTER ) outString << "center"; else outString << "right"; return RET_STRING; case MGR_OVERLAP: outDoubles.push_back(m_OverlapContent); return RET_DOUBLE; default: g_TwMgr->SetLastError(g_ErrUnknownAttrib); return RET_ERROR; } } // --------------------------------------------------------------------------- void CTwMgr::Minimize(TwBar *_Bar) { assert(m_Graph!=NULL && _Bar!=NULL); assert(m_Bars.size()==m_MinOccupied.size()); if( _Bar->m_IsMinimized ) return; if( _Bar->m_Visible ) { size_t i = m_NbMinimizedBars; m_NbMinimizedBars++; for( i=0; im_MinNumber = (int)i; } else _Bar->m_MinNumber = -1; _Bar->m_IsMinimized = true; _Bar->NotUpToDate(); } // --------------------------------------------------------------------------- void CTwMgr::Maximize(TwBar *_Bar) { assert(m_Graph!=NULL && _Bar!=NULL); assert(m_Bars.size()==m_MinOccupied.size()); if( !_Bar->m_IsMinimized ) return; if( _Bar->m_Visible ) { --m_NbMinimizedBars; if( m_NbMinimizedBars<0 ) m_NbMinimizedBars = 0; if( _Bar->m_MinNumber>=0 && _Bar->m_MinNumber<(int)m_MinOccupied.size() ) m_MinOccupied[_Bar->m_MinNumber] = false; } _Bar->m_IsMinimized = false; _Bar->NotUpToDate(); if( _Bar->m_IsHelpBar ) m_HelpBarNotUpToDate = true; } // --------------------------------------------------------------------------- void CTwMgr::Hide(TwBar *_Bar) { assert(m_Graph!=NULL && _Bar!=NULL); if( !_Bar->m_Visible ) return; if( _Bar->IsMinimized() ) { Maximize(_Bar); _Bar->m_Visible = false; Minimize(_Bar); } else _Bar->m_Visible = false; if( !_Bar->m_IsHelpBar ) m_HelpBarNotUpToDate = true; } // --------------------------------------------------------------------------- void CTwMgr::Unhide(TwBar *_Bar) { assert(m_Graph!=NULL && _Bar!=NULL); if( _Bar->m_Visible ) return; if( _Bar->IsMinimized() ) { Maximize(_Bar); _Bar->m_Visible = true; Minimize(_Bar); } else _Bar->m_Visible = true; _Bar->NotUpToDate(); if( !_Bar->m_IsHelpBar ) m_HelpBarNotUpToDate = true; } // --------------------------------------------------------------------------- void CTwMgr::SetFont(const CTexFont *_Font, bool _ResizeBars) { assert(m_Graph!=NULL); assert(_Font!=NULL); m_CurrentFont = _Font; for( int i=0; i<(int)m_Bars.size(); ++i ) if( m_Bars[i]!=NULL ) { int fh = m_Bars[i]->m_Font->m_CharHeight; m_Bars[i]->m_Font = _Font; if( _ResizeBars ) { if( m_Bars[i]->m_Movable ) { m_Bars[i]->m_PosX += (3*(fh-_Font->m_CharHeight))/2; m_Bars[i]->m_PosY += (fh-_Font->m_CharHeight)/2; } if( m_Bars[i]->m_Resizable ) { m_Bars[i]->m_Width = (m_Bars[i]->m_Width*_Font->m_CharHeight)/fh; m_Bars[i]->m_Height = (m_Bars[i]->m_Height*_Font->m_CharHeight)/fh; m_Bars[i]->m_ValuesWidth = (m_Bars[i]->m_ValuesWidth*_Font->m_CharHeight)/fh; } } m_Bars[i]->NotUpToDate(); } if( g_TwMgr->m_HelpBar!=NULL ) g_TwMgr->m_HelpBar->Update(); g_TwMgr->m_InfoBuildText = true; g_TwMgr->m_KeyPressedBuildText = true; m_HelpBarNotUpToDate = true; } // --------------------------------------------------------------------------- void ANT_CALL TwGlobalError(const char *_ErrorMessage) // to be called when g_TwMasterMgr is not created { if( g_ErrorHandler==NULL ) { fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", _ErrorMessage); #ifdef ANT_WINDOWS OutputDebugString("ERROR(AntTweakBar) >> "); OutputDebugString(_ErrorMessage); OutputDebugString("\n"); #endif // ANT_WINDOWS } else g_ErrorHandler(_ErrorMessage); if( g_BreakOnError ) abort(); } // --------------------------------------------------------------------------- void CTwMgr::SetLastError(const char *_ErrorMessage) // _ErrorMessage must be a static string { if (this != g_TwMasterMgr) { // route to master g_TwMasterMgr->SetLastError(_ErrorMessage); return; } m_LastError = _ErrorMessage; if( g_ErrorHandler==NULL ) { if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 ) fprintf(stderr, "%s(%d): ", m_CurrentDbgFile, m_CurrentDbgLine); fprintf(stderr, "ERROR(AntTweakBar) >> %s\n", m_LastError); #ifdef ANT_WINDOWS if( m_CurrentDbgFile!=NULL && strlen(m_CurrentDbgFile)>0 && m_CurrentDbgLine>0 ) { OutputDebugString(m_CurrentDbgFile); char sl[32]; sprintf(sl, "(%d): ", m_CurrentDbgLine); OutputDebugString(sl); } OutputDebugString("ERROR(AntTweakBar) >> "); OutputDebugString(m_LastError); OutputDebugString("\n"); #endif // ANT_WINDOWS } else g_ErrorHandler(_ErrorMessage); if( g_BreakOnError ) abort(); } // --------------------------------------------------------------------------- const char *CTwMgr::GetLastError() { if (this != g_TwMasterMgr) { // route to master return g_TwMasterMgr->GetLastError(); } const char *Err = m_LastError; m_LastError = NULL; return Err; } // --------------------------------------------------------------------------- const char *CTwMgr::CheckLastError() const { return m_LastError; } // --------------------------------------------------------------------------- void CTwMgr::SetCurrentDbgParams(const char *dbgFile, int dbgLine) { m_CurrentDbgFile = dbgFile; m_CurrentDbgLine = dbgLine; } // --------------------------------------------------------------------------- int ANT_CALL __TwDbg(const char *dbgFile, int dbgLine) { if( g_TwMgr!=NULL ) g_TwMgr->SetCurrentDbgParams(dbgFile, dbgLine); return 0; // always returns zero } // --------------------------------------------------------------------------- void ANT_CALL TwHandleErrors(TwErrorHandler _ErrorHandler, int _BreakOnError) { g_ErrorHandler = _ErrorHandler; g_BreakOnError = (_BreakOnError) ? true : false; } void ANT_CALL TwHandleErrors(TwErrorHandler _ErrorHandler) { TwHandleErrors(_ErrorHandler, false); } // --------------------------------------------------------------------------- const char *ANT_CALL TwGetLastError() { if( g_TwMasterMgr==NULL ) { TwGlobalError(g_ErrNotInit); return g_ErrNotInit; } else return g_TwMasterMgr->GetLastError(); } // --------------------------------------------------------------------------- TwBar *ANT_CALL TwNewBar(const char *_Name) { if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL ) { TwGlobalError(g_ErrNotInit); return NULL; // not initialized } TwFreeAsyncDrawing(); // For multi-thread savety if( _Name==NULL || strlen(_Name)<=0 ) { g_TwMgr->SetLastError(g_ErrBadParam); return NULL; } if( g_TwMgr->FindBar(_Name)>=0 ) { g_TwMgr->SetLastError(g_ErrExist); return NULL; } if( strstr(_Name, "`")!=NULL ) { g_TwMgr->SetLastError(g_ErrNoBackQuote); return NULL; } if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar if it exists { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } TwBar *Bar = new CTwBar(_Name); g_TwMgr->m_Bars.push_back(Bar); g_TwMgr->m_Order.push_back((int)g_TwMgr->m_Bars.size()-1); g_TwMgr->m_MinOccupied.push_back(false); g_TwMgr->m_HelpBarNotUpToDate = true; return Bar; } // --------------------------------------------------------------------------- int ANT_CALL TwDeleteBar(TwBar *_Bar) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( _Bar==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } if( _Bar==g_TwMgr->m_HelpBar ) { g_TwMgr->SetLastError(g_ErrDelHelp); return 0; } TwFreeAsyncDrawing(); // For multi-thread savety vector::iterator BarIt; int i = 0; for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i ) if( (*BarIt)==_Bar ) break; if( BarIt==g_TwMgr->m_Bars.end() ) { g_TwMgr->SetLastError(g_ErrNotFound); return 0; } if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) // delete popup bar first if it exists { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } // force bar to un-minimize g_TwMgr->Maximize(_Bar); // find an empty MinOccupied vector::iterator itm; int j = 0; for( itm=g_TwMgr->m_MinOccupied.begin(); itm!=g_TwMgr->m_MinOccupied.end(); ++itm, ++j) if( (*itm)==false ) break; assert( itm!=g_TwMgr->m_MinOccupied.end() ); // shift MinNumbers and erase the empty MinOccupied for( size_t k=0; km_Bars.size(); ++k ) if( g_TwMgr->m_Bars[k]!=NULL && g_TwMgr->m_Bars[k]->m_MinNumber>j ) g_TwMgr->m_Bars[k]->m_MinNumber -= 1; g_TwMgr->m_MinOccupied.erase(itm); // erase _Bar order vector::iterator BarOrderIt = g_TwMgr->m_Order.end(); for(vector::iterator it=g_TwMgr->m_Order.begin(); it!=g_TwMgr->m_Order.end(); ++it ) if( (*it)==i ) BarOrderIt = it; else if( (*it)>i ) (*it) -= 1; assert( BarOrderIt!=g_TwMgr->m_Order.end() ); g_TwMgr->m_Order.erase(BarOrderIt); // erase & delete _Bar g_TwMgr->m_Bars.erase(BarIt); delete _Bar; g_TwMgr->m_HelpBarNotUpToDate = true; return 1; } // --------------------------------------------------------------------------- int ANT_CALL TwDeleteAllBars() { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } TwFreeAsyncDrawing(); // For multi-thread savety int n = 0; if( g_TwMgr->m_Terminating || g_TwMgr->m_HelpBar==NULL ) { for( size_t i=0; im_Bars.size(); ++i ) if( g_TwMgr->m_Bars[i]!=NULL ) { ++n; delete g_TwMgr->m_Bars[i]; g_TwMgr->m_Bars[i] = NULL; } g_TwMgr->m_Bars.clear(); g_TwMgr->m_Order.clear(); g_TwMgr->m_MinOccupied.clear(); g_TwMgr->m_HelpBarNotUpToDate = true; } else { vector bars = g_TwMgr->m_Bars; for( size_t i = 0; i < bars.size(); ++i ) if( bars[i]!=0 && bars[i]!=g_TwMgr->m_HelpBar) { ++n; TwDeleteBar(bars[i]); } g_TwMgr->m_HelpBarNotUpToDate = true; } if( n==0 ) { g_TwMgr->SetLastError(g_ErrNthToDo); return 0; } else return 1; } // --------------------------------------------------------------------------- int ANT_CALL TwSetTopBar(const TwBar *_Bar) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( _Bar==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } TwFreeAsyncDrawing(); // For multi-thread savety if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnBottom.length()>0 ) { if( strcmp(_Bar->m_Name.c_str(), g_TwMgr->m_BarAlwaysOnBottom.c_str())==0 ) return TwSetBottomBar(_Bar); } int i = -1, iOrder; for( iOrder=0; iOrder<(int)g_TwMgr->m_Bars.size(); ++iOrder ) { i = g_TwMgr->m_Order[iOrder]; assert( i>=0 && i<(int)g_TwMgr->m_Bars.size() ); if( g_TwMgr->m_Bars[i]==_Bar ) break; } if( i<0 || iOrder>=(int)g_TwMgr->m_Bars.size() ) // bar not found { g_TwMgr->SetLastError(g_ErrNotFound); return 0; } for( int j=iOrder; j<(int)g_TwMgr->m_Bars.size()-1; ++j ) g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1]; g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = i; if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnTop.length()>0 ) { int topIdx = g_TwMgr->FindBar(g_TwMgr->m_BarAlwaysOnTop.c_str()); TwBar *top = (topIdx>=0 && topIdx<(int)g_TwMgr->m_Bars.size()) ? g_TwMgr->m_Bars[topIdx] : NULL; if( top!=NULL && top!=_Bar ) TwSetTopBar(top); } if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) TwSetTopBar(g_TwMgr->m_PopupBar); return 1; } // --------------------------------------------------------------------------- TwBar * ANT_CALL TwGetTopBar() { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return NULL; // not initialized } if( g_TwMgr->m_Bars.size()>0 && g_TwMgr->m_PopupBar==NULL ) return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-1 ]]; else if( g_TwMgr->m_Bars.size()>1 && g_TwMgr->m_PopupBar!=NULL ) return g_TwMgr->m_Bars[g_TwMgr->m_Order[ g_TwMgr->m_Bars.size()-2 ]]; else return NULL; } // --------------------------------------------------------------------------- int ANT_CALL TwSetBottomBar(const TwBar *_Bar) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( _Bar==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } TwFreeAsyncDrawing(); // For multi-thread savety if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnTop.length()>0 ) { if( strcmp(_Bar->m_Name.c_str(), g_TwMgr->m_BarAlwaysOnTop.c_str())==0 ) return TwSetTopBar(_Bar); } int i = -1, iOrder; for( iOrder=0; iOrder<(int)g_TwMgr->m_Bars.size(); ++iOrder ) { i = g_TwMgr->m_Order[iOrder]; assert( i>=0 && i<(int)g_TwMgr->m_Bars.size() ); if( g_TwMgr->m_Bars[i]==_Bar ) break; } if( i<0 || iOrder>=(int)g_TwMgr->m_Bars.size() ) // bar not found { g_TwMgr->SetLastError(g_ErrNotFound); return 0; } if( iOrder>0 ) for( int j=iOrder-1; j>=0; --j ) g_TwMgr->m_Order[j+1] = g_TwMgr->m_Order[j]; g_TwMgr->m_Order[0] = i; if( _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_BarAlwaysOnBottom.length()>0 ) { int btmIdx = g_TwMgr->FindBar(g_TwMgr->m_BarAlwaysOnBottom.c_str()); TwBar *btm = (btmIdx>=0 && btmIdx<(int)g_TwMgr->m_Bars.size()) ? g_TwMgr->m_Bars[btmIdx] : NULL; if( btm!=NULL && btm!=_Bar ) TwSetBottomBar(btm); } return 1; } // --------------------------------------------------------------------------- TwBar* ANT_CALL TwGetBottomBar() { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return NULL; // not initialized } if( g_TwMgr->m_Bars.size()>0 ) return g_TwMgr->m_Bars[g_TwMgr->m_Order[0]]; else return NULL; } // --------------------------------------------------------------------------- int ANT_CALL TwSetBarState(TwBar *_Bar, TwState _State) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( _Bar==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } TwFreeAsyncDrawing(); // For multi-thread savety switch( _State ) { case TW_STATE_SHOWN: g_TwMgr->Unhide(_Bar); return 1; case TW_STATE_ICONIFIED: //g_TwMgr->Unhide(_Bar); g_TwMgr->Minimize(_Bar); return 1; case TW_STATE_HIDDEN: //g_TwMgr->Maximize(_Bar); g_TwMgr->Hide(_Bar); return 1; case TW_STATE_UNICONIFIED: //g_TwMgr->Unhide(_Bar); g_TwMgr->Maximize(_Bar); return 1; default: g_TwMgr->SetLastError(g_ErrBadParam); return 0; } } // --------------------------------------------------------------------------- /* TwState ANT_CALL TwGetBarState(const TwBar *_Bar) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return TW_STATE_ERROR; // not initialized } if( _Bar==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return TW_STATE_ERROR; } if( !_Bar->m_Visible ) return TW_STATE_HIDDEN; else if( _Bar->IsMinimized() ) return TW_STATE_ICONIFIED; else return TW_STATE_SHOWN; } */ // --------------------------------------------------------------------------- const char * ANT_CALL TwGetBarName(TwBar *_Bar) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return NULL; // not initialized } if( _Bar==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return NULL; } vector::iterator BarIt; int i = 0; for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i ) if( (*BarIt)==_Bar ) break; if( BarIt==g_TwMgr->m_Bars.end() ) { g_TwMgr->SetLastError(g_ErrNotFound); return NULL; } return _Bar->m_Name.c_str(); } // --------------------------------------------------------------------------- int ANT_CALL TwGetBarCount() { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } return (int)g_TwMgr->m_Bars.size(); } // --------------------------------------------------------------------------- TwBar * ANT_CALL TwGetBarByIndex(int index) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return NULL; // not initialized } if( index>=0 && index<(int)g_TwMgr->m_Bars.size() ) return g_TwMgr->m_Bars[index]; else { g_TwMgr->SetLastError(g_ErrOutOfRange); return NULL; } } // --------------------------------------------------------------------------- TwBar * ANT_CALL TwGetBarByName(const char *name) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return NULL; // not initialized } int idx = g_TwMgr->FindBar(name); if ( idx>=0 && idx<(int)g_TwMgr->m_Bars.size() ) return g_TwMgr->m_Bars[idx]; else return NULL; } // --------------------------------------------------------------------------- int ANT_CALL TwRefreshBar(TwBar *bar) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( bar==NULL ) { vector::iterator BarIt; for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt ) if( *BarIt!=NULL ) (*BarIt)->NotUpToDate(); } else { vector::iterator BarIt; int i = 0; for( BarIt=g_TwMgr->m_Bars.begin(); BarIt!=g_TwMgr->m_Bars.end(); ++BarIt, ++i ) if( (*BarIt)==bar ) break; if( BarIt==g_TwMgr->m_Bars.end() ) { g_TwMgr->SetLastError(g_ErrNotFound); return 0; } bar->NotUpToDate(); } return 1; } // --------------------------------------------------------------------------- int BarVarHasAttrib(CTwBar *_Bar, CTwVar *_Var, const char *_Attrib, bool *_HasValue); int BarVarSetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, const char *_Value); ERetType BarVarGetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, std::vector& outDouble, std::ostringstream& outString); int ANT_CALL TwGetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int outValueMaxCount, void *outValues) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( paramName==NULL || strlen(paramName)<=0 ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } if( outValueMaxCount<=0 || outValues==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } if( bar==NULL ) bar = TW_GLOBAL_BAR; else { vector::iterator barIt; int i = 0; for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt, ++i ) if( (*barIt)==bar ) break; if( barIt==g_TwMgr->m_Bars.end() ) { g_TwMgr->SetLastError(g_ErrNotFound); return 0; } } CTwVarGroup *varParent = NULL; int varIndex = -1; CTwVar *var = NULL; if( varName!=NULL && strlen(varName)>0 ) { var = bar->Find(varName, &varParent, &varIndex); if( var==NULL ) { _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown var '%s/%s'", (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), varName); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } } bool hasValue = false; int paramID = BarVarHasAttrib(bar, var, paramName, &hasValue); if( paramID>0 ) { std::ostringstream valStr; std::vector valDbl; const char *PrevLastErrorPtr = g_TwMgr->CheckLastError(); ERetType retType = BarVarGetAttrib(bar, var, varParent, varIndex, paramID, valDbl, valStr); unsigned int i, valDblCount = (unsigned int)valDbl.size(); if( valDblCount > outValueMaxCount ) valDblCount = outValueMaxCount; if( retType==RET_DOUBLE && valDblCount==0 ) { g_TwMgr->SetLastError(g_ErrHasNoValue); retType = RET_ERROR; } if( retType==RET_DOUBLE ) { switch( paramValueType ) { case TW_PARAM_INT32: for( i=0; i(outValues))[i] = (int)valDbl[i]; return valDblCount; case TW_PARAM_FLOAT: for( i=0; i(outValues))[i] = (float)valDbl[i]; return valDblCount; case TW_PARAM_DOUBLE: for( i=0; i(outValues))[i] = valDbl[i]; return valDblCount; case TW_PARAM_CSTRING: valStr.clear(); for( i=0; i<(unsigned int)valDbl.size(); i++ ) // not valDblCount here valStr << ((i>0) ? " " : "") << valDbl[i]; strncpy(static_cast(outValues), valStr.str().c_str(), outValueMaxCount); i = (unsigned int)valStr.str().size(); if( i>outValueMaxCount-1 ) i = outValueMaxCount-1; (static_cast(outValues))[i] = '\0'; return 1; // always returns 1 for CSTRING default: g_TwMgr->SetLastError(g_ErrBadParam); // Unknown param value type retType = RET_ERROR; } } else if( retType==RET_STRING ) { if( paramValueType == TW_PARAM_CSTRING ) { strncpy(static_cast(outValues), valStr.str().c_str(), outValueMaxCount); i = (unsigned int)valStr.str().size(); if( i>outValueMaxCount-1 ) i = outValueMaxCount-1; (static_cast(outValues))[i] = '\0'; return 1; // always returns 1 for CSTRING } else { g_TwMgr->SetLastError(g_ErrBadType); // string cannot be converted to int or double retType = RET_ERROR; } } if( retType==RET_ERROR ) { bool errMsg = (g_TwMgr->CheckLastError()!=NULL && strlen(g_TwMgr->CheckLastError())>0 && PrevLastErrorPtr!=g_TwMgr->CheckLastError()); _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unable to get param '%s%s%s %s' %s%s", (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName, errMsg ? " : " : "", errMsg ? g_TwMgr->CheckLastError() : ""); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); } return retType; } else { _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown param '%s%s%s %s'", (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } } int ANT_CALL TwSetParam(TwBar *bar, const char *varName, const char *paramName, TwParamValueType paramValueType, unsigned int inValueCount, const void *inValues) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( paramName==NULL || strlen(paramName)<=0 ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } if( inValueCount>0 && inValues==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } TwFreeAsyncDrawing(); // For multi-thread savety if( bar==NULL ) bar = TW_GLOBAL_BAR; else { vector::iterator barIt; int i = 0; for( barIt=g_TwMgr->m_Bars.begin(); barIt!=g_TwMgr->m_Bars.end(); ++barIt, ++i ) if( (*barIt)==bar ) break; if( barIt==g_TwMgr->m_Bars.end() ) { g_TwMgr->SetLastError(g_ErrNotFound); return 0; } } CTwVarGroup *varParent = NULL; int varIndex = -1; CTwVar *var = NULL; if( varName!=NULL && strlen(varName)>0 ) { var = bar->Find(varName, &varParent, &varIndex); if( var==NULL ) { _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown var '%s/%s'", (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), varName); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } } bool hasValue = false; int paramID = BarVarHasAttrib(bar, var, paramName, &hasValue); if( paramID>0 ) { int ret = 0; const char *PrevLastErrorPtr = g_TwMgr->CheckLastError(); if( hasValue ) { std::ostringstream valuesStr; unsigned int i; switch( paramValueType ) { case TW_PARAM_INT32: for( i=0; i(inValues))[i] << ((i(inValues))[i] << ((i(inValues))[i] << ((i(inValues))[i]; for( const char *ch = str; *ch!=0; ch++ ) if( *ch=='`' ) valuesStr << "`'`'`"; else valuesStr << *ch; valuesStr << "` "; } */ if( inValueCount!=1 ) { g_TwMgr->SetLastError(g_ErrCStrParam); // count for CString param must be 1 return 0; } else valuesStr << static_cast(inValues); break; default: g_TwMgr->SetLastError(g_ErrBadParam); // Unknown param value type return 0; } ret = BarVarSetAttrib(bar, var, varParent, varIndex, paramID, valuesStr.str().c_str()); } else ret = BarVarSetAttrib(bar, var, varParent, varIndex, paramID, NULL); if( ret==0 ) { bool errMsg = (g_TwMgr->CheckLastError()!=NULL && strlen(g_TwMgr->CheckLastError())>0 && PrevLastErrorPtr!=g_TwMgr->CheckLastError()); _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unable to set param '%s%s%s %s' %s%s", (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName, errMsg ? " : " : "", errMsg ? g_TwMgr->CheckLastError() : ""); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); } return ret; } else { _snprintf(g_ErrParse, sizeof(g_ErrParse), "Unknown param '%s%s%s %s'", (bar==TW_GLOBAL_BAR) ? "GLOBAL" : bar->m_Name.c_str(), (var!=NULL) ? "/" : "", (var!=NULL) ? varName : "", paramName); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } } // --------------------------------------------------------------------------- static int s_PassProxy = 0; void *CTwMgr::CStruct::s_PassProxyAsClientData = &s_PassProxy; // special tag CTwMgr::CStructProxy::CStructProxy() { memset(this, 0, sizeof(*this)); } CTwMgr::CStructProxy::~CStructProxy() { if( m_StructData!=NULL && m_DeleteStructData ) { //if( m_StructExtData==NULL && g_TwMgr!=NULL && m_Type>=TW_TYPE_STRUCT_BASE && m_Typem_Structs.size() ) // g_TwMgr->UninitVarData(m_Type, m_StructData, g_TwMgr->m_Structs[m_Type-TW_TYPE_STRUCT_BASE].m_Size); delete[] (char*)m_StructData; } if( m_StructExtData!=NULL ) { //if( g_TwMgr!=NULL && m_Type>=TW_TYPE_STRUCT_BASE && m_Typem_Structs.size() ) // g_TwMgr->UninitVarData(m_Type, m_StructExtData, g_TwMgr->m_Structs[m_Type-TW_TYPE_STRUCT_BASE].m_Size); delete[] (char*)m_StructExtData; } memset(this, 0, sizeof(*this)); } /* void CTwMgr::InitVarData(TwType _Type, void *_Data, size_t _Size) { if( _Data!=NULL ) { if( _Type>=TW_TYPE_STRUCT_BASE && _Type=TW_TYPE_STRUCT_BASE && _Type~string(); memset(_Data, 0, _Size); } else memset(_Data, 0, _Size); } } */ void CTwMgr::UnrollCDStdString(std::vector& _Records, TwType _Type, void *_Data) { if( _Data!=NULL ) { if( _Type>=TW_TYPE_STRUCT_BASE && _Type& _Records) { for( size_t i=0; i<_Records.size(); ++i ) memcpy(_Records[i].m_DataPtr, _Records[i].m_PrevValue, m_ClientStdStringStructSize); } CTwMgr::CMemberProxy::CMemberProxy() { memset(this, 0, sizeof(*this)); } CTwMgr::CMemberProxy::~CMemberProxy() { memset(this, 0, sizeof(*this)); } void ANT_CALL CTwMgr::CMemberProxy::SetCB(const void *_Value, void *_ClientData) { if( _ClientData && _Value ) { const CMemberProxy *mProxy = static_cast(_ClientData); if( g_TwMgr && mProxy ) { const CStructProxy *sProxy = mProxy->m_StructProxy; if( sProxy && sProxy->m_StructData && sProxy->m_Type>=TW_TYPE_STRUCT_BASE && sProxy->m_Typem_Structs.size() ) { CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE]; if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() ) { CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex]; if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON ) { if( s.m_IsExt ) { memcpy((char *)sProxy->m_StructExtData + m.m_Offset, _Value, m.m_Size); if( s.m_CopyVarFromExtCallback && sProxy->m_StructExtData ) s.m_CopyVarFromExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex, (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData); } else memcpy((char *)sProxy->m_StructData + m.m_Offset, _Value, m.m_Size); if( sProxy->m_StructSetCallback ) { g_TwMgr->m_CDStdStringRecords.resize(0); g_TwMgr->UnrollCDStdString(g_TwMgr->m_CDStdStringRecords, sProxy->m_Type, sProxy->m_StructData); sProxy->m_StructSetCallback(sProxy->m_StructData, sProxy->m_StructClientData); g_TwMgr->RestoreCDStdString(g_TwMgr->m_CDStdStringRecords); } } } } } } } void ANT_CALL CTwMgr::CMemberProxy::GetCB(void *_Value, void *_ClientData) { if( _ClientData && _Value ) { const CMemberProxy *mProxy = static_cast(_ClientData); if( g_TwMgr && mProxy ) { const CStructProxy *sProxy = mProxy->m_StructProxy; if( sProxy && sProxy->m_StructData && sProxy->m_Type>=TW_TYPE_STRUCT_BASE && sProxy->m_Typem_Structs.size() ) { CTwMgr::CStruct& s = g_TwMgr->m_Structs[sProxy->m_Type-TW_TYPE_STRUCT_BASE]; if( mProxy->m_MemberIndex>=0 && mProxy->m_MemberIndex<(int)s.m_Members.size() ) { CTwMgr::CStructMember& m = s.m_Members[mProxy->m_MemberIndex]; if( m.m_Size>0 && m.m_Type!=TW_TYPE_BUTTON ) { if( sProxy->m_StructGetCallback ) sProxy->m_StructGetCallback(sProxy->m_StructData, sProxy->m_StructClientData); if( s.m_IsExt ) { if( s.m_CopyVarToExtCallback && sProxy->m_StructExtData ) s.m_CopyVarToExtCallback(sProxy->m_StructData, sProxy->m_StructExtData, mProxy->m_MemberIndex, (s.m_ExtClientData==s.s_PassProxyAsClientData) ? _ClientData : s.m_ExtClientData); memcpy(_Value, (char *)sProxy->m_StructExtData + m.m_Offset, m.m_Size); } else memcpy(_Value, (char *)sProxy->m_StructData + m.m_Offset, m.m_Size); } } } } } } // --------------------------------------------------------------------------- void ANT_CALL CTwMgr::CCDStdString::SetCB(const void *_Value, void *_ClientData) { if( _Value==NULL || _ClientData==NULL || g_TwMgr==NULL ) return; CTwMgr::CCDStdString *CDStdString = (CTwMgr::CCDStdString *)_ClientData; const char *SrcStr = *(const char **)_Value; if( SrcStr==NULL ) { static char s_EmptyString[] = ""; SrcStr = s_EmptyString; } if( CDStdString->m_ClientSetCallback==NULL ) { if( g_TwMgr->m_CopyStdStringToClient && CDStdString->m_ClientStdStringPtr!=NULL ) { CTwMgr::CClientStdString clientSrcStr; // convert VC++ Release/Debug std::string clientSrcStr.FromLib(SrcStr); g_TwMgr->m_CopyStdStringToClient(*(CDStdString->m_ClientStdStringPtr), clientSrcStr.ToClient()); } } else { if( CDStdString->m_ClientSetCallback==CMemberProxy::SetCB ) CDStdString->m_ClientSetCallback(&SrcStr, CDStdString->m_ClientData); else { CTwMgr::CClientStdString clientSrcStr; // convert VC++ Release/Debug std::string clientSrcStr.FromLib(SrcStr); std::string& ValStr = clientSrcStr.ToClient(); CDStdString->m_ClientSetCallback(&ValStr, CDStdString->m_ClientData); } } } void ANT_CALL CTwMgr::CCDStdString::GetCB(void *_Value, void *_ClientData) { if( _Value==NULL || _ClientData==NULL || g_TwMgr==NULL ) return; CTwMgr::CCDStdString *CDStdString = (CTwMgr::CCDStdString *)_ClientData; char **DstStrPtr = (char **)_Value; if( CDStdString->m_ClientGetCallback==NULL ) { if( CDStdString->m_ClientStdStringPtr!=NULL ) { //*DstStrPtr = const_cast(CDStdString->m_ClientStdStringPtr->c_str()); static CTwMgr::CLibStdString s_LibStr; // static because it will be used as a returned value s_LibStr.FromClient(*CDStdString->m_ClientStdStringPtr); *DstStrPtr = const_cast(s_LibStr.ToLib().c_str()); } else { static char s_EmptyString[] = ""; *DstStrPtr = s_EmptyString; } } else { // m_ClientGetCallback uses TwCopyStdStringToLibrary to copy string // and TwCopyStdStringToLibrary does the VC++ Debug/Release std::string conversion. CDStdString->m_ClientGetCallback(&(CDStdString->m_LocalString[0]), CDStdString->m_ClientData); //*DstStrPtr = const_cast(CDStdString->m_LocalString.c_str()); char **StrPtr = (char **)&(CDStdString->m_LocalString[0]); *DstStrPtr = *StrPtr; } } // --------------------------------------------------------------------------- static int s_SeparatorTag = 0; // --------------------------------------------------------------------------- static int AddVar(TwBar *_Bar, const char *_Name, ETwType _Type, void *_VarPtr, bool _ReadOnly, TwSetVarCallback _SetCallback, TwGetVarCallback _GetCallback, TwButtonCallback _ButtonCallback, void *_ClientData, const char *_Def) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } char unnamedVarName[64]; if( _Name==NULL || strlen(_Name)==0 ) // create a name automatically { static unsigned int s_UnnamedVarCount = 0; _snprintf(unnamedVarName, sizeof(unnamedVarName), "TW_UNNAMED_%04X", s_UnnamedVarCount); _Name = unnamedVarName; ++s_UnnamedVarCount; } if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 || (_VarPtr==NULL && _GetCallback==NULL && _Type!=TW_TYPE_BUTTON) ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } if( _Bar->Find(_Name)!=NULL ) { g_TwMgr->SetLastError(g_ErrExist); return 0; } if( strstr(_Name, "`")!=NULL ) { g_TwMgr->SetLastError(g_ErrNoBackQuote); return 0; } if( _VarPtr==NULL && _Type!=TW_TYPE_BUTTON && _GetCallback!=NULL && _SetCallback==NULL ) _ReadOnly = true; // force readonly in this case // Convert color types if( _Type==TW_TYPE_COLOR32 ) _Type = g_TwMgr->m_TypeColor32; else if( _Type==TW_TYPE_COLOR3F ) _Type = g_TwMgr->m_TypeColor3F; else if( _Type==TW_TYPE_COLOR4F ) _Type = g_TwMgr->m_TypeColor4F; // Convert rotation types if( _Type==TW_TYPE_QUAT4F ) _Type = g_TwMgr->m_TypeQuat4F; else if( _Type==TW_TYPE_QUAT4D ) _Type = g_TwMgr->m_TypeQuat4D; else if( _Type==TW_TYPE_DIR3F ) _Type = g_TwMgr->m_TypeDir3F; else if( _Type==TW_TYPE_DIR3D ) _Type = g_TwMgr->m_TypeDir3D; // VC++ uses a different definition of std::string in Debug and Release modes. // sizeof(std::string) is encoded in TW_TYPE_STDSTRING to overcome this issue. if( (_Type&0xffff0000)==(TW_TYPE_STDSTRING&0xffff0000) ) { size_t clientStdStringStructSize = (_Type&0xffff); if( g_TwMgr->m_ClientStdStringStructSize==0 ) g_TwMgr->m_ClientStdStringStructSize = clientStdStringStructSize; int diff = abs((int)g_TwMgr->m_ClientStdStringStructSize - (int)sizeof(std::string)); if( g_TwMgr->m_ClientStdStringStructSize!=clientStdStringStructSize || g_TwMgr->m_ClientStdStringStructSize==0 || (diff!=0 && diff!=sizeof(void*))) { g_TwMgr->SetLastError(g_ErrStdString); return 0; } _Type = TW_TYPE_STDSTRING; // force type to be our TW_TYPE_STDSTRING } if( _Type==TW_TYPE_STDSTRING ) { g_TwMgr->m_CDStdStrings.push_back(CTwMgr::CCDStdString()); CTwMgr::CCDStdString& CDStdString = g_TwMgr->m_CDStdStrings.back(); CDStdString.m_ClientStdStringPtr = (std::string *)_VarPtr; CDStdString.m_ClientSetCallback = _SetCallback; CDStdString.m_ClientGetCallback = _GetCallback; CDStdString.m_ClientData = _ClientData; //CDStdString.m_This = g_TwMgr->m_CDStdStrings.end(); //--CDStdString.m_This; TwGetVarCallback GetCB = CTwMgr::CCDStdString::GetCB; TwSetVarCallback SetCB = CTwMgr::CCDStdString::SetCB; if( _VarPtr==NULL && _SetCallback==NULL ) SetCB = NULL; if( _VarPtr==NULL && _GetCallback==NULL ) GetCB = NULL; return AddVar(_Bar, _Name, TW_TYPE_CDSTDSTRING, NULL, _ReadOnly, SetCB, GetCB, NULL, &CDStdString, _Def); } else if( (_Type>TW_TYPE_UNDEF && _Type=TW_TYPE_ENUM_BASE && _Typem_Enums.size()) || (_Type>TW_TYPE_CSSTRING_BASE && _Type<=TW_TYPE_CSSTRING_MAX) || _Type==TW_TYPE_CDSTDSTRING || IsCustomType(_Type) ) // (_Type>=TW_TYPE_CUSTOM_BASE && _Typem_Customs.size()) ) { CTwVarAtom *Var = new CTwVarAtom; Var->m_Name = _Name; Var->m_Ptr = _VarPtr; Var->m_Type = _Type; Var->m_ColorPtr = &(_Bar->m_ColLabelText); if( _VarPtr!=NULL ) { assert( _GetCallback==NULL && _SetCallback==NULL && _ButtonCallback==NULL ); Var->m_ReadOnly = _ReadOnly; Var->m_GetCallback = NULL; Var->m_SetCallback = NULL; Var->m_ClientData = NULL; } else { assert( _GetCallback!=NULL || _Type==TW_TYPE_BUTTON ); Var->m_GetCallback = _GetCallback; Var->m_SetCallback = _SetCallback; Var->m_ClientData = _ClientData; if( _Type==TW_TYPE_BUTTON ) { Var->m_Val.m_Button.m_Callback = _ButtonCallback; if( _ButtonCallback==NULL && _ClientData==&s_SeparatorTag ) { Var->m_Val.m_Button.m_Separator = 1; Var->m_Label = " "; } else if( _ButtonCallback==NULL ) Var->m_ColorPtr = &(_Bar->m_ColStaticText); } if( _Type!=TW_TYPE_BUTTON ) Var->m_ReadOnly = (_SetCallback==NULL || _ReadOnly); else Var->m_ReadOnly = (_ButtonCallback==NULL); } Var->SetDefaults(); if( IsCustomType(_Type) ) // _Type>=TW_TYPE_CUSTOM_BASE && _Typem_Customs.size() ) { if( Var->m_GetCallback==CTwMgr::CMemberProxy::GetCB && Var->m_SetCallback==CTwMgr::CMemberProxy::SetCB ) Var->m_Val.m_Custom.m_MemberProxy = static_cast(Var->m_ClientData); else Var->m_Val.m_Custom.m_MemberProxy = NULL; } _Bar->m_VarRoot.m_Vars.push_back(Var); _Bar->NotUpToDate(); g_TwMgr->m_HelpBarNotUpToDate = true; if( _Def!=NULL && strlen(_Def)>0 ) { string d = '`' + _Bar->m_Name + "`/`" + _Name + "` " + _Def; return TwDefine(d.c_str()); } else return 1; } else if(_Type>=TW_TYPE_STRUCT_BASE && _Typem_Structs.size()) { CTwMgr::CStruct& s = g_TwMgr->m_Structs[_Type-TW_TYPE_STRUCT_BASE]; CTwMgr::CStructProxy *sProxy = NULL; void *vPtr; if( !s.m_IsExt ) { if( _VarPtr!=NULL ) vPtr = _VarPtr; else { assert( _GetCallback!=NULL || _SetCallback!=NULL ); assert( s.m_Size>0 ); vPtr = new char[s.m_Size]; memset(vPtr, 0, s.m_Size); // create a new StructProxy g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy()); sProxy = &(g_TwMgr->m_StructProxies.back()); sProxy->m_Type = _Type; sProxy->m_StructData = vPtr; sProxy->m_DeleteStructData = true; sProxy->m_StructSetCallback = _SetCallback; sProxy->m_StructGetCallback = _GetCallback; sProxy->m_StructClientData = _ClientData; sProxy->m_CustomDrawCallback = NULL; sProxy->m_CustomMouseButtonCallback = NULL; sProxy->m_CustomMouseMotionCallback = NULL; sProxy->m_CustomMouseLeaveCallback = NULL; sProxy->m_CustomCaptureFocus = false; sProxy->m_CustomIndexFirst = -1; sProxy->m_CustomIndexLast = -1; //g_TwMgr->InitVarData(sProxy->m_Type, sProxy->m_StructData, s.m_Size); } } else // s.m_IsExt { assert( s.m_Size>0 && s.m_ClientStructSize>0 ); vPtr = new char[s.m_Size]; // will be m_StructExtData memset(vPtr, 0, s.m_Size); // create a new StructProxy g_TwMgr->m_StructProxies.push_back(CTwMgr::CStructProxy()); sProxy = &(g_TwMgr->m_StructProxies.back()); sProxy->m_Type = _Type; sProxy->m_StructExtData = vPtr; sProxy->m_StructSetCallback = _SetCallback; sProxy->m_StructGetCallback = _GetCallback; sProxy->m_StructClientData = _ClientData; sProxy->m_CustomDrawCallback = NULL; sProxy->m_CustomMouseButtonCallback = NULL; sProxy->m_CustomMouseMotionCallback = NULL; sProxy->m_CustomMouseLeaveCallback = NULL; sProxy->m_CustomCaptureFocus = false; sProxy->m_CustomIndexFirst = -1; sProxy->m_CustomIndexLast = -1; //g_TwMgr->InitVarData(sProxy->m_Type, sProxy->m_StructExtData, s.m_Size); if( _VarPtr!=NULL ) { sProxy->m_StructData = _VarPtr; sProxy->m_DeleteStructData = false; } else { sProxy->m_StructData = new char[s.m_ClientStructSize]; memset(sProxy->m_StructData, 0, s.m_ClientStructSize); sProxy->m_DeleteStructData = true; //g_TwMgr->InitVarData(ClientStructType, sProxy->m_StructData, s.m_ClientStructSize); //ClientStructType is unknown } _VarPtr = NULL; // force use of TwAddVarCB for members // init m_StructExtdata if( s.m_ExtClientData==CTwMgr::CStruct::s_PassProxyAsClientData ) s.m_StructExtInitCallback(sProxy->m_StructExtData, sProxy); else s.m_StructExtInitCallback(sProxy->m_StructExtData, s.m_ExtClientData); } for( int i=0; i<(int)s.m_Members.size(); ++i ) { CTwMgr::CStructMember& m = s.m_Members[i]; string name = string(_Name) + '.' + m.m_Name; const char *access = ""; if( _ReadOnly ) access = "readonly "; string def = "label=`" + m.m_Name + "` group=`" + _Name + "` " + access; // + m.m_DefString; // member def must be done after group def if( _VarPtr!=NULL ) { if( TwAddVarRW(_Bar, name.c_str(), m.m_Type, (char*)vPtr+m.m_Offset, def.c_str())==0 ) return 0; } else { assert( sProxy!=NULL ); // create a new MemberProxy g_TwMgr->m_MemberProxies.push_back(CTwMgr::CMemberProxy()); CTwMgr::CMemberProxy& mProxy = g_TwMgr->m_MemberProxies.back(); mProxy.m_StructProxy = sProxy; mProxy.m_MemberIndex = i; assert( !(s.m_IsExt && (m.m_Type==TW_TYPE_STDSTRING || m.m_Type==TW_TYPE_CDSTDSTRING)) ); // forbidden because this case is not handled by UnrollCDStdString if( TwAddVarCB(_Bar, name.c_str(), m.m_Type, CTwMgr::CMemberProxy::SetCB, CTwMgr::CMemberProxy::GetCB, &mProxy, def.c_str())==0 ) return 0; mProxy.m_Var = _Bar->Find(name.c_str(), &mProxy.m_VarParent, NULL); mProxy.m_Bar = _Bar; } if( sProxy!=NULL && IsCustomType(m.m_Type) ) // m.m_Type>=TW_TYPE_CUSTOM_BASE && m.m_Typem_Customs.size() ) { if( sProxy->m_CustomIndexFirst<0 ) sProxy->m_CustomIndexFirst = sProxy->m_CustomIndexLast = i; else sProxy->m_CustomIndexLast = i; } } char structInfo[64]; sprintf(structInfo, "typeid=%d valptr=%p close ", _Type, vPtr); string grpDef = '`' + _Bar->m_Name + "`/`" + _Name + "` " + structInfo; if( _Def!=NULL && strlen(_Def)>0 ) grpDef += _Def; int ret = TwDefine(grpDef.c_str()); for( int i=0; i<(int)s.m_Members.size(); ++i ) // members must be defined even if grpDef has error { CTwMgr::CStructMember& m = s.m_Members[i]; if( m.m_DefString.length()>0 ) { string memberDef = '`' + _Bar->m_Name + "`/`" + _Name + '.' + m.m_Name + "` " + m.m_DefString; if( !TwDefine(memberDef.c_str()) ) // all members must be defined even if memberDef has error ret = 0; } } return ret; } else { if( _Type==TW_TYPE_CSSTRING_BASE ) g_TwMgr->SetLastError(g_ErrBadSize); // static string of size null else g_TwMgr->SetLastError(g_ErrNotFound); return 0; } } // --------------------------------------------------------------------------- int ANT_CALL TwAddVarRW(TwBar *_Bar, const char *_Name, ETwType _Type, void *_Var, const char *_Def) { return AddVar(_Bar, _Name, _Type, _Var, false, NULL, NULL, NULL, NULL, _Def); } // --------------------------------------------------------------------------- int ANT_CALL TwAddVarRO(TwBar *_Bar, const char *_Name, ETwType _Type, const void *_Var, const char *_Def) { return AddVar(_Bar, _Name, _Type, const_cast(_Var), true, NULL, NULL, NULL, NULL, _Def); } // --------------------------------------------------------------------------- int ANT_CALL TwAddVarCB(TwBar *_Bar, const char *_Name, ETwType _Type, TwSetVarCallback _SetCallback, TwGetVarCallback _GetCallback, void *_ClientData, const char *_Def) { return AddVar(_Bar, _Name, _Type, NULL, false, _SetCallback, _GetCallback, NULL, _ClientData, _Def); } // --------------------------------------------------------------------------- int ANT_CALL TwAddButton(TwBar *_Bar, const char *_Name, TwButtonCallback _Callback, void *_ClientData, const char *_Def) { return AddVar(_Bar, _Name, TW_TYPE_BUTTON, NULL, false, NULL, NULL, _Callback, _ClientData, _Def); } // --------------------------------------------------------------------------- int ANT_CALL TwAddSeparator(TwBar *_Bar, const char *_Name, const char *_Def) { return AddVar(_Bar, _Name, TW_TYPE_BUTTON, NULL, true, NULL, NULL, NULL, &s_SeparatorTag, _Def); } // --------------------------------------------------------------------------- int ANT_CALL TwRemoveVar(TwBar *_Bar, const char *_Name) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( _Bar==NULL || _Name==NULL || strlen(_Name)==0 ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar ) // delete popup bar first if it exists { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } _Bar->StopEditInPlace(); // desactivate EditInPlace CTwVarGroup *Parent = NULL; int Index = -1; CTwVar *Var = _Bar->Find(_Name, &Parent, &Index); if( Var!=NULL && Parent!=NULL && Index>=0 ) { if( Parent->m_StructValuePtr!=NULL ) { g_TwMgr->SetLastError(g_ErrDelStruct); return 0; } delete Var; Parent->m_Vars.erase(Parent->m_Vars.begin()+Index); if( Parent!=&(_Bar->m_VarRoot) && Parent->m_Vars.size()<=0 ) TwRemoveVar(_Bar, Parent->m_Name.c_str()); _Bar->NotUpToDate(); if( _Bar!=g_TwMgr->m_HelpBar ) g_TwMgr->m_HelpBarNotUpToDate = true; return 1; } g_TwMgr->SetLastError(g_ErrNotFound); return 0; } // --------------------------------------------------------------------------- int ANT_CALL TwRemoveAllVars(TwBar *_Bar) { if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( _Bar==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar && _Bar!=g_TwMgr->m_HelpBar ) // delete popup bar first if it exists { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } _Bar->StopEditInPlace(); // desactivate EditInPlace for( vector::iterator it=_Bar->m_VarRoot.m_Vars.begin(); it!=_Bar->m_VarRoot.m_Vars.end(); ++it ) if( *it != NULL ) { delete *it; *it = NULL; } _Bar->m_VarRoot.m_Vars.resize(0); _Bar->NotUpToDate(); g_TwMgr->m_HelpBarNotUpToDate = true; return 1; } // --------------------------------------------------------------------------- int ParseToken(string& _Token, const char *_Def, int& Line, int& Column, bool _KeepQuotes, bool _EndCR, char _Sep1='\0', char _Sep2='\0') { const char *Cur = _Def; _Token = ""; // skip spaces while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' || *Cur=='\n' ) { if( *Cur=='\n' && _EndCR ) return (int)(Cur-_Def); // a CR has been found ++Cur; if( *Cur=='\n' ) { ++Line; Column = 1; } else if( *Cur=='\t' ) Column += g_TabLength; else if( *Cur!='\r' ) ++Column; } // read token int QuoteLine=0, QuoteColumn=0; const char *QuoteCur; char Quote = 0; bool AddChar; bool LineJustIncremented = false; while( (Quote==0 && (*Cur!='\0' && *Cur!=' ' && *Cur!='\t' && *Cur!='\r' && *Cur!='\n' && *Cur!=_Sep1 && *Cur!=_Sep2)) || (Quote!=0 && (*Cur!='\0' /* && *Cur!='\r' && *Cur!='\n' */)) ) // allow multi-line strings { LineJustIncremented = false; AddChar = true; if( Quote==0 && (*Cur=='\'' || *Cur=='\"' || *Cur=='`') ) { Quote = *Cur; QuoteLine = Line; QuoteColumn = Column; QuoteCur = Cur; AddChar = _KeepQuotes; } else if ( Quote!=0 && *Cur==Quote ) { Quote = 0; AddChar = _KeepQuotes; } if( AddChar ) _Token += *Cur; ++Cur; if( *Cur=='\t' ) Column += g_TabLength; else if( *Cur=='\n' ) { ++Line; LineJustIncremented = true; Column = 1; } else ++Column; } if( Quote!=0 ) { Line = QuoteLine; Column = QuoteColumn; return -(int)(Cur-_Def); // unclosed quote } else { if( *Cur=='\n' ) { if( !LineJustIncremented ) ++Line; Column = 1; } else if( *Cur=='\t' ) Column += g_TabLength; else if( *Cur!='\r' && *Cur!='\0' ) ++Column; return (int)(Cur-_Def); } } // --------------------------------------------------------------------------- int GetBarVarFromString(CTwBar **_Bar, CTwVar **_Var, CTwVarGroup **_VarParent, int *_VarIndex, const char *_Str) { *_Bar = NULL; *_Var = NULL; *_VarParent = NULL; *_VarIndex = -1; vector Names; string Token; const char *Cur =_Str; int l=1, c=1, p=1; while( *Cur!='\0' && p>0 && Names.size()<=3 ) { p = ParseToken(Token, Cur, l, c, false, true, '/', '\\'); if( p>0 && Token.size()>0 ) { Names.push_back(Token); Cur += p + ((Cur[p]!='\0')?1:0); } } if( p<=0 || (Names.size()!=1 && Names.size()!=2) ) return 0; // parse error int BarIdx = g_TwMgr->FindBar(Names[0].c_str()); if( BarIdx<0 ) { if( Names.size()==1 && strcmp(Names[0].c_str(), "GLOBAL")==0 ) { *_Bar = TW_GLOBAL_BAR; return +3; // 'GLOBAL' found } else return -1; // bar not found } *_Bar = g_TwMgr->m_Bars[BarIdx]; if( Names.size()==1 ) return 1; // bar found, no var name parsed *_Var = (*_Bar)->Find(Names[1].c_str(), _VarParent, _VarIndex); if( *_Var==NULL ) return -2; // var not found return 2; // bar and var found } int BarVarHasAttrib(CTwBar *_Bar, CTwVar *_Var, const char *_Attrib, bool *_HasValue) { assert(_Bar!=NULL && _HasValue!=NULL && _Attrib!=NULL && strlen(_Attrib)>0); *_HasValue = false; if( _Bar==TW_GLOBAL_BAR ) { assert( _Var==NULL ); return g_TwMgr->HasAttrib(_Attrib, _HasValue); } else if( _Var==NULL ) return _Bar->HasAttrib(_Attrib, _HasValue); else return _Var->HasAttrib(_Attrib, _HasValue); } int BarVarSetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, const char *_Value) { assert(_Bar!=NULL && _AttribID>0); /* don't delete popupbar here: if any attrib is changed every frame by the app, popup will not work anymore. if( g_TwMgr->m_PopupBar!=NULL && _Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar->m_BarLinkedToPopupList==_Bar ) // delete popup bar first if it exists { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } */ if( _Bar==TW_GLOBAL_BAR ) { assert( _Var==NULL ); return g_TwMgr->SetAttrib(_AttribID, _Value); } else if( _Var==NULL ) return _Bar->SetAttrib(_AttribID, _Value); else return _Var->SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex); // don't make _Bar not-up-to-date here, should be done in SetAttrib if needed to avoid too frequent refreshs } ERetType BarVarGetAttrib(CTwBar *_Bar, CTwVar *_Var, CTwVarGroup *_VarParent, int _VarIndex, int _AttribID, std::vector& outDoubles, std::ostringstream& outString) { assert(_Bar!=NULL && _AttribID>0); if( _Bar==TW_GLOBAL_BAR ) { assert( _Var==NULL ); return g_TwMgr->GetAttrib(_AttribID, outDoubles, outString); } else if( _Var==NULL ) return _Bar->GetAttrib(_AttribID, outDoubles, outString); else return _Var->GetAttrib(_AttribID, _Bar, _VarParent, _VarIndex, outDoubles, outString); } // --------------------------------------------------------------------------- static inline std::string ErrorPosition(bool _MultiLine, int _Line, int _Column) { if( !_MultiLine ) return ""; else { char pos[32]; //_snprintf(pos, sizeof(pos)-1, " line %d column %d", _Line, _Column); _snprintf(pos, sizeof(pos)-1, " line %d", _Line); (void)_Column; pos[sizeof(pos)-1] = '\0'; return pos; } } // --------------------------------------------------------------------------- int ANT_CALL TwDefine(const char *_Def) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return 0; // not initialized } if( _Def==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return 0; } bool MultiLine = false; const char *Cur = _Def; while( *Cur!='\0' ) { if( *Cur=='\n' ) { MultiLine = true; break; } ++Cur; } int Line = 1; int Column = 1; enum EState { PARSE_NAME, PARSE_ATTRIB }; EState State = PARSE_NAME; string Token; string Value; CTwBar *Bar = NULL; CTwVar *Var = NULL; CTwVarGroup *VarParent = NULL; int VarIndex = -1; int p; Cur = _Def; while( *Cur!='\0' ) { const char *PrevCur = Cur; p = ParseToken(Token, Cur, Line, Column, (State==PARSE_NAME), (State==PARSE_ATTRIB), (State==PARSE_ATTRIB)?'=':'\0'); if( p<=0 || Token.size()<=0 ) { if( p>0 && Cur[p]=='\0' ) { Cur += p; continue; } _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), (p<0)?(Cur-p):PrevCur); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } char CurSep = Cur[p]; Cur += p + ((CurSep!='\0')?1:0); if( State==PARSE_NAME ) { int Err = GetBarVarFromString(&Bar, &Var, &VarParent, &VarIndex, Token.c_str()); if( Err<=0 ) { if( Err==-1 ) _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Bar not found%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); else if( Err==-2 ) _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Variable not found%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); else _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } State = PARSE_ATTRIB; } else // State==PARSE_ATTRIB { assert(State==PARSE_ATTRIB); assert(Bar!=NULL); bool HasValue = false; Value = ""; int AttribID = BarVarHasAttrib(Bar, Var, Token.c_str(), &HasValue); if( AttribID<=0 ) { _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: Unknown attribute%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } // special case for backward compatibility if( HasValue && ( _stricmp(Token.c_str(), "readonly")==0 || _stricmp(Token.c_str(), "hexa")==0 ) ) { if( CurSep==' ' || CurSep=='\t' ) { const char *ch = Cur; while( *ch==' ' || *ch=='\t' ) // find next non-space character ++ch; if( *ch!='=' ) // if this is not '=' the param has no value HasValue = false; } } if( HasValue ) { if( CurSep!='=' ) { string EqualStr; p = ParseToken(EqualStr, Cur, Line, Column, true, true, '='); CurSep = Cur[p]; if( p<0 || EqualStr.size()>0 || CurSep!='=' ) { _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: '=' not found while reading attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } Cur += p + 1; } p = ParseToken(Value, Cur, Line, Column, false, true); if( p<=0 ) { _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: can't read attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } CurSep = Cur[p]; Cur += p + ((CurSep!='\0')?1:0); } const char *PrevLastErrorPtr = g_TwMgr->CheckLastError(); if( BarVarSetAttrib(Bar, Var, VarParent, VarIndex, AttribID, HasValue?Value.c_str():NULL)==0 ) { if( g_TwMgr->CheckLastError()==NULL || strlen(g_TwMgr->CheckLastError())<=0 || g_TwMgr->CheckLastError()==PrevLastErrorPtr ) _snprintf(g_ErrParse, sizeof(g_ErrParse), "Parsing error in def string: wrong attribute value%s [%-16s...]", ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); else _snprintf(g_ErrParse, sizeof(g_ErrParse), "%s%s [%-16s...]", g_TwMgr->CheckLastError(), ErrorPosition(MultiLine, Line, Column).c_str(), Token.c_str()); g_ErrParse[sizeof(g_ErrParse)-1] = '\0'; g_TwMgr->SetLastError(g_ErrParse); return 0; } // sweep spaces to detect next attrib while( *Cur==' ' || *Cur=='\t' || *Cur=='\r' ) { ++Cur; if( *Cur=='\t' ) Column += g_TabLength; else if( *Cur!='\r' ) ++Column; } if( *Cur=='\n' ) // new line detected { ++Line; Column = 1; State = PARSE_NAME; } } } g_TwMgr->m_HelpBarNotUpToDate = true; return 1; } // --------------------------------------------------------------------------- TwType ANT_CALL TwDefineEnum(const char *_Name, const TwEnumVal *_EnumValues, unsigned int _NbValues) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return TW_TYPE_UNDEF; // not initialized } if( _EnumValues==NULL && _NbValues!=0 ) { g_TwMgr->SetLastError(g_ErrBadParam); return TW_TYPE_UNDEF; } if( g_TwMgr->m_PopupBar!=NULL ) // delete popup bar first if it exists { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } size_t enumIndex = g_TwMgr->m_Enums.size(); if( _Name!=NULL && strlen(_Name)>0 ) for( size_t j=0; jm_Enums.size(); ++j ) if( strcmp(_Name, g_TwMgr->m_Enums[j].m_Name.c_str())==0 ) { enumIndex = j; break; } if( enumIndex==g_TwMgr->m_Enums.size() ) g_TwMgr->m_Enums.push_back(CTwMgr::CEnum()); assert( enumIndex>=0 && enumIndexm_Enums.size() ); CTwMgr::CEnum& e = g_TwMgr->m_Enums[enumIndex]; if( _Name!=NULL && strlen(_Name)>0 ) e.m_Name = _Name; else e.m_Name = ""; e.m_Entries.clear(); for(unsigned int i=0; i<_NbValues; ++i) { CTwMgr::CEnum::CEntries::value_type Entry(_EnumValues[i].Value, (_EnumValues[i].Label!=NULL)?_EnumValues[i].Label:""); pair Result = e.m_Entries.insert(Entry); if( !Result.second ) (Result.first)->second = Entry.second; } return TwType( TW_TYPE_ENUM_BASE + enumIndex ); } // --------------------------------------------------------------------------- TwType TW_CALL TwDefineEnumFromString(const char *_Name, const char *_EnumString) { if (_EnumString == NULL) return TwDefineEnum(_Name, NULL, 0); // split enumString stringstream EnumStream(_EnumString); string Label; vector Labels; while( getline(EnumStream, Label, ',') ) { // trim Label size_t Start = Label.find_first_not_of(" \n\r\t"); size_t End = Label.find_last_not_of(" \n\r\t"); if( Start==string::npos || End==string::npos ) Label = ""; else Label = Label.substr(Start, (End-Start)+1); // store Label Labels.push_back(Label); } // create TwEnumVal array vector Vals(Labels.size()); for( int i=0; i<(int)Labels.size(); i++ ) { Vals[i].Value = i; Vals[i].Label = Labels[i].c_str(); } return TwDefineEnum(_Name, Vals.empty() ? NULL : &(Vals[0]), (unsigned int)Vals.size()); } // --------------------------------------------------------------------------- void ANT_CALL CTwMgr::CStruct::DefaultSummary(char *_SummaryString, size_t _SummaryMaxLength, const void *_Value, void *_ClientData) { const CTwVarGroup *varGroup = static_cast(_Value); // special case if( _SummaryString && _SummaryMaxLength>0 ) _SummaryString[0] = '\0'; size_t structIndex = (size_t)(_ClientData); if( g_TwMgr && _SummaryString && _SummaryMaxLength>2 && varGroup && static_cast(varGroup)->IsGroup() && structIndex>=0 && structIndex<=g_TwMgr->m_Structs.size() ) { // return g_TwMgr->m_Structs[structIndex].m_Name.c_str(); CTwMgr::CStruct& s = g_TwMgr->m_Structs[structIndex]; _SummaryString[0] = '{'; _SummaryString[1] = '\0'; bool separator = false; for( size_t i=0; im_Name + '.' + s.m_Members[i].m_Name; const CTwVar *var = varGroup->Find(varName.c_str(), NULL, NULL); if( var ) { if( var->IsGroup() ) { const CTwVarGroup *grp = static_cast(var); if( grp->m_SummaryCallback!=NULL ) { size_t l = strlen(_SummaryString); if( separator ) { _SummaryString[l++] = ','; _SummaryString[l++] = '\0'; } if( grp->m_SummaryCallback==CTwMgr::CStruct::DefaultSummary ) grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp, grp->m_SummaryClientData); else grp->m_SummaryCallback(_SummaryString+l, _SummaryMaxLength-l, grp->m_StructValuePtr, grp->m_SummaryClientData); separator = true; } } else { size_t l = strlen(_SummaryString); if( separator ) { _SummaryString[l++] = ','; _SummaryString[l++] = '\0'; } string valString; const CTwVarAtom *atom = static_cast(var); atom->ValueToString(&valString); if( atom->m_Type==TW_TYPE_BOOLCPP || atom->m_Type==TW_TYPE_BOOL8 || atom->m_Type==TW_TYPE_BOOL16 || atom->m_Type==TW_TYPE_BOOL32 ) { if (valString == "0") valString = "-"; else if (valString == "1") valString = "\x7f"; // check sign } strncat(_SummaryString, valString.c_str(), _SummaryMaxLength-l); separator = true; } if( strlen(_SummaryString)>_SummaryMaxLength-2 ) break; } } size_t l = strlen(_SummaryString); if( l>_SummaryMaxLength-2 ) { _SummaryString[_SummaryMaxLength-2] = '.'; _SummaryString[_SummaryMaxLength-1] = '.'; _SummaryString[_SummaryMaxLength+0] = '\0'; } else { _SummaryString[l+0] = '}'; _SummaryString[l+1] = '\0'; } } } // --------------------------------------------------------------------------- TwType ANT_CALL TwDefineStruct(const char *_StructName, const TwStructMember *_StructMembers, unsigned int _NbMembers, size_t _StructSize, TwSummaryCallback _SummaryCallback, void *_SummaryClientData) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return TW_TYPE_UNDEF; // not initialized } if( _StructMembers==NULL || _NbMembers==0 || _StructSize==0 ) { g_TwMgr->SetLastError(g_ErrBadParam); return TW_TYPE_UNDEF; } if( _StructName!=NULL && strlen(_StructName)>0 ) for( size_t j=0; jm_Structs.size(); ++j ) if( strcmp(_StructName, g_TwMgr->m_Structs[j].m_Name.c_str())==0 ) { g_TwMgr->SetLastError(g_ErrExist); return TW_TYPE_UNDEF; } size_t structIndex = g_TwMgr->m_Structs.size(); CTwMgr::CStruct s; s.m_Size = _StructSize; if( _StructName!=NULL && strlen(_StructName)>0 ) s.m_Name = _StructName; else s.m_Name = ""; s.m_Members.resize(_NbMembers); if( _SummaryCallback!=NULL ) { s.m_SummaryCallback = _SummaryCallback; s.m_SummaryClientData = _SummaryClientData; } else { s.m_SummaryCallback = CTwMgr::CStruct::DefaultSummary; s.m_SummaryClientData = (void *)(structIndex); } for( unsigned int i=0; i<_NbMembers; ++i ) { CTwMgr::CStructMember& m = s.m_Members[i]; if( _StructMembers[i].Name!=NULL ) m.m_Name = _StructMembers[i].Name; else { char name[16]; sprintf(name, "%u", i); m.m_Name = name; } m.m_Type = _StructMembers[i].Type; m.m_Size = 0; // to avoid endless recursivity in GetDataSize m.m_Size = CTwVar::GetDataSize(m.m_Type); if( _StructMembers[i].Offset<_StructSize ) m.m_Offset = _StructMembers[i].Offset; else { g_TwMgr->SetLastError(g_ErrOffset); return TW_TYPE_UNDEF; } if( _StructMembers[i].DefString!=NULL && strlen(_StructMembers[i].DefString)>0 ) m.m_DefString = _StructMembers[i].DefString; else m.m_DefString = ""; } g_TwMgr->m_Structs.push_back(s); assert( g_TwMgr->m_Structs.size()==structIndex+1 ); return TwType( TW_TYPE_STRUCT_BASE + structIndex ); } // --------------------------------------------------------------------------- TwType ANT_CALL TwDefineStructExt(const char *_StructName, const TwStructMember *_StructExtMembers, unsigned int _NbExtMembers, size_t _StructSize, size_t _StructExtSize, TwStructExtInitCallback _StructExtInitCallback, TwCopyVarFromExtCallback _CopyVarFromExtCallback, TwCopyVarToExtCallback _CopyVarToExtCallback, TwSummaryCallback _SummaryCallback, void *_ClientData, const char *_Help) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL ) { TwGlobalError(g_ErrNotInit); return TW_TYPE_UNDEF; // not initialized } if( _StructSize==0 || _StructExtInitCallback==NULL || _CopyVarFromExtCallback==NULL || _CopyVarToExtCallback==NULL ) { g_TwMgr->SetLastError(g_ErrBadParam); return TW_TYPE_UNDEF; } TwType type = TwDefineStruct(_StructName, _StructExtMembers, _NbExtMembers, _StructExtSize, _SummaryCallback, _ClientData); if( type>=TW_TYPE_STRUCT_BASE && typem_Structs.size() ) { CTwMgr::CStruct& s = g_TwMgr->m_Structs[type-TW_TYPE_STRUCT_BASE]; s.m_IsExt = true; s.m_ClientStructSize = _StructSize; s.m_StructExtInitCallback = _StructExtInitCallback; s.m_CopyVarFromExtCallback = _CopyVarFromExtCallback; s.m_CopyVarToExtCallback = _CopyVarToExtCallback; s.m_ExtClientData = _ClientData; if( _Help!=NULL ) s.m_Help = _Help; } return type; } // --------------------------------------------------------------------------- bool TwGetKeyCode(int *_Code, int *_Modif, const char *_String) { assert(_Code!=NULL && _Modif!=NULL); bool Ok = true; *_Modif = TW_KMOD_NONE; *_Code = 0; size_t Start = strlen(_String)-1; if( Start<0 ) return false; while( Start>0 && _String[Start-1]!='+' ) --Start; while( _String[Start]==' ' || _String[Start]=='\t' ) ++Start; char *CodeStr = _strdup(_String+Start); for( size_t i=strlen(CodeStr)-1; i>=0; ++i ) if( CodeStr[i]==' ' || CodeStr[i]=='\t' ) CodeStr[i] = '\0'; else break; /* if( strstr(_String, "SHIFT")!=NULL || strstr(_String, "shift")!=NULL ) *_Modif |= TW_KMOD_SHIFT; if( strstr(_String, "CTRL")!=NULL || strstr(_String, "ctrl")!=NULL ) *_Modif |= TW_KMOD_CTRL; if( strstr(_String, "META")!=NULL || strstr(_String, "meta")!=NULL ) *_Modif |= TW_KMOD_META; if( strstr(_String, "ALTGR")!=NULL || strstr(_String, "altgr")!=NULL ) ((void)(0)); // *_Modif |= TW_KMOD_ALTGR; else // ALT and ALTGR are exclusive if( strstr(_String, "ALT")!=NULL || strstr(_String, "alt")!=NULL ) *_Modif |= TW_KMOD_ALT; */ char *up = _strdup(_String); // _strupr(up); for( char *upch=up; *upch!='\0'; ++upch ) *upch = (char)toupper(*upch); if( strstr(up, "SHIFT")!=NULL ) *_Modif |= TW_KMOD_SHIFT; if( strstr(up, "CTRL")!=NULL ) *_Modif |= TW_KMOD_CTRL; if( strstr(up, "META")!=NULL ) *_Modif |= TW_KMOD_META; if( strstr(up, "ALTGR")!=NULL ) ((void)(0)); // *_Modif |= TW_KMOD_ALTGR; else // ALT and ALTGR are exclusive if( strstr(up, "ALT")!=NULL ) *_Modif |= TW_KMOD_ALT; free(up); if( strlen(CodeStr)==1 ) *_Code = (unsigned char)(CodeStr[0]); else if( _stricmp(CodeStr, "backspace")==0 || _stricmp(CodeStr, "bs")==0 ) *_Code = TW_KEY_BACKSPACE; else if( _stricmp(CodeStr, "tab")==0 ) *_Code = TW_KEY_TAB; else if( _stricmp(CodeStr, "clear")==0 || _stricmp(CodeStr, "clr")==0 ) *_Code = TW_KEY_CLEAR; else if( _stricmp(CodeStr, "return")==0 || _stricmp(CodeStr, "ret")==0 ) *_Code = TW_KEY_RETURN; else if( _stricmp(CodeStr, "pause")==0 ) *_Code = TW_KEY_PAUSE; else if( _stricmp(CodeStr, "escape")==0 || _stricmp(CodeStr, "esc")==0 ) *_Code = TW_KEY_ESCAPE; else if( _stricmp(CodeStr, "space")==0 ) *_Code = TW_KEY_SPACE; else if( _stricmp(CodeStr, "delete")==0 || _stricmp(CodeStr, "del")==0 ) *_Code = TW_KEY_DELETE; /* else if( strlen(CodeStr)==4 && CodeStr[3]>='0' && CodeStr[3]<='9' && (strstr(CodeStr, "pad")==CodeStr || strstr(CodeStr, "PAD")==CodeStr) ) *_Code = TW_KEY_PAD_0 + CodeStr[3]-'0'; else if( _stricmp(CodeStr, "pad.")==0 ) *_Code = TW_KEY_PAD_PERIOD; else if( _stricmp(CodeStr, "pad/")==0 ) *_Code = TW_KEY_PAD_DIVIDE; else if( _stricmp(CodeStr, "pad*")==0 ) *_Code = TW_KEY_PAD_MULTIPLY; else if( _stricmp(CodeStr, "pad+")==0 ) *_Code = TW_KEY_PAD_PLUS; else if( _stricmp(CodeStr, "pad-")==0 ) *_Code = TW_KEY_PAD_MINUS; else if( _stricmp(CodeStr, "padenter")==0 ) *_Code = TW_KEY_PAD_ENTER; else if( _stricmp(CodeStr, "pad=")==0 ) *_Code = TW_KEY_PAD_EQUALS; */ else if( _stricmp(CodeStr, "up")==0 ) *_Code = TW_KEY_UP; else if( _stricmp(CodeStr, "down")==0 ) *_Code = TW_KEY_DOWN; else if( _stricmp(CodeStr, "right")==0 ) *_Code = TW_KEY_RIGHT; else if( _stricmp(CodeStr, "left")==0 ) *_Code = TW_KEY_LEFT; else if( _stricmp(CodeStr, "insert")==0 || _stricmp(CodeStr, "ins")==0 ) *_Code = TW_KEY_INSERT; else if( _stricmp(CodeStr, "home")==0 ) *_Code = TW_KEY_HOME; else if( _stricmp(CodeStr, "end")==0 ) *_Code = TW_KEY_END; else if( _stricmp(CodeStr, "pgup")==0 ) *_Code = TW_KEY_PAGE_UP; else if( _stricmp(CodeStr, "pgdown")==0 ) *_Code = TW_KEY_PAGE_DOWN; else if( (strlen(CodeStr)==2 || strlen(CodeStr)==3) && (CodeStr[0]=='f' || CodeStr[0]=='F') ) { int n = 0; if( sscanf(CodeStr+1, "%d", &n)==1 && n>0 && n<16 ) *_Code = TW_KEY_F1 + n-1; else Ok = false; } free(CodeStr); return Ok; } bool TwGetKeyString(std::string *_String, int _Code, int _Modif) { assert(_String!=NULL); bool Ok = true; if( _Modif & TW_KMOD_SHIFT ) *_String += "SHIFT+"; if( _Modif & TW_KMOD_CTRL ) *_String += "CTRL+"; if ( _Modif & TW_KMOD_ALT ) *_String += "ALT+"; if ( _Modif & TW_KMOD_META ) *_String += "META+"; // if ( _Modif & TW_KMOD_ALTGR ) // *_String += "ALTGR+"; switch( _Code ) { case TW_KEY_BACKSPACE: *_String += "BackSpace"; break; case TW_KEY_TAB: *_String += "Tab"; break; case TW_KEY_CLEAR: *_String += "Clear"; break; case TW_KEY_RETURN: *_String += "Return"; break; case TW_KEY_PAUSE: *_String += "Pause"; break; case TW_KEY_ESCAPE: *_String += "Esc"; break; case TW_KEY_SPACE: *_String += "Space"; break; case TW_KEY_DELETE: *_String += "Delete"; break; /* case TW_KEY_PAD_0: *_String += "PAD0"; break; case TW_KEY_PAD_1: *_String += "PAD1"; break; case TW_KEY_PAD_2: *_String += "PAD2"; break; case TW_KEY_PAD_3: *_String += "PAD3"; break; case TW_KEY_PAD_4: *_String += "PAD4"; break; case TW_KEY_PAD_5: *_String += "PAD5"; break; case TW_KEY_PAD_6: *_String += "PAD6"; break; case TW_KEY_PAD_7: *_String += "PAD7"; break; case TW_KEY_PAD_8: *_String += "PAD8"; break; case TW_KEY_PAD_9: *_String += "PAD9"; break; case TW_KEY_PAD_PERIOD: *_String += "PAD."; break; case TW_KEY_PAD_DIVIDE: *_String += "PAD/"; break; case TW_KEY_PAD_MULTIPLY: *_String += "PAD*"; break; case TW_KEY_PAD_MINUS: *_String += "PAD-"; break; case TW_KEY_PAD_PLUS: *_String += "PAD+"; break; case TW_KEY_PAD_ENTER: *_String += "PADEnter"; break; case TW_KEY_PAD_EQUALS: *_String += "PAD="; break; */ case TW_KEY_UP: *_String += "Up"; break; case TW_KEY_DOWN: *_String += "Down"; break; case TW_KEY_RIGHT: *_String += "Right"; break; case TW_KEY_LEFT: *_String += "Left"; break; case TW_KEY_INSERT: *_String += "Insert"; break; case TW_KEY_HOME: *_String += "Home"; break; case TW_KEY_END: *_String += "End"; break; case TW_KEY_PAGE_UP: *_String += "PgUp"; break; case TW_KEY_PAGE_DOWN: *_String += "PgDown"; break; case TW_KEY_F1: *_String += "F1"; break; case TW_KEY_F2: *_String += "F2"; break; case TW_KEY_F3: *_String += "F3"; break; case TW_KEY_F4: *_String += "F4"; break; case TW_KEY_F5: *_String += "F5"; break; case TW_KEY_F6: *_String += "F6"; break; case TW_KEY_F7: *_String += "F7"; break; case TW_KEY_F8: *_String += "F8"; break; case TW_KEY_F9: *_String += "F9"; break; case TW_KEY_F10: *_String += "F10"; break; case TW_KEY_F11: *_String += "F11"; break; case TW_KEY_F12: *_String += "F12"; break; case TW_KEY_F13: *_String += "F13"; break; case TW_KEY_F14: *_String += "F14"; break; case TW_KEY_F15: *_String += "F15"; break; default: if( _Code>0 && _Code<256 ) *_String += char(_Code); else { *_String += "Unknown"; Ok = false; } } return Ok; } // --------------------------------------------------------------------------- const int TW_MOUSE_NOMOTION = -1; ETwMouseAction TW_MOUSE_MOTION = (ETwMouseAction)(-2); ETwMouseAction TW_MOUSE_WHEEL = (ETwMouseAction)(-3); ETwMouseButtonID TW_MOUSE_NA = (ETwMouseButtonID)(-1); static int TwMouseEvent(ETwMouseAction _EventType, TwMouseButtonID _Button, int _MouseX, int _MouseY, int _WheelPos) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL ) { // TwGlobalError(g_ErrNotInit); -> not an error here return 0; // not initialized } if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 ) { //g_TwMgr->SetLastError(g_ErrBadWndSize); // not an error, windows not yet ready. return 0; } // For multi-thread safety if( !TwFreeAsyncDrawing() ) return 0; if( _MouseX==TW_MOUSE_NOMOTION ) _MouseX = g_TwMgr->m_LastMouseX; else g_TwMgr->m_LastMouseX = _MouseX; if( _MouseY==TW_MOUSE_NOMOTION ) _MouseY = g_TwMgr->m_LastMouseY; else g_TwMgr->m_LastMouseY = _MouseY; // for autorepeat if( (!g_TwMgr->m_IsRepeatingMousePressed || !g_TwMgr->m_CanRepeatMousePressed) && _EventType==TW_MOUSE_PRESSED ) { g_TwMgr->m_LastMousePressedTime = g_TwMgr->m_Timer.GetTime(); g_TwMgr->m_LastMousePressedButtonID = _Button; g_TwMgr->m_LastMousePressedPosition[0] = _MouseX; g_TwMgr->m_LastMousePressedPosition[1] = _MouseY; g_TwMgr->m_CanRepeatMousePressed = true; g_TwMgr->m_IsRepeatingMousePressed = false; } else if( _EventType==TW_MOUSE_RELEASED || _EventType==TW_MOUSE_WHEEL ) { g_TwMgr->m_CanRepeatMousePressed = false; g_TwMgr->m_IsRepeatingMousePressed = false; } bool Handled = false; bool wasPopup = (g_TwMgr->m_PopupBar!=NULL); CTwBar *Bar = NULL; int i; // search for a bar with mousedrag enabled CTwBar *BarDragging = NULL; for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0; --i ) { Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]]; if( Bar!=NULL && Bar->m_Visible && Bar->IsDragging() ) { BarDragging = Bar; break; } } for( i=(int)g_TwMgr->m_Bars.size(); i>=0; --i ) { if( i==(int)g_TwMgr->m_Bars.size() ) // first try the bar with mousedrag enabled (this bar has the focus) Bar = BarDragging; else { Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]]; if( Bar==BarDragging ) continue; } if( Bar!=NULL && Bar->m_Visible ) { if( _EventType==TW_MOUSE_MOTION ) Handled = Bar->MouseMotion(_MouseX, _MouseY); else if( _EventType==TW_MOUSE_PRESSED || _EventType==TW_MOUSE_RELEASED ) Handled = Bar->MouseButton(_Button, (_EventType==TW_MOUSE_PRESSED), _MouseX, _MouseY); else if( _EventType==TW_MOUSE_WHEEL ) { if( abs(_WheelPos-g_TwMgr->m_LastMouseWheelPos)<4 ) // avoid crazy wheel positions Handled = Bar->MouseWheel(_WheelPos, g_TwMgr->m_LastMouseWheelPos, _MouseX, _MouseY); } if( Handled ) break; } } if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; /* if( i>=0 && Bar!=NULL && Handled && (_EventType==TW_MOUSE_PRESSED || Bar->IsMinimized()) && i!=((int)g_TwMgr->m_Bars.size())-1 ) { int iOrder = g_TwMgr->m_Order[i]; for( int j=i; j<(int)g_TwMgr->m_Bars.size()-1; ++j ) g_TwMgr->m_Order[j] = g_TwMgr->m_Order[j+1]; g_TwMgr->m_Order[(int)g_TwMgr->m_Bars.size()-1] = iOrder; } */ if( _EventType==TW_MOUSE_PRESSED || (Bar!=NULL && Bar->IsMinimized() && Handled) ) { if( wasPopup && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL ) // delete popup { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } if( i>=0 && Bar!=NULL && Handled && !wasPopup ) TwSetTopBar(Bar); } if( _EventType==TW_MOUSE_WHEEL ) g_TwMgr->m_LastMouseWheelPos = _WheelPos; return Handled ? 1 : 0; } int ANT_CALL TwMouseButton(ETwMouseAction _EventType, TwMouseButtonID _Button) { return TwMouseEvent(_EventType, _Button, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, 0); } int ANT_CALL TwMouseMotion(int _MouseX, int _MouseY) { return TwMouseEvent(TW_MOUSE_MOTION, TW_MOUSE_NA, _MouseX, _MouseY, 0); } int ANT_CALL TwMouseWheel(int _Pos) { return TwMouseEvent(TW_MOUSE_WHEEL, TW_MOUSE_NA, TW_MOUSE_NOMOTION, TW_MOUSE_NOMOTION, _Pos); } // --------------------------------------------------------------------------- static int TranslateKey(int _Key, int _Modifiers) { // CTRL special cases //if( (_Modifiers&TW_KMOD_CTRL) && !(_Modifiers&TW_KMOD_ALT || _Modifiers&TW_KMOD_META) && _Key>0 && _Key<32 ) // _Key += 'a'-1; if( (_Modifiers&TW_KMOD_CTRL) ) { if( _Key>='a' && _Key<='z' && ( ((_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS _Key += 'A'-'a'; else if ( _Key>='A' && _Key<='Z' && ( ((_Modifiers&0x2000) && (_Modifiers&TW_KMOD_SHIFT)) || (!(_Modifiers&0x2000) && !(_Modifiers&TW_KMOD_SHIFT)) )) // 0x2000 is SDL's KMOD_CAPS _Key += 'a'-'A'; } // PAD translation (for SDL keysym) if( _Key>=256 && _Key<=272 ) // 256=SDLK_KP0 ... 272=SDLK_KP_EQUALS { //bool Num = ((_Modifiers&TW_KMOD_SHIFT) && !(_Modifiers&0x1000)) || (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM //_Modifiers &= ~TW_KMOD_SHIFT; // remove shift modifier bool Num = (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM if( _Key==266 ) // SDLK_KP_PERIOD _Key = Num ? '.' : TW_KEY_DELETE; else if( _Key==267 ) // SDLK_KP_DIVIDE _Key = '/'; else if( _Key==268 ) // SDLK_KP_MULTIPLY _Key = '*'; else if( _Key==269 ) // SDLK_KP_MINUS _Key = '-'; else if( _Key==270 ) // SDLK_KP_PLUS _Key = '+'; else if( _Key==271 ) // SDLK_KP_ENTER _Key = TW_KEY_RETURN; else if( _Key==272 ) // SDLK_KP_EQUALS _Key = '='; else if( Num ) // num SDLK_KP0..9 _Key += '0' - 256; else if( _Key==256 ) // non-num SDLK_KP01 _Key = TW_KEY_INSERT; else if( _Key==257 ) // non-num SDLK_KP1 _Key = TW_KEY_END; else if( _Key==258 ) // non-num SDLK_KP2 _Key = TW_KEY_DOWN; else if( _Key==259 ) // non-num SDLK_KP3 _Key = TW_KEY_PAGE_DOWN; else if( _Key==260 ) // non-num SDLK_KP4 _Key = TW_KEY_LEFT; else if( _Key==262 ) // non-num SDLK_KP6 _Key = TW_KEY_RIGHT; else if( _Key==263 ) // non-num SDLK_KP7 _Key = TW_KEY_HOME; else if( _Key==264 ) // non-num SDLK_KP8 _Key = TW_KEY_UP; else if( _Key==265 ) // non-num SDLK_KP9 _Key = TW_KEY_PAGE_UP; } return _Key; } // --------------------------------------------------------------------------- static int KeyPressed(int _Key, int _Modifiers, bool _TestOnly) { CTwFPU fpu; // force fpu precision if( g_TwMgr==NULL || g_TwMgr->m_Graph==NULL ) { // TwGlobalError(g_ErrNotInit); -> not an error here return 0; // not initialized } if( g_TwMgr->m_WndHeight<=0 || g_TwMgr->m_WndWidth<=0 ) { //g_TwMgr->SetLastError(g_ErrBadWndSize); // not an error, windows not yet ready. return 0; } // For multi-thread savety if( !TwFreeAsyncDrawing() ) return 0; /* // Test for TwDeleteBar if( _Key>='0' && _Key<='9' ) { int n = _Key-'0'; if( (int)g_TwMgr->m_Bars.size()>n && g_TwMgr->m_Bars[n]!=NULL ) { printf("Delete %s\n", g_TwMgr->m_Bars[n]->m_Name.c_str()); TwDeleteBar(g_TwMgr->m_Bars[n]); } else printf("can't delete %d\n", n); return 1; } */ //char s[256]; //sprintf(s, "twkeypressed k=%d m=%x\n", _Key, _Modifiers); //OutputDebugString(s); _Key = TranslateKey(_Key, _Modifiers); if( _Key>' ' && _Key<256 ) // don't test SHIFT if _Key is a common key _Modifiers &= ~TW_KMOD_SHIFT; // complete partial modifiers comming from SDL if( _Modifiers & TW_KMOD_SHIFT ) _Modifiers |= TW_KMOD_SHIFT; if( _Modifiers & TW_KMOD_CTRL ) _Modifiers |= TW_KMOD_CTRL; if( _Modifiers & TW_KMOD_ALT ) _Modifiers |= TW_KMOD_ALT; if( _Modifiers & TW_KMOD_META ) _Modifiers |= TW_KMOD_META; bool Handled = false; CTwBar *Bar = NULL; CTwBar *PopupBar = g_TwMgr->m_PopupBar; //int Order = 0; int i; if( _Key>0 && _Keym_LastMouseX; int MouseY = g_TwMgr->m_LastMouseY; for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i ) { Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]]; if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized() && ( (MouseX>=Bar->m_PosX && MouseXm_PosX+Bar->m_Width && MouseY>=Bar->m_PosY && MouseYm_PosY+Bar->m_Height) || Bar==PopupBar) ) { if (_TestOnly) Handled = Bar->KeyTest(_Key, _Modifiers); else Handled = Bar->KeyPressed(_Key, _Modifiers); } } // If not handled, send it to non-iconified bars in the right order for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i ) { Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]]; /* for( size_t j=0; jm_Bars.size(); ++j ) if( g_TwMgr->m_Order[j]==i ) { Bar = g_TwMgr->m_Bars[j]; break; } Order = i; */ if( Bar!=NULL && Bar->m_Visible && !Bar->IsMinimized() ) { if( _TestOnly ) Handled = Bar->KeyTest(_Key, _Modifiers); else Handled = Bar->KeyPressed(_Key, _Modifiers); if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call return 1; } } // If not handled, send it to iconified bars in the right order for( i=((int)g_TwMgr->m_Bars.size())-1; i>=0 && !Handled; --i ) { Bar = g_TwMgr->m_Bars[g_TwMgr->m_Order[i]]; if( Bar!=NULL && Bar->m_Visible && Bar->IsMinimized() ) { if( _TestOnly ) Handled = Bar->KeyTest(_Key, _Modifiers); else Handled = Bar->KeyPressed(_Key, _Modifiers); } } if( g_TwMgr->m_HelpBar!=NULL && g_TwMgr->m_Graph && !_TestOnly ) { string Str; TwGetKeyString(&Str, _Key, _Modifiers); char Msg[256]; sprintf(Msg, "Key pressed: %s", Str.c_str()); g_TwMgr->m_KeyPressedStr = Msg; g_TwMgr->m_KeyPressedBuildText = true; // OutputDebugString(Msg); } } if( Handled && Bar!=g_TwMgr->m_PopupBar && g_TwMgr->m_PopupBar!=NULL && g_TwMgr->m_PopupBar==PopupBar ) // delete popup { TwDeleteBar(g_TwMgr->m_PopupBar); g_TwMgr->m_PopupBar = NULL; } if( Handled && Bar!=NULL && Bar!=g_TwMgr->m_PopupBar && Bar!=PopupBar ) // popup bar may have been destroyed TwSetTopBar(Bar); return Handled ? 1 : 0; } int ANT_CALL TwKeyPressed(int _Key, int _Modifiers) { return KeyPressed(_Key, _Modifiers, false); } int ANT_CALL TwKeyTest(int _Key, int _Modifiers) { return KeyPressed(_Key, _Modifiers, true); } // --------------------------------------------------------------------------- struct StructCompare : public binary_function { bool operator()(const TwType& _Left, const TwType& _Right) const { assert( g_TwMgr!=NULL ); int i0 = _Left-TW_TYPE_STRUCT_BASE; int i1 = _Right-TW_TYPE_STRUCT_BASE; if( i0>=0 && i0<(int)g_TwMgr->m_Structs.size() && i1>=0 && i1<(int)g_TwMgr->m_Structs.size() ) return g_TwMgr->m_Structs[i0].m_Name < g_TwMgr->m_Structs[i1].m_Name; else return false; } }; typedef set StructSet; static void InsertUsedStructs(StructSet& _Set, const CTwVarGroup *_Grp) { assert( g_TwMgr!=NULL && _Grp!=NULL ); for( size_t i=0; i<_Grp->m_Vars.size(); ++i ) if( _Grp->m_Vars[i]!=NULL && _Grp->m_Vars[i]->m_Visible && _Grp->m_Vars[i]->IsGroup() )// && _Grp->m_Vars[i]->m_Help.length()>0 ) { const CTwVarGroup *SubGrp = static_cast(_Grp->m_Vars[i]); if( SubGrp->m_StructValuePtr!=NULL && SubGrp->m_StructType>=TW_TYPE_STRUCT_BASE && SubGrp->m_StructTypem_Structs.size() && g_TwMgr->m_Structs[SubGrp->m_StructType-TW_TYPE_STRUCT_BASE].m_Name.length()>0 ) { if( SubGrp->m_Help.length()>0 ) _Set.insert(SubGrp->m_StructType); else { int idx = SubGrp->m_StructType - TW_TYPE_STRUCT_BASE; if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[idx].m_Name.length()>0 ) { for( size_t j=0; jm_Structs[idx].m_Members.size(); ++j ) if( g_TwMgr->m_Structs[idx].m_Members[j].m_Help.length()>0 ) { _Set.insert(SubGrp->m_StructType); break; } } } } InsertUsedStructs(_Set, SubGrp); } } static void SplitString(vector& _OutSplits, const char *_String, int _Width, const CTexFont *_Font) { assert( _Font!=NULL && _String!=NULL ); _OutSplits.resize(0); int l = (int)strlen(_String); if( l==0 ) { _String = " "; l = 1; } if( _String!=NULL && l>0 && _Width>0 ) { int w = 0; int i = 0; int First = 0; int Last = 0; bool PrevNotBlank = true; unsigned char c; bool Tab = false, CR = false; string Split; const string TabString(g_TabLength, ' '); while( im_CharWidth[(int)' ']; Tab = true; } else if( c=='\n' ) { w += _Width+1; // force split Last = i; CR = true; } else w += _Font->m_CharWidth[(int)c]; if( w>_Width || i==l-1 ) { if( Last<=First || i==l-1 ) Last = i; if( Tab ) { Split.resize(0); for(int k=0; km_HelpBar!=NULL); assert( _String!=NULL ); int n = 0; const CTexFont *Font = g_TwMgr->m_HelpBar->m_Font; assert(Font!=NULL); string Decal; for( int s=0; s<_Level; ++s ) Decal += ' '; int DecalWidth = (_Level+2)*Font->m_CharWidth[(int)' ']; if( _Width>DecalWidth ) { vector Split; SplitString(Split, _String, _Width-DecalWidth, Font); for( int i=0; i<(int)Split.size(); ++i ) { CTwVarAtom *Var = new CTwVarAtom; Var->m_Name = Decal + Split[i]; Var->m_Ptr = NULL; if( _Type==TW_TYPE_HELP_HEADER ) Var->m_ReadOnly = false; else Var->m_ReadOnly = true; Var->m_NoSlider = true; Var->m_DontClip = true; Var->m_Type = _Type; Var->m_LeftMargin = (signed short)((_Level+1)*Font->m_CharWidth[(int)' ']); Var->m_TopMargin = (signed short)(-g_TwMgr->m_HelpBar->m_Sep); //Var->m_TopMargin = 1; Var->m_ColorPtr = &(g_TwMgr->m_HelpBar->m_ColHelpText); Var->SetDefaults(); _Grp->m_Vars.push_back(Var); ++n; } } return n; } static int AppendHelp(CTwVarGroup *_Grp, const CTwVarGroup *_ToAppend, int _Level, int _Width) { assert( _Grp!=NULL ); assert( _ToAppend!=NULL ); int n = 0; string Decal; for( int s=0; s<_Level; ++s ) Decal += ' '; if( _ToAppend->m_Help.size()>0 ) n += AppendHelpString(_Grp, _ToAppend->m_Help.c_str(), _Level, _Width, TW_TYPE_HELP_GRP); for( size_t i=0; i<_ToAppend->m_Vars.size(); ++i ) if( _ToAppend->m_Vars[i]!=NULL && _ToAppend->m_Vars[i]->m_Visible ) { bool append = true; if( !_ToAppend->m_Vars[i]->IsGroup() ) { const CTwVarAtom *a = static_cast(_ToAppend->m_Vars[i]); if( a->m_Type==TW_TYPE_BUTTON && a->m_Val.m_Button.m_Callback==NULL ) append = false; else if( a->m_KeyIncr[0]==0 && a->m_KeyIncr[1]==0 && a->m_KeyDecr[0]==0 && a->m_KeyDecr[1]==0 && a->m_Help.length()<=0 ) append = false; } else if( _ToAppend->m_Vars[i]->IsGroup() && static_cast(_ToAppend->m_Vars[i])->m_StructValuePtr!=NULL // that's a struct var && _ToAppend->m_Vars[i]->m_Help.length()<=0 ) append = false; if( append ) { CTwVarAtom *Var = new CTwVarAtom; Var->m_Name = Decal; if( _ToAppend->m_Vars[i]->m_Label.size()>0 ) Var->m_Name += _ToAppend->m_Vars[i]->m_Label; else Var->m_Name += _ToAppend->m_Vars[i]->m_Name; Var->m_Ptr = NULL; if( _ToAppend->m_Vars[i]->IsGroup() && static_cast(_ToAppend->m_Vars[i])->m_StructValuePtr!=NULL ) { // That's a struct var Var->m_Type = TW_TYPE_HELP_STRUCT; Var->m_Val.m_HelpStruct.m_StructType = static_cast(_ToAppend->m_Vars[i])->m_StructType; Var->m_ReadOnly = true; Var->m_NoSlider = true; } else if( !_ToAppend->m_Vars[i]->IsGroup() ) { Var->m_Type = TW_TYPE_SHORTCUT; Var->m_Val.m_Shortcut.m_Incr[0] = static_cast(_ToAppend->m_Vars[i])->m_KeyIncr[0]; Var->m_Val.m_Shortcut.m_Incr[1] = static_cast(_ToAppend->m_Vars[i])->m_KeyIncr[1]; Var->m_Val.m_Shortcut.m_Decr[0] = static_cast(_ToAppend->m_Vars[i])->m_KeyDecr[0]; Var->m_Val.m_Shortcut.m_Decr[1] = static_cast(_ToAppend->m_Vars[i])->m_KeyDecr[1]; Var->m_ReadOnly = static_cast(_ToAppend->m_Vars[i])->m_ReadOnly; Var->m_NoSlider = true; } else { Var->m_Type = TW_TYPE_HELP_GRP; Var->m_DontClip = true; Var->m_LeftMargin = (signed short)((_Level+2)*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']); //Var->m_TopMargin = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight/2-2+2*(_Level-1)); Var->m_TopMargin = 2; if( Var->m_TopMargin>g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3 ) Var->m_TopMargin = (signed short)(g_TwMgr->m_HelpBar->m_Font->m_CharHeight-3); Var->m_ReadOnly = true; } Var->SetDefaults(); _Grp->m_Vars.push_back(Var); size_t VarIndex = _Grp->m_Vars.size()-1; ++n; if( _ToAppend->m_Vars[i]->IsGroup() && static_cast(_ToAppend->m_Vars[i])->m_StructValuePtr==NULL ) { int nAppended = AppendHelp(_Grp, static_cast(_ToAppend->m_Vars[i]), _Level+1, _Width); if( _Grp->m_Vars.size()==VarIndex+1 ) { delete _Grp->m_Vars[VarIndex]; _Grp->m_Vars.resize(VarIndex); } else n += nAppended; } else if( _ToAppend->m_Vars[i]->m_Help.length()>0 ) n += AppendHelpString(_Grp, _ToAppend->m_Vars[i]->m_Help.c_str(), _Level+1, _Width, TW_TYPE_HELP_ATOM); } } return n; } static void CopyHierarchy(CTwVarGroup *dst, const CTwVarGroup *src) { if( dst==NULL || src==NULL ) return; dst->m_Name = src->m_Name; dst->m_Open = src->m_Open; dst->m_Visible = src->m_Visible; dst->m_ColorPtr = src->m_ColorPtr; dst->m_DontClip = src->m_DontClip; dst->m_IsRoot = src->m_IsRoot; dst->m_LeftMargin = src->m_LeftMargin; dst->m_TopMargin = src->m_TopMargin; dst->m_Vars.resize(src->m_Vars.size()); for(size_t i=0; im_Vars.size(); ++i) if( src->m_Vars[i]!=NULL && src->m_Vars[i]->IsGroup() ) { CTwVarGroup *grp = new CTwVarGroup; CopyHierarchy(grp, static_cast(src->m_Vars[i])); dst->m_Vars[i] = grp; } else dst->m_Vars[i] = NULL; } // copy the 'open' flag from original hierarchy to current hierarchy static void SynchroHierarchy(CTwVarGroup *cur, const CTwVarGroup *orig) { if( cur==NULL || orig==NULL ) return; if( strcmp(cur->m_Name.c_str(), orig->m_Name.c_str())==0 ) cur->m_Open = orig->m_Open; size_t j = 0; while( jm_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) ) ++j; for(size_t i=0; im_Vars.size(); ++i) if( cur->m_Vars[i]!=NULL && cur->m_Vars[i]->IsGroup() && jm_Vars.size() && orig->m_Vars[j]!=NULL && orig->m_Vars[j]->IsGroup() ) { CTwVarGroup *curGrp = static_cast(cur->m_Vars[i]); const CTwVarGroup *origGrp = static_cast(orig->m_Vars[j]); if( strcmp(curGrp->m_Name.c_str(), origGrp->m_Name.c_str())==0 ) { curGrp->m_Open = origGrp->m_Open; SynchroHierarchy(curGrp, origGrp); ++j; while( jm_Vars.size() && (orig->m_Vars[j]==NULL || !orig->m_Vars[j]->IsGroup()) ) ++j; } } } void CTwMgr::UpdateHelpBar() { if( m_HelpBar==NULL || m_HelpBar->IsMinimized() ) return; if( !m_HelpBarUpdateNow && (float)m_Timer.GetTime()m_VarRoot); TwRemoveAllVars(m_HelpBar); if( m_HelpBar->m_UpToDate ) m_HelpBar->Update(); if( m_Help.size()>0 ) AppendHelpString(&(m_HelpBar->m_VarRoot), m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM); if( m_HelpBar->m_Help.size()>0 ) AppendHelpString(&(m_HelpBar->m_VarRoot), m_HelpBar->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM); AppendHelpString(&(m_HelpBar->m_VarRoot), "", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_HEADER); for( size_t ib=0; ibm_IsHelpBar) && m_Bars[ib]!=m_PopupBar && m_Bars[ib]->m_Visible ) { // Create a group CTwVarGroup *Grp = new CTwVarGroup; Grp->m_SummaryCallback = NULL; Grp->m_SummaryClientData = NULL; Grp->m_StructValuePtr = NULL; if( m_Bars[ib]->m_Label.size()<=0 ) Grp->m_Name = m_Bars[ib]->m_Name; else Grp->m_Name = m_Bars[ib]->m_Label; Grp->m_Open = true; Grp->m_ColorPtr = &(m_HelpBar->m_ColGrpText); m_HelpBar->m_VarRoot.m_Vars.push_back(Grp); if( m_Bars[ib]->m_Help.size()>0 ) AppendHelpString(Grp, m_Bars[ib]->m_Help.c_str(), 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_GRP); // Append variables (recursive) AppendHelp(Grp, &(m_Bars[ib]->m_VarRoot), 1, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0); // Append structures StructSet UsedStructs; InsertUsedStructs(UsedStructs, &(m_Bars[ib]->m_VarRoot)); CTwVarGroup *StructGrp = NULL; int MemberCount = 0; for( StructSet::iterator it=UsedStructs.begin(); it!=UsedStructs.end(); ++it ) { int idx = (*it) - TW_TYPE_STRUCT_BASE; if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() && g_TwMgr->m_Structs[idx].m_Name.length()>0 ) { if( StructGrp==NULL ) { StructGrp = new CTwVarGroup; StructGrp->m_StructType = TW_TYPE_HELP_STRUCT; // a special line background color will be used StructGrp->m_Name = "Structures"; StructGrp->m_Open = false; StructGrp->m_ColorPtr = &(m_HelpBar->m_ColStructText); //Grp->m_Vars.push_back(StructGrp); MemberCount = 0; } CTwVarAtom *Var = new CTwVarAtom; Var->m_Ptr = NULL; Var->m_Type = TW_TYPE_HELP_GRP; Var->m_DontClip = true; Var->m_LeftMargin = (signed short)(3*g_TwMgr->m_HelpBar->m_Font->m_CharWidth[(int)' ']); Var->m_TopMargin = 2; Var->m_ReadOnly = true; Var->m_NoSlider = true; Var->m_Name = '{'+g_TwMgr->m_Structs[idx].m_Name+'}'; StructGrp->m_Vars.push_back(Var); size_t structIndex = StructGrp->m_Vars.size()-1; if( g_TwMgr->m_Structs[idx].m_Help.size()>0 ) AppendHelpString(StructGrp, g_TwMgr->m_Structs[idx].m_Help.c_str(), 2, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0-2*Var->m_LeftMargin, TW_TYPE_HELP_ATOM); // Append struct members for( size_t im=0; imm_Structs[idx].m_Members.size(); ++im ) { if( g_TwMgr->m_Structs[idx].m_Members[im].m_Help.size()>0 ) { CTwVarAtom *Var = new CTwVarAtom; Var->m_Ptr = NULL; Var->m_Type = TW_TYPE_SHORTCUT; Var->m_Val.m_Shortcut.m_Incr[0] = 0; Var->m_Val.m_Shortcut.m_Incr[1] = 0; Var->m_Val.m_Shortcut.m_Decr[0] = 0; Var->m_Val.m_Shortcut.m_Decr[1] = 0; Var->m_ReadOnly = false; Var->m_NoSlider = true; if( g_TwMgr->m_Structs[idx].m_Members[im].m_Label.length()>0 ) Var->m_Name = " "+g_TwMgr->m_Structs[idx].m_Members[im].m_Label; else Var->m_Name = " "+g_TwMgr->m_Structs[idx].m_Members[im].m_Name; StructGrp->m_Vars.push_back(Var); //if( g_TwMgr->m_Structs[idx].m_Members[im].m_Help.size()>0 ) AppendHelpString(StructGrp, g_TwMgr->m_Structs[idx].m_Members[im].m_Help.c_str(), 3, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0-4*Var->m_LeftMargin, TW_TYPE_HELP_ATOM); } } if( StructGrp->m_Vars.size()==structIndex+1 ) // remove struct from help { delete StructGrp->m_Vars[structIndex]; StructGrp->m_Vars.resize(structIndex); } else ++MemberCount; } } if( StructGrp!=NULL ) { if( MemberCount==1 ) StructGrp->m_Name = "Structure"; if( StructGrp->m_Vars.size()>0 ) Grp->m_Vars.push_back(StructGrp); else { delete StructGrp; StructGrp = NULL; } } } // Append RotoSlider CTwVarGroup *RotoGrp = new CTwVarGroup; RotoGrp->m_SummaryCallback = NULL; RotoGrp->m_SummaryClientData = NULL; RotoGrp->m_StructValuePtr = NULL; RotoGrp->m_Name = "RotoSlider"; RotoGrp->m_Open = false; RotoGrp->m_ColorPtr = &(m_HelpBar->m_ColGrpText); m_HelpBar->m_VarRoot.m_Vars.push_back(RotoGrp); AppendHelpString(RotoGrp, "The RotoSlider allows rapid editing of numerical values.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM); AppendHelpString(RotoGrp, "To modify a numerical value, click on its label or on its roto [.] button, then move the mouse outside of the grey circle while keeping the mouse button pressed, and turn around the circle to increase or decrease the numerical value.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM); AppendHelpString(RotoGrp, "The two grey lines depict the min and max bounds.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM); AppendHelpString(RotoGrp, "Moving the mouse far form the circle allows precise increase or decrease, while moving near the circle allows fast increase or decrease.", 0, m_HelpBar->m_VarX2-m_HelpBar->m_VarX0, TW_TYPE_HELP_ATOM); SynchroHierarchy(&m_HelpBar->m_VarRoot, &prevHierarchy); m_HelpBarNotUpToDate = false; } // --------------------------------------------------------------------------- #if defined(ANT_WINDOWS) #include "res/TwXCursors.h" void CTwMgr::CreateCursors() { if( m_CursorsCreated ) return; m_CursorArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_ARROW)); m_CursorMove = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEALL)); m_CursorWE = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZEWE)); m_CursorNS = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENS)); m_CursorTopRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW)); m_CursorTopLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE)); m_CursorBottomLeft = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENESW)); m_CursorBottomRight = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_SIZENWSE)); m_CursorHelp = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HELP)); m_CursorCross = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS)); m_CursorUpArrow = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW)); m_CursorNo = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_NO)); m_CursorIBeam = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_IBEAM)); #ifdef IDC_HAND m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_HAND)); #else m_CursorHand = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_UPARROW)); #endif int cur; HMODULE hdll = GetModuleHandle(ANT_TWEAK_BAR_DLL); if( hdll==NULL ) g_UseCurRsc = false; // force the use of built-in cursors (not using resources) if( g_UseCurRsc ) m_CursorCenter = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+0)); else m_CursorCenter = PixmapCursor(0); if( m_CursorCenter==NULL ) m_CursorCenter = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS)); if( g_UseCurRsc ) m_CursorPoint = ::LoadCursor(hdll, MAKEINTRESOURCE(IDC_CURSOR1+1)); else m_CursorPoint = PixmapCursor(1); if( m_CursorPoint==NULL ) m_CursorPoint = ::LoadCursor(NULL ,MAKEINTRESOURCE(IDC_CROSS)); for( cur=0; cur>2) + y*8] |= (unsigned char)(g_CurPict[_CurIdx][x+y*32] << 2*(3-(x&3))+1); //turn whiteon data[(x>>2) + y*8] |= (unsigned char)(g_CurMask[_CurIdx][x+y*32] << 2*(3-(x&3))); //turn the alpha all the way up } //printf("\n"); } NSImage *img = [[NSImage alloc] initWithSize: [imgr size]]; [img addRepresentation: imgr]; NSCursor *cur = [[NSCursor alloc] initWithImage: img hotSpot: NSMakePoint(g_CurHot[_CurIdx][0],g_CurHot[_CurIdx][1])]; [imgr autorelease]; [img autorelease]; if (cur) return cur; else return [NSCursor arrowCursor]; } void CTwMgr::CreateCursors() { if (m_CursorsCreated) return; m_CursorArrow = [[NSCursor arrowCursor] retain]; m_CursorMove = [[NSCursor crosshairCursor] retain]; m_CursorWE = [[NSCursor resizeLeftRightCursor] retain]; m_CursorNS = [[NSCursor resizeUpDownCursor] retain]; m_CursorTopRight = [[NSCursor arrowCursor] retain]; //osx not have one m_CursorTopLeft = [[NSCursor arrowCursor] retain]; //osx not have one m_CursorBottomRight = [[NSCursor arrowCursor] retain]; //osx not have one m_CursorBottomLeft = [[NSCursor arrowCursor] retain]; //osx not have one m_CursorHelp = [[NSCursor arrowCursor] retain]; //osx not have one m_CursorHand = [[NSCursor pointingHandCursor] retain]; m_CursorCross = [[NSCursor arrowCursor] retain]; m_CursorUpArrow = [[NSCursor arrowCursor] retain]; m_CursorNo = [[NSCursor arrowCursor] retain]; m_CursorIBeam = [[NSCursor IBeamCursor] retain]; for (int i=0;ierror_code, err->request_code); // No exit! return 0 ; } static void IgnoreXErrors() { if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() ) { XFlush(g_TwMgr->m_CurrentXDisplay); XSync(g_TwMgr->m_CurrentXDisplay, False); } s_PrevErrorHandler = XSetErrorHandler(InactiveErrorHandler); } static void RestoreXErrors() { if( g_TwMgr!=NULL && g_TwMgr->m_CurrentXDisplay==glXGetCurrentDisplay() ) { XFlush(g_TwMgr->m_CurrentXDisplay); XSync(g_TwMgr->m_CurrentXDisplay, False); } XSetErrorHandler(s_PrevErrorHandler); } CTwMgr::CCursor CTwMgr::PixmapCursor(int _CurIdx) { if( !m_CurrentXDisplay || !m_CurrentXWindow ) return XC_left_ptr; IgnoreXErrors(); XColor black, white, exact; Colormap colmap = DefaultColormap(m_CurrentXDisplay, DefaultScreen(m_CurrentXDisplay)); Status s1 = XAllocNamedColor(m_CurrentXDisplay, colmap, "black", &black, &exact); Status s2 = XAllocNamedColor(m_CurrentXDisplay, colmap, "white", &white, &exact); if( s1==0 || s2==0 ) return XC_left_ptr; // cannot allocate colors! int x, y; unsigned int mask[32]; unsigned int pict[32]; for( y=0; y<32; ++y ) { mask[y] = pict[y] = 0; for( x=0; x<32; ++x ) { mask[y] |= (((unsigned int)(g_CurMask[_CurIdx][x+y*32]))<m_CurrentXDisplay ) { Window wnd = glXGetCurrentDrawable(); if( wnd!=g_TwMgr->m_CurrentXWindow ) { FreeCursors(); g_TwMgr->m_CurrentXWindow = wnd; CreateCursors(); // now _Cursor is not a valid cursor ID. } else { IgnoreXErrors(); XDefineCursor(m_CurrentXDisplay, m_CurrentXWindow, _Cursor); RestoreXErrors(); } } } } #endif //defined(ANT_UNIX) // --------------------------------------------------------------------------- void ANT_CALL TwCopyCDStringToClientFunc(TwCopyCDStringToClient copyCDStringToClientFunc) { g_InitCopyCDStringToClient = copyCDStringToClientFunc; if( g_TwMgr!=NULL ) g_TwMgr->m_CopyCDStringToClient = copyCDStringToClientFunc; } void ANT_CALL TwCopyCDStringToLibrary(char **destinationLibraryStringPtr, const char *sourceClientString) { if( g_TwMgr==NULL ) { if( destinationLibraryStringPtr!=NULL ) *destinationLibraryStringPtr = const_cast(sourceClientString); return; } // static buffer to store sourceClientString copy associated to sourceClientString pointer std::vector& Buf = g_TwMgr->m_CDStdStringCopyBuffers[(void *)sourceClientString]; size_t len = (sourceClientString!=NULL) ? strlen(sourceClientString) : 0; if( Buf.size()m_CopyStdStringToClient = copyStdStringToClientFunc; } void ANT_CALL TwCopyStdStringToLibrary(std::string& destLibraryString, const std::string& srcClientString) { /* // check if destLibraryString should be initialized char *Mem = (char *)&destLibraryString; bool Init = true; for( int i=0; i& Buf = g_TwMgr->m_CDStdStringCopyBuffers[(void *)&srcClientString]; size_t len = strlen(SrcStr); if( Buf.size()& _OutRects) const { if( Empty() ) return false; if( _Rect.Empty() || _Rect.Y>=Y+H || _Rect.Y+_Rect.H<=Y || _Rect.X>=X+W || _Rect.X+_Rect.W<=X ) { _OutRects.push_back(*this); return true; } bool Ret = false; int Y0 = Y; int Y1 = Y+H-1; if( _Rect.Y>Y ) { Y0 = _Rect.Y; _OutRects.push_back(CRect(X, Y, W, Y0-Y+1)); Ret = true; } if( _Rect.Y+_Rect.HX ) { X0 = _Rect.X; //-2; _OutRects.push_back(CRect(X, Y0, X0-X+1, Y1-Y0+1)); Ret = true; } if( _Rect.X+_Rect.W& _Rects, vector& _OutRects) const { _OutRects.clear(); size_t i, j, NbRects = _Rects.size(); if( NbRects==0 ) { _OutRects.push_back(*this); return true; } else { vector TmpRects; Subtract(_Rects[0], _OutRects); for( i=1; i #define ANT_CALL TW_CALL #include "TwColors.h" #include "TwFonts.h" #include "TwGraph.h" #include "AntPerfTimer.h" //#define BENCH // uncomment to activate benchmarks #ifdef BENCH # define PERF(cmd) cmd #else // BENCH # define PERF(cmd) #endif // BENCH const int NB_ROTO_CURSORS = 12; // --------------------------------------------------------------------------- // API unexposed by AntTweakBar.h // --------------------------------------------------------------------------- // bar states -> use TwDefine instead typedef enum ETwState { TW_STATE_SHOWN = 1, TW_STATE_ICONIFIED = 2, TW_STATE_HIDDEN = 3, TW_STATE_UNICONIFIED = 4, TW_STATE_ERROR = 0 } TwState; /*ANT_TWEAK_BAR_API*/ int ANT_CALL TwSetBarState(TwBar *bar, TwState state); /*ANT_TWEAK_BAR_API*/ //TwState ANT_CALL TwGetBarState(const TwBar *bar); // var states -> use TwDefine instead: visible/iconified implemented only as string commands //ANT_TWEAK_BAR_API int ANT_CALL TwSetVarState(TwBar *bar, const char *name, TwState state); //ANT_TWEAK_BAR_API TwState ANT_CALL TwGetVarState(const TwBar *bar, const char *name); struct CTwVarGroup; typedef void (ANT_CALL *TwStructExtInitCallback)(void *structExtValue, void *clientData); typedef void (ANT_CALL *TwCopyVarFromExtCallback)(void *structValue, const void *structExtValue, unsigned int structExtMemberIndex, void *clientData); typedef void (ANT_CALL *TwCopyVarToExtCallback)(const void *structValue, void *structExtValue, unsigned int structExtMemberIndex, void *clientData); /*ANT_TWEAK_BAR_API*/ TwType ANT_CALL TwDefineStructExt(const char *name, const TwStructMember *structExtMembers, unsigned int nbExtMembers, size_t structSize, size_t structExtSize, TwStructExtInitCallback structExtInitCallback, TwCopyVarFromExtCallback copyVarFromExtCallback, TwCopyVarToExtCallback copyVarToExtCallback, TwSummaryCallback summaryCallback, void *clientData, const char *help); typedef void (ANT_CALL *TwCustomDrawCallback)(int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp); typedef bool (ANT_CALL *TwCustomMouseMotionCallback)(int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp); typedef bool (ANT_CALL *TwCustomMouseButtonCallback)(TwMouseButtonID button, bool pressed, int mouseX, int mouseY, int w, int h, void *structExtValue, void *clientData, TwBar *bar, CTwVarGroup *varGrp); typedef void (ANT_CALL *TwCustomMouseLeaveCallback)(void *structExtValue, void *clientData, TwBar *bar); enum ERetType { RET_ERROR = 0, RET_DOUBLE, RET_STRING }; enum EButtonAlign { BUTTON_ALIGN_LEFT, BUTTON_ALIGN_CENTER, BUTTON_ALIGN_RIGHT }; // --------------------------------------------------------------------------- // AntTweakBar Manager // --------------------------------------------------------------------------- struct CTwMgr { ETwGraphAPI m_GraphAPI; void * m_Device; int m_WndID; class ITwGraph * m_Graph; int m_WndWidth; int m_WndHeight; const CTexFont * m_CurrentFont; std::vector m_Bars; std::vector m_Order; std::vector m_MinOccupied; void Minimize(TwBar *_Bar); void Maximize(TwBar *_Bar); void Hide(TwBar *_Bar); void Unhide(TwBar *_Bar); void SetFont(const CTexFont *_Font, bool _ResizeBars); int m_LastMouseX; int m_LastMouseY; int m_LastMouseWheelPos; int m_IconPos; // 0: bottom-left, 1:bottom-right, 2:top-left, 3:top-right int m_IconAlign; // 0: vertical, 1: horizontal int m_IconMarginX, m_IconMarginY; bool m_FontResizable; std::string m_BarAlwaysOnTop; std::string m_BarAlwaysOnBottom; bool m_UseOldColorScheme; bool m_Contained; EButtonAlign m_ButtonAlign; bool m_OverlapContent; bool m_Terminating; std::string m_Help; TwBar * m_HelpBar; float m_LastHelpUpdateTime; void UpdateHelpBar(); bool m_HelpBarNotUpToDate; bool m_HelpBarUpdateNow; void * m_KeyPressedTextObj; bool m_KeyPressedBuildText; std::string m_KeyPressedStr; float m_KeyPressedTime; void * m_InfoTextObj; bool m_InfoBuildText; int m_BarInitColorHue; int FindBar(const char *_Name) const; int HasAttrib(const char *_Attrib, bool *_HasValue) const; int SetAttrib(int _AttribID, const char *_Value); ERetType GetAttrib(int _AttribID, std::vector& outDouble, std::ostringstream& outString) const; void SetLastError(const char *_StaticErrorMesssage); // _StaticErrorMesssage must be a static string const char * GetLastError(); // returns a static string describing the error, and set LastError to NULL const char * CheckLastError() const; // returns the LastError, but does not set it to NULL void SetCurrentDbgParams(const char *file, int line); TwBar * m_PopupBar; //bool IsProcessing() const { return m_Processing); //void SetProcessing(bool processing) { m_Processing = processing; } CTwMgr(ETwGraphAPI _GraphAPI, void *_Device, int _WndID); ~CTwMgr(); struct CStructMember { std::string m_Name; std::string m_Label; TwType m_Type; size_t m_Offset; std::string m_DefString; size_t m_Size; std::string m_Help; }; struct CStruct { std::string m_Name; std::vector m_Members; size_t m_Size; TwSummaryCallback m_SummaryCallback; void * m_SummaryClientData; std::string m_Help; bool m_IsExt; size_t m_ClientStructSize; TwStructExtInitCallback m_StructExtInitCallback; TwCopyVarFromExtCallback m_CopyVarFromExtCallback; TwCopyVarToExtCallback m_CopyVarToExtCallback; void * m_ExtClientData; CStruct() : m_IsExt(false), m_StructExtInitCallback(NULL), m_CopyVarFromExtCallback(NULL), m_CopyVarToExtCallback(NULL), m_ExtClientData(NULL) {} static void ANT_CALL DefaultSummary(char *_SummaryString, size_t _SummaryMaxLength, const void *_Value, void *_ClientData); static void * s_PassProxyAsClientData; }; std::vector m_Structs; // followings are used for TwAddVarCB( ... StructType ... ) struct CStructProxy { TwType m_Type; void * m_StructData; bool m_DeleteStructData; void * m_StructExtData; TwSetVarCallback m_StructSetCallback; TwGetVarCallback m_StructGetCallback; void * m_StructClientData; TwCustomDrawCallback m_CustomDrawCallback; TwCustomMouseMotionCallback m_CustomMouseMotionCallback; TwCustomMouseButtonCallback m_CustomMouseButtonCallback; TwCustomMouseLeaveCallback m_CustomMouseLeaveCallback; bool m_CustomCaptureFocus; int m_CustomIndexFirst; int m_CustomIndexLast; CStructProxy(); ~CStructProxy(); }; struct CMemberProxy { CStructProxy * m_StructProxy; int m_MemberIndex; struct CTwVar * m_Var; struct CTwVarGroup * m_VarParent; CTwBar * m_Bar; CMemberProxy(); ~CMemberProxy(); static void ANT_CALL SetCB(const void *_Value, void *_ClientData); static void ANT_CALL GetCB(void *_Value, void *_ClientData); }; std::list m_StructProxies; // elements should not move std::list m_MemberProxies; // elements should not move //void InitVarData(TwType _Type, void *_Data, size_t _Size); //void UninitVarData(TwType _Type, void *_Data, size_t _Size); struct CEnum { std::string m_Name; typedef std::map CEntries; CEntries m_Entries; }; std::vector m_Enums; TwType m_TypeColor32; TwType m_TypeColor3F; TwType m_TypeColor4F; TwType m_TypeQuat4F; TwType m_TypeQuat4D; TwType m_TypeDir3F; TwType m_TypeDir3D; std::vector m_CSStringBuffer; struct CCDStdString { std::string * m_ClientStdStringPtr; char m_LocalString[sizeof(std::string)+2*sizeof(void*)]; //+2*sizeof(void*) because of VC++ std::string extra info in Debug TwSetVarCallback m_ClientSetCallback; TwGetVarCallback m_ClientGetCallback; void * m_ClientData; static void ANT_CALL SetCB(const void *_Value, void *_ClientData); static void ANT_CALL GetCB(void *_Value, void *_ClientData); }; std::list m_CDStdStrings; struct CClientStdString // Convertion between VC++ Debug/Release std::string { CClientStdString(); void FromLib(const char *libStr); std::string& ToClient(); private: char m_Data[sizeof(std::string)+2*sizeof(void *)]; std::string m_LibStr; }; struct CLibStdString // Convertion between VC++ Debug/Release std::string { CLibStdString(); void FromClient(const std::string& clientStr); std::string& ToLib(); private: char m_Data[sizeof(std::string)+2*sizeof(void *)]; }; struct CCDStdStringRecord { void * m_DataPtr; char m_PrevValue[sizeof(std::string)+2*sizeof(void*)]; CClientStdString m_ClientStdString; }; std::vector m_CDStdStringRecords; void UnrollCDStdString(std::vector& _Records, TwType _Type, void *_Data); void RestoreCDStdString(const std::vector& _Records); std::map > m_CDStdStringCopyBuffers; struct CCustom // custom var type { virtual ~CCustom() = 0; }; std::vector m_Customs; PerfTimer m_Timer; double m_LastMousePressedTime; TwMouseButtonID m_LastMousePressedButtonID; int m_LastMousePressedPosition[2]; double m_RepeatMousePressedDelay; double m_RepeatMousePressedPeriod; bool m_CanRepeatMousePressed; bool m_IsRepeatingMousePressed; double m_LastDrawTime; #if defined(ANT_WINDOWS) typedef HCURSOR CCursor; CCursor PixmapCursor(int _CurIdx); #elif defined(ANT_UNIX) typedef Cursor CCursor; CCursor PixmapCursor(int _CurIdx); Display * m_CurrentXDisplay; Window m_CurrentXWindow; #elif defined(ANT_OSX) typedef NSCursor * CCursor; CCursor PixmapCursor(int _CurIdx); #endif // defined(ANT_UNIX) bool m_CursorsCreated; void CreateCursors(); void FreeCursors(); void SetCursor(CCursor _Cursor); CCursor m_CursorArrow; CCursor m_CursorMove; CCursor m_CursorWE; CCursor m_CursorNS; CCursor m_CursorTopLeft; CCursor m_CursorTopRight; CCursor m_CursorBottomLeft; CCursor m_CursorBottomRight; CCursor m_CursorHelp; CCursor m_CursorHand; CCursor m_CursorCross; CCursor m_CursorUpArrow; CCursor m_CursorNo; CCursor m_CursorIBeam; CCursor m_RotoCursors[NB_ROTO_CURSORS]; CCursor m_CursorCenter; CCursor m_CursorPoint; TwCopyCDStringToClient m_CopyCDStringToClient; TwCopyStdStringToClient m_CopyStdStringToClient; size_t m_ClientStdStringStructSize; protected: int m_NbMinimizedBars; const char * m_LastError; const char * m_CurrentDbgFile; int m_CurrentDbgLine; //bool m_Processing; }; extern CTwMgr *g_TwMgr; // --------------------------------------------------------------------------- // Extra functions and TwTypes // --------------------------------------------------------------------------- bool TwGetKeyCode(int *_Code, int *_Modif, const char *_String); bool TwGetKeyString(std::string *_String, int _Code, int _Modif); const TwType TW_TYPE_SHORTCUT = TwType(0xfff1); const TwType TW_TYPE_HELP_GRP = TwType(0xfff2); const TwType TW_TYPE_HELP_ATOM = TwType(0xfff3); const TwType TW_TYPE_HELP_HEADER = TwType(0xfff4); const TwType TW_TYPE_HELP_STRUCT = TwType(0xfff5); const TwType TW_TYPE_BUTTON = TwType(0xfff6); const TwType TW_TYPE_CDSTDSTRING = TwType(0xfff7); const TwType TW_TYPE_STRUCT_BASE = TwType(0x10000000); const TwType TW_TYPE_ENUM_BASE = TwType(0x20000000); const TwType TW_TYPE_CSSTRING_BASE = TW_TYPE_CSSTRING(0); // defined as 0x30000000 (see AntTweakBar.h) const TwType TW_TYPE_CSSTRING_MAX = TW_TYPE_CSSTRING(0xfffffff); #define TW_CSSTRING_SIZE(type) ((int)((type)&0xfffffff)) const TwType TW_TYPE_CUSTOM_BASE = TwType(0x40000000); extern "C" int ANT_CALL TwSetLastError(const char *_StaticErrorMessage); const TwGraphAPI TW_OPENGL_CORE = (TwGraphAPI)5; // WIP (note: OpenGL Core Profil requires OpenGL 3.2 or later) // Clipping helper struct CRect { int X, Y, W, H; CRect() : X(0), Y(0), W(0), H(0) {} CRect(int _X, int _Y, int _W, int _H) : X(_X), Y(_Y), W(_W), H(_H) {} bool operator==(const CRect& _Rect) { return (Empty() && _Rect.Empty()) || (X==_Rect.X && Y==_Rect.Y && W==_Rect.W && H==_Rect.H); } bool Empty(int _Margin=0) const { return (W<=_Margin || H<=_Margin); } bool Subtract(const CRect& _Rect, std::vector& _OutRects) const; bool Subtract(const std::vector& _Rects, std::vector& _OutRects) const; }; // --------------------------------------------------------------------------- // Global bar attribs // --------------------------------------------------------------------------- enum EMgrAttribs { MGR_HELP = 1, MGR_FONT_SIZE, MGR_ICON_POS, MGR_ICON_ALIGN, MGR_ICON_MARGIN, MGR_FONT_RESIZABLE, MGR_COLOR_SCHEME, MGR_CONTAINED, MGR_BUTTON_ALIGN, MGR_OVERLAP }; // --------------------------------------------------------------------------- // Color struct ext // --------------------------------------------------------------------------- struct CColorExt { int R, G, B; int H, L, S; int A; bool m_HLS, m_HasAlpha, m_OGL; bool m_CanHaveAlpha; bool m_IsColorF; unsigned int m_PrevConvertedColor; CTwMgr::CStructProxy*m_StructProxy; void RGB2HLS(); void HLS2RGB(); static void ANT_CALL InitColor32CB(void *_ExtValue, void *_ClientData); static void ANT_CALL InitColor3FCB(void *_ExtValue, void *_ClientData); static void ANT_CALL InitColor4FCB(void *_ExtValue, void *_ClientData); static void ANT_CALL CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData); static void ANT_CALL CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData); static void ANT_CALL SummaryCB(char *_SummaryString, size_t _SummaryMaxLength, const void *_ExtValue, void *_ClientData); static void CreateTypes(); }; // --------------------------------------------------------------------------- // Quaternion struct ext // --------------------------------------------------------------------------- struct CQuaternionExt { double Qx, Qy, Qz, Qs; // Quat value double Vx, Vy, Vz, Angle; // Not used double Dx, Dy, Dz; // Dir value set when used as a direction bool m_AAMode; // Axis & angle mode -> disabled bool m_ShowVal; // Display values bool m_IsFloat; // Quat/Dir uses floats bool m_IsDir; // Mapped to a dir vector instead of a quat double m_Dir[3]; // If not zero, display one direction vector color32 m_DirColor; // Direction vector color float m_Permute[3][3]; // Permute frame axis CTwMgr::CStructProxy*m_StructProxy; static void ANT_CALL InitQuat4FCB(void *_ExtValue, void *_ClientData); static void ANT_CALL InitQuat4DCB(void *_ExtValue, void *_ClientData); static void ANT_CALL InitDir3FCB(void *_ExtValue, void *_ClientData); static void ANT_CALL InitDir3DCB(void *_ExtValue, void *_ClientData); static void ANT_CALL CopyVarFromExtCB(void *_VarValue, const void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData); static void ANT_CALL CopyVarToExtCB(const void *_VarValue, void *_ExtValue, unsigned int _ExtMemberIndex, void *_ClientData); static void ANT_CALL SummaryCB(char *_SummaryString, size_t _SummaryMaxLength, const void *_ExtValue, void *_ClientData); static void ANT_CALL DrawCB(int _W, int _H, void *_ExtValue, void *_ClientData, TwBar *_Bar, CTwVarGroup *varGrp); static bool ANT_CALL MouseMotionCB(int _MouseX, int _MouseY, int _W, int _H, void *_StructExtValue, void *_ClientData, TwBar *_Bar, CTwVarGroup *varGrp); static bool ANT_CALL MouseButtonCB(TwMouseButtonID _Button, bool _Pressed, int _MouseX, int _MouseY, int _W, int _H, void *_StructExtValue, void *_ClientData, TwBar *_Bar, CTwVarGroup *varGrp); static void ANT_CALL MouseLeaveCB(void *_StructExtValue, void *_ClientData, TwBar *_Bar); static void CreateTypes(); static TwType s_CustomType; void ConvertToAxisAngle(); void ConvertFromAxisAngle(); void CopyToVar(); static std::vector s_SphTri; static std::vector s_SphCol; static std::vector s_SphTriProj; static std::vector s_SphColLight; static std::vector s_ArrowTri[4]; static std::vector s_ArrowTriProj[4]; static std::vector s_ArrowNorm[4]; static std::vector s_ArrowColLight[4]; enum EArrowParts { ARROW_CONE, ARROW_CONE_CAP, ARROW_CYL, ARROW_CYL_CAP }; static void CreateSphere(); static void CreateArrow(); static void ApplyQuat(float *outX, float *outY, float *outZ, float x, float y, float z, float qx, float qy, float qz, float qs); static void QuatFromDir(double *outQx, double *outQy, double *outQz, double *outQs, double dx, double dy, double dz); inline void Permute(float *outX, float *outY, float *outZ, float x, float y, float z); inline void PermuteInv(float *outX, float *outY, float *outZ, float x, float y, float z); inline void Permute(double *outX, double *outY, double *outZ, double x, double y, double z); inline void PermuteInv(double *outX, double *outY, double *outZ, double x, double y, double z); bool m_Highlighted; bool m_Rotating; double m_OrigQuat[4]; float m_OrigX, m_OrigY; double m_PrevX, m_PrevY; }; // --------------------------------------------------------------------------- // CTwFPU objects set and restore the fpu precision if needed. // (could be useful because DirectX changes it and AntTweakBar requires default double precision) // --------------------------------------------------------------------------- struct CTwFPU { CTwFPU() { #ifdef ANT_WINDOWS state0 = _controlfp(0, 0); if( (state0&MCW_PC)==_PC_24 ) // we need at least _PC_53 _controlfp(_PC_53, MCW_PC); #else state0 = 0; #endif } ~CTwFPU() { #ifdef ANT_WINDOWS if( (state0&MCW_PC)==_PC_24 ) _controlfp(_PC_24, MCW_PC); #else state0 = 0; #endif } private: unsigned int state0; }; // --------------------------------------------------------------------------- #endif // !defined ANT_TW_MGR_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwOpenGL.cpp0000644000000000000000000007144712635011627024727 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwOpenGL.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // --------------------------------------------------------------------------- #include "TwPrecomp.h" #include "LoadOGL.h" #include "TwOpenGL.h" #include "TwMgr.h" using namespace std; const char *g_ErrCantLoadOGL = "Cannot load OpenGL library dynamically"; const char *g_ErrCantUnloadOGL = "Cannot unload OpenGL library"; GLuint g_SmallFontTexID = 0; GLuint g_NormalFontTexID = 0; GLuint g_LargeFontTexID = 0; // --------------------------------------------------------------------------- // Extensions typedef void (APIENTRY * PFNGLBindBufferARB)(GLenum target, GLuint buffer); typedef void (APIENTRY * PFNGLBindProgramARB)(GLenum target, GLuint program); typedef GLuint (APIENTRY * PFNGLGetHandleARB)(GLenum pname); typedef void (APIENTRY * PFNGLUseProgramObjectARB)(GLuint programObj); typedef void (APIENTRY * PFNGLTexImage3D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRY * PFNGLActiveTextureARB)(GLenum texture); typedef void (APIENTRY * PFNGLClientActiveTextureARB)(GLenum texture); typedef void (APIENTRY * PFNGLBlendEquation)(GLenum mode); typedef void (APIENTRY * PFNGLBlendEquationSeparate)(GLenum srcMode, GLenum dstMode); typedef void (APIENTRY * PFNGLBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); PFNGLBindBufferARB _glBindBufferARB = NULL; PFNGLBindProgramARB _glBindProgramARB = NULL; PFNGLGetHandleARB _glGetHandleARB = NULL; PFNGLUseProgramObjectARB _glUseProgramObjectARB = NULL; PFNGLTexImage3D _glTexImage3D = NULL; PFNGLActiveTextureARB _glActiveTextureARB = NULL; PFNGLClientActiveTextureARB _glClientActiveTextureARB = NULL; PFNGLBlendEquation _glBlendEquation = NULL; PFNGLBlendEquationSeparate _glBlendEquationSeparate = NULL; PFNGLBlendFuncSeparate _glBlendFuncSeparate = NULL; #ifndef GL_ARRAY_BUFFER_ARB # define GL_ARRAY_BUFFER_ARB 0x8892 #endif #ifndef GL_ELEMENT_ARRAY_BUFFER_ARB # define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 #endif #ifndef GL_ARRAY_BUFFER_BINDING_ARB # define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 #endif #ifndef GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB # define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 #endif #ifndef GL_VERTEX_PROGRAM_ARB # define GL_VERTEX_PROGRAM_ARB 0x8620 #endif #ifndef GL_FRAGMENT_PROGRAM_ARB # define GL_FRAGMENT_PROGRAM_ARB 0x8804 #endif #ifndef GL_PROGRAM_OBJECT_ARB # define GL_PROGRAM_OBJECT_ARB 0x8B40 #endif #ifndef GL_TEXTURE_3D # define GL_TEXTURE_3D 0x806F #endif #ifndef GL_TEXTURE0_ARB # define GL_TEXTURE0_ARB 0x84C0 #endif #ifndef GL_ACTIVE_TEXTURE_ARB # define GL_ACTIVE_TEXTURE_ARB 0x84E0 #endif #ifndef GL_CLIENT_ACTIVE_TEXTURE_ARB # define GL_CLIENT_ACTIVE_TEXTURE_ARB 0x84E1 #endif #ifndef GL_MAX_TEXTURE_UNITS_ARB # define GL_MAX_TEXTURE_UNITS_ARB 0x84E2 #endif #ifndef GL_MAX_TEXTURE_COORDS # define GL_MAX_TEXTURE_COORDS 0x8871 #endif #ifndef GL_TEXTURE_RECTANGLE_ARB # define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #endif #ifndef GL_FUNC_ADD # define GL_FUNC_ADD 0x8006 #endif #ifndef GL_BLEND_EQUATION # define GL_BLEND_EQUATION 0x8009 #endif #ifndef GL_BLEND_EQUATION_RGB # define GL_BLEND_EQUATION_RGB GL_BLEND_EQUATION #endif #ifndef GL_BLEND_EQUATION_ALPHA # define GL_BLEND_EQUATION_ALPHA 0x883D #endif #ifndef GL_BLEND_SRC_RGB # define GL_BLEND_SRC_RGB 0x80C9 #endif #ifndef GL_BLEND_DST_RGB # define GL_BLEND_DST_RGB 0x80C8 #endif #ifndef GL_BLEND_SRC_ALPHA # define GL_BLEND_SRC_ALPHA 0x80CB #endif #ifndef GL_BLEND_DST_ALPHA # define GL_BLEND_DST_ALPHA 0x80CA #endif // --------------------------------------------------------------------------- #ifdef _DEBUG static void CheckGLError(const char *file, int line, const char *func) { int err=0; char msg[256]; while( (err=_glGetError())!=0 ) { sprintf(msg, "%s(%d) : [%s] GL_ERROR=0x%x\n", file, line, func, err); #ifdef ANT_WINDOWS OutputDebugString(msg); #endif fprintf(stderr, msg); } } # ifdef __FUNCTION__ # define CHECK_GL_ERROR CheckGLError(__FILE__, __LINE__, __FUNCTION__) # else # define CHECK_GL_ERROR CheckGLError(__FILE__, __LINE__, "") # endif #else # define CHECK_GL_ERROR ((void)(0)) #endif // --------------------------------------------------------------------------- static GLuint BindFont(const CTexFont *_Font) { GLuint TexID = 0; _glGenTextures(1, &TexID); _glBindTexture(GL_TEXTURE_2D, TexID); _glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); _glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); _glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); _glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); _glPixelStorei(GL_UNPACK_ALIGNMENT, 1); _glPixelTransferf(GL_ALPHA_SCALE, 1); _glPixelTransferf(GL_ALPHA_BIAS, 0); _glPixelTransferf(GL_RED_BIAS, 1); _glPixelTransferf(GL_GREEN_BIAS, 1); _glPixelTransferf(GL_BLUE_BIAS, 1); _glTexImage2D(GL_TEXTURE_2D, 0, 4, _Font->m_TexWidth, _Font->m_TexHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, _Font->m_TexBytes); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); _glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); _glBindTexture(GL_TEXTURE_2D, 0); _glPixelTransferf(GL_ALPHA_BIAS, 0); _glPixelTransferf(GL_RED_BIAS, 0); _glPixelTransferf(GL_GREEN_BIAS, 0); _glPixelTransferf(GL_BLUE_BIAS, 0); return TexID; } static void UnbindFont(GLuint _FontTexID) { if( _FontTexID>0 ) _glDeleteTextures(1, &_FontTexID); } // --------------------------------------------------------------------------- int CTwGraphOpenGL::Init() { m_Drawing = false; m_FontTexID = 0; m_FontTex = NULL; m_MaxClipPlanes = -1; if( LoadOpenGL()==0 ) { g_TwMgr->SetLastError(g_ErrCantLoadOGL); return 0; } // Get extensions _glBindBufferARB = reinterpret_cast(_glGetProcAddress("glBindBufferARB")); _glBindProgramARB = reinterpret_cast(_glGetProcAddress("glBindProgramARB")); _glGetHandleARB = reinterpret_cast(_glGetProcAddress("glGetHandleARB")); _glUseProgramObjectARB = reinterpret_cast(_glGetProcAddress("glUseProgramObjectARB")); _glTexImage3D = reinterpret_cast(_glGetProcAddress("glTexImage3D")); _glActiveTextureARB = reinterpret_cast(_glGetProcAddress("glActiveTextureARB")); _glClientActiveTextureARB = reinterpret_cast(_glGetProcAddress("glClientActiveTextureARB")); _glBlendEquation = reinterpret_cast(_glGetProcAddress("glBlendEquation")); _glBlendEquationSeparate = reinterpret_cast(_glGetProcAddress("glBlendEquationSeparate")); _glBlendFuncSeparate = reinterpret_cast(_glGetProcAddress("glBlendFuncSeparate")); m_SupportTexRect = false; // updated in BeginDraw return 1; } // --------------------------------------------------------------------------- int CTwGraphOpenGL::Shut() { assert(m_Drawing==false); UnbindFont(m_FontTexID); int Res = 1; if( UnloadOpenGL()==0 ) { g_TwMgr->SetLastError(g_ErrCantUnloadOGL); Res = 0; } return Res; } // --------------------------------------------------------------------------- void CTwGraphOpenGL::BeginDraw(int _WndWidth, int _WndHeight) { assert(m_Drawing==false && _WndWidth>0 && _WndHeight>0); m_Drawing = true; m_WndWidth = _WndWidth; m_WndHeight = _WndHeight; CHECK_GL_ERROR; //#if !defined(ANT_OSX) static bool s_SupportTexRectChecked = false; if (!s_SupportTexRectChecked) { const char *ext = (const char *)_glGetString(GL_EXTENSIONS); if( ext!=0 && strlen(ext)>0 ) m_SupportTexRect = (strstr(ext, "GL_ARB_texture_rectangle")!=NULL); s_SupportTexRectChecked = true; } //#endif _glPushAttrib(GL_ALL_ATTRIB_BITS); _glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); if( _glActiveTextureARB ) { _glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &m_PrevActiveTextureARB); _glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &m_PrevClientActiveTextureARB); GLint maxTexUnits = 1; _glGetIntegerv(GL_MAX_TEXTURE_COORDS, &maxTexUnits); // was GL_MAX_TEXTURE_UNITS_ARB if( maxTexUnits<1 ) maxTexUnits = 1; else if( maxTexUnits > MAX_TEXTURES ) maxTexUnits = MAX_TEXTURES; GLint i; for( i=0; i0 && _WndHeight>0 ) { Vp[0] = 0; Vp[1] = 0; Vp[2] = _WndWidth; Vp[3] = _WndHeight; _glViewport(Vp[0], Vp[1], Vp[2], Vp[3]); } _glLoadIdentity(); //_glOrtho(Vp[0], Vp[0]+Vp[2]-1, Vp[1]+Vp[3]-1, Vp[1], -1, 1); // Doesn't work _glOrtho(Vp[0], Vp[0]+Vp[2], Vp[1]+Vp[3], Vp[1], -1, 1); */ if( _WndWidth>0 && _WndHeight>0 ) { Vp[0] = 0; Vp[1] = 0; Vp[2] = _WndWidth-1; Vp[3] = _WndHeight-1; _glViewport(Vp[0], Vp[1], Vp[2], Vp[3]); } _glLoadIdentity(); _glOrtho(Vp[0], Vp[0]+Vp[2], Vp[1]+Vp[3], Vp[1], -1, 1); _glGetIntegerv(GL_VIEWPORT, m_ViewportInit); _glGetFloatv(GL_PROJECTION_MATRIX, m_ProjMatrixInit); _glGetFloatv(GL_LINE_WIDTH, &m_PrevLineWidth); _glDisable(GL_POLYGON_STIPPLE); _glLineWidth(1); _glDisable(GL_LINE_SMOOTH); _glDisable(GL_LINE_STIPPLE); _glDisable(GL_CULL_FACE); _glDisable(GL_DEPTH_TEST); _glDisable(GL_LIGHTING); _glEnable(GL_BLEND); _glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); _glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &m_PrevTexEnv); _glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); _glGetIntegerv(GL_POLYGON_MODE, m_PrevPolygonMode); _glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); _glDisable(GL_ALPHA_TEST); //_glEnable(GL_ALPHA_TEST); //_glAlphaFunc(GL_GREATER, 0); _glDisable(GL_FOG); _glDisable(GL_LOGIC_OP); _glDisable(GL_SCISSOR_TEST); if( m_MaxClipPlanes<0 ) { _glGetIntegerv(GL_MAX_CLIP_PLANES, &m_MaxClipPlanes); if( m_MaxClipPlanes<0 || m_MaxClipPlanes>255 ) m_MaxClipPlanes = 6; } for( GLint i=0; i MAX_TEXTURES ) maxTexUnits = MAX_TEXTURES; GLint i; for( i=0; i_X1) ++_X0; if(_Y0<_Y1) ++_Y1; else if(_Y0>_Y1) ++_Y0; */ //const GLfloat dx = +0.0f; const GLfloat dx = +0.5f; //GLfloat dy = -0.2f; const GLfloat dy = -0.5f; if( _AntiAliased ) _glEnable(GL_LINE_SMOOTH); else _glDisable(GL_LINE_SMOOTH); _glDisable(GL_TEXTURE_2D); _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); _glBegin(GL_LINES); _glColor4ub(GLubyte(_Color0>>16), GLubyte(_Color0>>8), GLubyte(_Color0), GLubyte(_Color0>>24)); _glVertex2f((GLfloat)_X0+dx, (GLfloat)_Y0+dy); _glColor4ub(GLubyte(_Color1>>16), GLubyte(_Color1>>8), GLubyte(_Color1), GLubyte(_Color1>>24)); _glVertex2f((GLfloat)_X1+dx, (GLfloat)_Y1+dy); //_glVertex2i(_X0, _Y0); //_glVertex2i(_X1, _Y1); _glEnd(); _glDisable(GL_LINE_SMOOTH); } // --------------------------------------------------------------------------- void CTwGraphOpenGL::DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11) { assert(m_Drawing==true); /* // border adjustment if(_X0<_X1) ++_X1; else if(_X0>_X1) ++_X0; if(_Y0<_Y1) ++_Y1; else if(_Y0>_Y1) ++_Y0; */ // border adjustment if(_X0<_X1) ++_X1; else if(_X0>_X1) ++_X0; if(_Y0<_Y1) --_Y0; else if(_Y0>_Y1) --_Y1; const GLfloat dx = +0.0f; const GLfloat dy = +0.0f; _glDisable(GL_TEXTURE_2D); _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); //GLubyte r = GLubyte(_Color>>16); //GLubyte g = GLubyte(_Color>>8); //GLubyte b = GLubyte(_Color); //GLubyte a = GLubyte(_Color>>24); //_glColor4ub(GLubyte(_Color>>16), GLubyte(_Color>>8), GLubyte(_Color), GLubyte(_Color>>24)); //_glColor4ub(r, g, b, a); _glBegin(GL_QUADS); _glColor4ub(GLubyte(_Color00>>16), GLubyte(_Color00>>8), GLubyte(_Color00), GLubyte(_Color00>>24)); _glVertex2f((GLfloat)_X0+dx, (GLfloat)_Y0+dy); _glColor4ub(GLubyte(_Color10>>16), GLubyte(_Color10>>8), GLubyte(_Color10), GLubyte(_Color10>>24)); _glVertex2f((GLfloat)_X1+dx, (GLfloat)_Y0+dy); _glColor4ub(GLubyte(_Color11>>16), GLubyte(_Color11>>8), GLubyte(_Color11), GLubyte(_Color11>>24)); _glVertex2f((GLfloat)_X1+dx, (GLfloat)_Y1+dy); _glColor4ub(GLubyte(_Color01>>16), GLubyte(_Color01>>8), GLubyte(_Color01), GLubyte(_Color01>>24)); _glVertex2f((GLfloat)_X0+dx, (GLfloat)_Y1+dy); _glEnd(); } // --------------------------------------------------------------------------- void *CTwGraphOpenGL::NewTextObj() { return new CTextObj; } // --------------------------------------------------------------------------- void CTwGraphOpenGL::DeleteTextObj(void *_TextObj) { assert(_TextObj!=NULL); delete static_cast(_TextObj); } // --------------------------------------------------------------------------- void CTwGraphOpenGL::BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth) { assert(m_Drawing==true); assert(_TextObj!=NULL); assert(_Font!=NULL); if( _Font != m_FontTex ) { UnbindFont(m_FontTexID); m_FontTexID = BindFont(_Font); m_FontTex = _Font; } CTextObj *TextObj = static_cast(_TextObj); TextObj->m_TextVerts.resize(0); TextObj->m_TextUVs.resize(0); TextObj->m_BgVerts.resize(0); TextObj->m_Colors.resize(0); TextObj->m_BgColors.resize(0); int x, x1, y, y1, i, Len; unsigned char ch; const unsigned char *Text; color32 LineColor = COLOR32_RED; for( int Line=0; Line<_NbLines; ++Line ) { x = 0; y = Line * (_Font->m_CharHeight+_Sep); y1 = y+_Font->m_CharHeight; Len = (int)_TextLines[Line].length(); Text = (const unsigned char *)(_TextLines[Line].c_str()); if( _LineColors!=NULL ) LineColor = (_LineColors[Line]&0xff00ff00) | GLubyte(_LineColors[Line]>>16) | (GLubyte(_LineColors[Line])<<16); for( i=0; im_CharWidth[ch]; TextObj->m_TextVerts.push_back(Vec2(x , y )); TextObj->m_TextVerts.push_back(Vec2(x1, y )); TextObj->m_TextVerts.push_back(Vec2(x , y1)); TextObj->m_TextVerts.push_back(Vec2(x1, y )); TextObj->m_TextVerts.push_back(Vec2(x1, y1)); TextObj->m_TextVerts.push_back(Vec2(x , y1)); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV1[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch])); if( _LineColors!=NULL ) { TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); } x = x1; } if( _BgWidth>0 ) { TextObj->m_BgVerts.push_back(Vec2(-1 , y )); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y )); TextObj->m_BgVerts.push_back(Vec2(-1 , y1)); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y )); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y1)); TextObj->m_BgVerts.push_back(Vec2(-1 , y1)); if( _LineBgColors!=NULL ) { color32 LineBgColor = (_LineBgColors[Line]&0xff00ff00) | GLubyte(_LineBgColors[Line]>>16) | (GLubyte(_LineBgColors[Line])<<16); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); } } } } // --------------------------------------------------------------------------- void CTwGraphOpenGL::DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor) { assert(m_Drawing==true); assert(_TextObj!=NULL); CTextObj *TextObj = static_cast(_TextObj); if( TextObj->m_TextVerts.size()<4 && TextObj->m_BgVerts.size()<4 ) return; // nothing to draw _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); _glTranslatef((GLfloat)_X, (GLfloat)_Y, 0); _glEnableClientState(GL_VERTEX_ARRAY); if( (_BgColor!=0 || TextObj->m_BgColors.size()==TextObj->m_BgVerts.size()) && TextObj->m_BgVerts.size()>=4 ) { _glDisable(GL_TEXTURE_2D); _glVertexPointer(2, GL_FLOAT, 0, &(TextObj->m_BgVerts[0])); if( TextObj->m_BgColors.size()==TextObj->m_BgVerts.size() && _BgColor==0 ) { _glEnableClientState(GL_COLOR_ARRAY); _glColorPointer(4, GL_UNSIGNED_BYTE, 0, &(TextObj->m_BgColors[0])); } else { _glDisableClientState(GL_COLOR_ARRAY); _glColor4ub(GLubyte(_BgColor>>16), GLubyte(_BgColor>>8), GLubyte(_BgColor), GLubyte(_BgColor>>24)); } _glDrawArrays(GL_TRIANGLES, 0, (int)TextObj->m_BgVerts.size()); } _glEnable(GL_TEXTURE_2D); _glBindTexture(GL_TEXTURE_2D, m_FontTexID); _glEnableClientState(GL_TEXTURE_COORD_ARRAY); if( TextObj->m_TextVerts.size()>=4 ) { _glVertexPointer(2, GL_FLOAT, 0, &(TextObj->m_TextVerts[0])); _glTexCoordPointer(2, GL_FLOAT, 0, &(TextObj->m_TextUVs[0])); if( TextObj->m_Colors.size()==TextObj->m_TextVerts.size() && _Color==0 ) { _glEnableClientState(GL_COLOR_ARRAY); _glColorPointer(4, GL_UNSIGNED_BYTE, 0, &(TextObj->m_Colors[0])); } else { _glDisableClientState(GL_COLOR_ARRAY); _glColor4ub(GLubyte(_Color>>16), GLubyte(_Color>>8), GLubyte(_Color), GLubyte(_Color>>24)); } _glDrawArrays(GL_TRIANGLES, 0, (int)TextObj->m_TextVerts.size()); } _glDisableClientState(GL_VERTEX_ARRAY); _glDisableClientState(GL_TEXTURE_COORD_ARRAY); _glDisableClientState(GL_COLOR_ARRAY); } // --------------------------------------------------------------------------- void CTwGraphOpenGL::ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY) { if( _Width>0 && _Height>0 ) { GLint vp[4]; vp[0] = _X0; vp[1] = _Y0; vp[2] = _Width-1; vp[3] = _Height-1; _glViewport(vp[0], m_WndHeight-vp[1]-vp[3], vp[2], vp[3]); GLint matrixMode = 0; _glGetIntegerv(GL_MATRIX_MODE, &matrixMode); _glMatrixMode(GL_PROJECTION); _glLoadIdentity(); _glOrtho(_OffsetX, _OffsetX+vp[2], vp[3]-_OffsetY, -_OffsetY, -1, 1); _glMatrixMode(matrixMode); } } // --------------------------------------------------------------------------- void CTwGraphOpenGL::RestoreViewport() { _glViewport(m_ViewportInit[0], m_ViewportInit[1], m_ViewportInit[2], m_ViewportInit[3]); GLint matrixMode = 0; _glGetIntegerv(GL_MATRIX_MODE, &matrixMode); _glMatrixMode(GL_PROJECTION); _glLoadMatrixf(m_ProjMatrixInit); _glMatrixMode(matrixMode); } // --------------------------------------------------------------------------- void CTwGraphOpenGL::SetScissor(int _X0, int _Y0, int _Width, int _Height) { if( _Width>0 && _Height>0 ) { _glScissor(_X0-1, m_WndHeight-_Y0-_Height, _Width-1, _Height); _glEnable(GL_SCISSOR_TEST); } else _glDisable(GL_SCISSOR_TEST); } // --------------------------------------------------------------------------- void CTwGraphOpenGL::DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode) { assert(m_Drawing==true); const GLfloat dx = +0.0f; const GLfloat dy = +0.0f; GLint prevCullFaceMode, prevFrontFace; _glGetIntegerv(GL_CULL_FACE_MODE, &prevCullFaceMode); _glGetIntegerv(GL_FRONT_FACE, &prevFrontFace); GLboolean prevCullEnable = _glIsEnabled(GL_CULL_FACE); _glCullFace(GL_BACK); _glEnable(GL_CULL_FACE); if( _CullMode==CULL_CW ) _glFrontFace(GL_CCW); else if( _CullMode==CULL_CCW ) _glFrontFace(GL_CW); else _glDisable(GL_CULL_FACE); _glDisable(GL_TEXTURE_2D); _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); _glBegin(GL_TRIANGLES); for(int i=0; i<3*_NumTriangles; ++i) { color32 col = _Colors[i]; _glColor4ub(GLubyte(col>>16), GLubyte(col>>8), GLubyte(col), GLubyte(col>>24)); _glVertex2f((GLfloat)_Vertices[2*i+0]+dx, (GLfloat)_Vertices[2*i+1]+dy); } _glEnd(); _glCullFace(prevCullFaceMode); _glFrontFace(prevFrontFace); if( prevCullEnable ) _glEnable(GL_CULL_FACE); else _glDisable(GL_CULL_FACE); } // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwOpenGL.h0000644000000000000000000001037012635011627024360 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwOpenGL.h // @brief OpenGL graph functions // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // notes: Private header // TAB=4 // // --------------------------------------------------------------------------- #if !defined ANT_TW_OPENGL_INCLUDED #define ANT_TW_OPENGL_INCLUDED #include "TwGraph.h" // --------------------------------------------------------------------------- class CTwGraphOpenGL : public ITwGraph { public: virtual int Init(); virtual int Shut(); virtual void BeginDraw(int _WndWidth, int _WndHeight); virtual void EndDraw(); virtual bool IsDrawing(); virtual void Restore(); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased=false); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color, bool _AntiAliased=false) { DrawLine(_X0, _Y0, _X1, _Y1, _Color, _Color, _AntiAliased); } virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11); virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color) { DrawRect(_X0, _Y0, _X1, _Y1, _Color, _Color, _Color, _Color); } virtual void DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode); virtual void * NewTextObj(); virtual void DeleteTextObj(void *_TextObj); virtual void BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth); virtual void DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor); virtual void ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY); virtual void RestoreViewport(); virtual void SetScissor(int _X0, int _Y0, int _Width, int _Height); protected: bool m_Drawing; GLuint m_FontTexID; const CTexFont * m_FontTex; GLfloat m_PrevLineWidth; GLint m_PrevTexEnv; GLint m_PrevPolygonMode[2]; GLint m_MaxClipPlanes; GLint m_PrevTexture; GLint m_PrevArrayBufferARB; GLint m_PrevElementArrayBufferARB; GLboolean m_PrevVertexProgramARB; GLboolean m_PrevFragmentProgramARB; GLuint m_PrevProgramObjectARB; GLboolean m_PrevTexture3D; enum EMaxTextures { MAX_TEXTURES = 128 }; GLboolean m_PrevActiveTexture1D[MAX_TEXTURES]; GLboolean m_PrevActiveTexture2D[MAX_TEXTURES]; GLboolean m_PrevActiveTexture3D[MAX_TEXTURES]; GLboolean m_PrevClientTexCoordArray[MAX_TEXTURES]; GLint m_PrevActiveTextureARB; GLint m_PrevClientActiveTextureARB; bool m_SupportTexRect; GLboolean m_PrevTexRectARB; GLint m_PrevBlendEquation; GLint m_PrevBlendEquationRGB; GLint m_PrevBlendEquationAlpha; GLint m_PrevBlendSrcRGB; GLint m_PrevBlendDstRGB; GLint m_PrevBlendSrcAlpha; GLint m_PrevBlendDstAlpha; GLint m_ViewportInit[4]; GLfloat m_ProjMatrixInit[16]; int m_WndWidth; int m_WndHeight; struct Vec2 { GLfloat x, y; Vec2(){} Vec2(GLfloat _X, GLfloat _Y):x(_X),y(_Y){} Vec2(int _X, int _Y):x(GLfloat(_X)),y(GLfloat(_Y)){} }; struct CTextObj { std::vector m_TextVerts; std::vector m_TextUVs; std::vector m_BgVerts; std::vectorm_Colors; std::vectorm_BgColors; }; }; // --------------------------------------------------------------------------- #endif // !defined ANT_TW_OPENGL_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwOpenGLCore.cpp0000644000000000000000000006217412635011627025535 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwOpenGLCore.cpp // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Work In Progress // // --------------------------------------------------------------------------- #pragma warning GL3 #define GL3_PROTOTYPES 1 //// #include //// #define ANT_OGL_HEADER_INCLUDED //// #include "TwPrecomp.h" #include "LoadOGLCore.h" #include "TwOpenGLCore.h" #include "TwMgr.h" using namespace std; extern const char *g_ErrCantLoadOGL; extern const char *g_ErrCantUnloadOGL; // --------------------------------------------------------------------------- #ifdef _DEBUG static void CheckGLCoreError(const char *file, int line, const char *func) { int err=0; char msg[256]; while( (err=_glGetError())!=0 ) { sprintf(msg, "%s(%d) : [%s] GL_CORE_ERROR=0x%x\n", file, line, func, err); #ifdef ANT_WINDOWS OutputDebugString(msg); #endif fprintf(stderr, msg); } } # ifdef __FUNCTION__ # define CHECK_GL_ERROR CheckGLCoreError(__FILE__, __LINE__, __FUNCTION__) # else # define CHECK_GL_ERROR CheckGLCoreError(__FILE__, __LINE__, "") # endif #else # define CHECK_GL_ERROR ((void)(0)) #endif // --------------------------------------------------------------------------- static GLuint BindFont(const CTexFont *_Font) { GLuint TexID = 0; /* _glGenTextures(1, &TexID); _glBindTexture(GL_TEXTURE_2D, TexID); _glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); _glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); _glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); _glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); _glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); _glPixelStorei(GL_UNPACK_ALIGNMENT, 1); _glPixelTransferf(GL_ALPHA_SCALE, 1); _glPixelTransferf(GL_ALPHA_BIAS, 0); _glPixelTransferf(GL_RED_BIAS, 1); _glPixelTransferf(GL_GREEN_BIAS, 1); _glPixelTransferf(GL_BLUE_BIAS, 1); _glTexImage2D(GL_TEXTURE_2D, 0, 4, _Font->m_TexWidth, _Font->m_TexHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, _Font->m_TexBytes); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST); _glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST); _glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); _glBindTexture(GL_TEXTURE_2D, 0); _glPixelTransferf(GL_ALPHA_BIAS, 0); _glPixelTransferf(GL_RED_BIAS, 0); _glPixelTransferf(GL_GREEN_BIAS, 0); _glPixelTransferf(GL_BLUE_BIAS, 0); */ return TexID; } static void UnbindFont(GLuint _FontTexID) { /* if( _FontTexID>0 ) _glDeleteTextures(1, &_FontTexID); */ } // --------------------------------------------------------------------------- int CTwGraphOpenGLCore::Init() { m_Drawing = false; m_FontTexID = 0; m_FontTex = NULL; if( LoadOpenGLCore()==0 ) { g_TwMgr->SetLastError(g_ErrCantLoadOGL); return 0; } /* m_MaxClipPlanes = -1; // Get extensions _glBindBufferARB = reinterpret_cast(_glGetProcAddress("glBindBufferARB")); _glBindProgramARB = reinterpret_cast(_glGetProcAddress("glBindProgramARB")); _glGetHandleARB = reinterpret_cast(_glGetProcAddress("glGetHandleARB")); _glUseProgramObjectARB = reinterpret_cast(_glGetProcAddress("glUseProgramObjectARB")); _glTexImage3D = reinterpret_cast(_glGetProcAddress("glTexImage3D")); _glActiveTextureARB = reinterpret_cast(_glGetProcAddress("glActiveTextureARB")); _glClientActiveTextureARB = reinterpret_cast(_glGetProcAddress("glClientActiveTextureARB")); _glBlendEquation = reinterpret_cast(_glGetProcAddress("glBlendEquation")); _glBlendEquationSeparate = reinterpret_cast(_glGetProcAddress("glBlendEquationSeparate")); _glBlendFuncSeparate = reinterpret_cast(_glGetProcAddress("glBlendFuncSeparate")); #if !defined(ANT_OSX) const char *ext = (const char *)_glGetString(GL_EXTENSIONS); if( ext!=0 && strlen(ext)>0 ) m_SupportTexRect = (strstr(ext, "GL_ARB_texture_rectangle")!=NULL); else #endif m_SupportTexRect = false; */ // Create shaders const GLchar *lineRectVS[] = { "#version 150 core\n" "in vec3 vertex;" "void main() { gl_Position = vec4(vertex, 1); }" }; m_LineRectVS = _glCreateShader(GL_VERTEX_SHADER); _glShaderSource(m_LineRectVS, 1, lineRectVS, NULL); _glCompileShader(m_LineRectVS); const GLchar *lineRectFS[] = { "#version 150 core\n" "out vec4 color;" "void main() { color = vec4(1, 0, 1, 1); }" }; m_LineRectFS = _glCreateShader(GL_FRAGMENT_SHADER); _glShaderSource(m_LineRectFS, 1, lineRectFS, NULL); _glCompileShader(m_LineRectFS); m_LineRectProgram = _glCreateProgram(); _glAttachShader(m_LineRectProgram, m_LineRectVS); _glAttachShader(m_LineRectProgram, m_LineRectFS); _glLinkProgram(m_LineRectProgram); // Create line/rect vertex buffer const GLfloat lineRectInitBuffer[] = { 0,0,0, 0,0,0, 0,0,0, 0,0,0 }; _glGenVertexArrays(1, &m_LineRectVArray); _glBindVertexArray(m_LineRectVArray); _glGenBuffers(1, &m_LineRectBuffer); _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectBuffer); _glBufferData(GL_ARRAY_BUFFER, sizeof(lineRectInitBuffer), lineRectInitBuffer, GL_DYNAMIC_DRAW); CHECK_GL_ERROR; return 1; } // --------------------------------------------------------------------------- int CTwGraphOpenGLCore::Shut() { assert(m_Drawing==false); UnbindFont(m_FontTexID); int Res = 1; if( UnloadOpenGLCore()==0 ) { g_TwMgr->SetLastError(g_ErrCantUnloadOGL); Res = 0; } return Res; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::BeginDraw(int _WndWidth, int _WndHeight) { assert(m_Drawing==false && _WndWidth>0 && _WndHeight>0); m_Drawing = true; m_WndWidth = _WndWidth; m_WndHeight = _WndHeight; m_OffsetX = 0; m_OffsetY = 0; CHECK_GL_ERROR; //_glPushAttrib(GL_ALL_ATTRIB_BITS); //_glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); /* _glGetIntegerv(GL_ACTIVE_TEXTURE, &m_PrevActiveTexture); GLint maxTexUnits = 1; _glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTexUnits); if( maxTexUnits<1 ) maxTexUnits = 1; else if( maxTexUnits > 32 ) maxTexUnits = 32; for( GLint i=0; i0 && _WndHeight>0 ) { Vp[0] = 0; Vp[1] = 0; Vp[2] = _WndWidth-1; Vp[3] = _WndHeight-1; _glViewport(Vp[0], Vp[1], Vp[2], Vp[3]); } _glGetIntegerv(GL_VIEWPORT, m_ViewportInit); _glGetFloatv(GL_LINE_WIDTH, &m_PrevLineWidth); _glLineWidth(1); _glDisable(GL_LINE_SMOOTH); _glDisable(GL_CULL_FACE); _glDisable(GL_DEPTH_TEST); _glEnable(GL_BLEND); _glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); _glDisable(GL_SCISSOR_TEST); m_PrevTexture = 0; _glGetIntegerv(GL_TEXTURE_BINDING_2D, &m_PrevTexture); /* _glDisableClientState(GL_VERTEX_ARRAY); _glDisableClientState(GL_NORMAL_ARRAY); _glDisableClientState(GL_TEXTURE_COORD_ARRAY); _glDisableClientState(GL_INDEX_ARRAY); _glDisableClientState(GL_COLOR_ARRAY); _glDisableClientState(GL_EDGE_FLAG_ARRAY); if( _glBindBuffer!=NULL ) { m_PrevArrayBufferARB = m_PrevElementArrayBufferARB = 0; _glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &m_PrevArrayBufferARB); _glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &m_PrevElementArrayBufferARB); _glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); _glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } if( _glBindProgramARB!=NULL ) { m_PrevVertexProgramARB = _glIsEnabled(GL_VERTEX_PROGRAM_ARB); m_PrevFragmentProgramARB = _glIsEnabled(GL_FRAGMENT_PROGRAM_ARB); _glDisable(GL_VERTEX_PROGRAM_ARB); _glDisable(GL_FRAGMENT_PROGRAM_ARB); } if( _glGetHandleARB!=NULL && _glUseProgramObjectARB!=NULL ) { m_PrevProgramObjectARB = _glGetHandleARB(GL_PROGRAM_OBJECT_ARB); _glUseProgramObjectARB(0); } */ /* _glDisable(GL_TEXTURE_1D); _glDisable(GL_TEXTURE_2D); m_PrevTexture3D = _glIsEnabled(GL_TEXTURE_3D); _glDisable(GL_TEXTURE_3D); m_PrevTexRect = _glIsEnabled(GL_TEXTURE_RECTANGLE); _glDisable(GL_TEXTURE_RECTANGLE); if( _glBlendEquationSeparate!=NULL ) { _glGetIntegerv(GL_BLEND_EQUATION_RGB, &m_PrevBlendEquationRGB); _glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &m_PrevBlendEquationAlpha); _glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); } if( _glBlendFuncSeparate!=NULL ) { _glGetIntegerv(GL_BLEND_SRC_RGB, &m_PrevBlendSrcRGB); _glGetIntegerv(GL_BLEND_DST_RGB, &m_PrevBlendDstRGB); _glGetIntegerv(GL_BLEND_SRC_ALPHA, &m_PrevBlendSrcAlpha); _glGetIntegerv(GL_BLEND_DST_ALPHA, &m_PrevBlendDstAlpha); _glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } if( _glBlendEquation!=NULL ) { _glGetIntegerv(GL_BLEND_EQUATION, &m_PrevBlendEquation); _glBlendEquation(GL_FUNC_ADD); } */ CHECK_GL_ERROR; // _glUseProgram(m_LineRectProgram); // GLint projLoc = _glGetUniformLocation(m_LineRectProgram, "proj"); // _glUniformMatrix4fv(projLoc, 1, false, proj); CHECK_GL_ERROR; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::EndDraw() { assert(m_Drawing==true); m_Drawing = false; /* _glBindTexture(GL_TEXTURE_2D, m_PrevTexture); if( _glBindBufferARB!=NULL ) { _glBindBufferARB(GL_ARRAY_BUFFER_ARB, m_PrevArrayBufferARB); _glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, m_PrevElementArrayBufferARB); } if( _glBindProgramARB!=NULL ) { if( m_PrevVertexProgramARB ) _glEnable(GL_VERTEX_PROGRAM_ARB); if( m_PrevFragmentProgramARB ) _glEnable(GL_FRAGMENT_PROGRAM_ARB); } if( _glGetHandleARB!=NULL && _glUseProgramObjectARB!=NULL ) _glUseProgramObjectARB(m_PrevProgramObjectARB); if( _glTexImage3D!=NULL && m_PrevTexture3D ) _glEnable(GL_TEXTURE_3D); if( m_SupportTexRect && m_PrevTexRectARB ) _glEnable(GL_TEXTURE_RECTANGLE_ARB); if( _glBlendEquation!=NULL ) _glBlendEquation(m_PrevBlendEquation); if( _glBlendEquationSeparate!=NULL ) _glBlendEquationSeparate(m_PrevBlendEquationRGB, m_PrevBlendEquationAlpha); if( _glBlendFuncSeparate!=NULL ) _glBlendFuncSeparate(m_PrevBlendSrcRGB, m_PrevBlendDstRGB, m_PrevBlendSrcAlpha, m_PrevBlendDstAlpha); _glPolygonMode(GL_FRONT, m_PrevPolygonMode[0]); _glPolygonMode(GL_BACK, m_PrevPolygonMode[1]); _glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, m_PrevTexEnv); _glLineWidth(m_PrevLineWidth); _glMatrixMode(GL_PROJECTION); _glPopMatrix(); _glMatrixMode(GL_MODELVIEW); _glPopMatrix(); _glMatrixMode(GL_TEXTURE); _glPopMatrix(); _glPopClientAttrib(); _glPopAttrib(); if( _glActiveTextureARB ) { GLint maxTexUnits = 1; _glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTexUnits); if( maxTexUnits<1 ) maxTexUnits = 1; else if( maxTexUnits > 32 ) maxTexUnits = 32; for( GLint i=0; i>16) & 0xff) | ((col<<16) & 0xff0000); } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased) { assert(m_Drawing==true); /* //const GLfloat dx = +0.0f; const GLfloat dx = +0.5f; //GLfloat dy = -0.2f; const GLfloat dy = -0.5f; if( _AntiAliased ) _glEnable(GL_LINE_SMOOTH); else _glDisable(GL_LINE_SMOOTH); _glDisable(GL_TEXTURE_2D); _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); _glBegin(GL_LINES); _glColor4ub(GLubyte(_Color0>>16), GLubyte(_Color0>>8), GLubyte(_Color0), GLubyte(_Color0>>24)); _glVertex2f((GLfloat)_X0+dx, (GLfloat)_Y0+dy); _glColor4ub(GLubyte(_Color1>>16), GLubyte(_Color1>>8), GLubyte(_Color1), GLubyte(_Color1>>24)); _glVertex2f((GLfloat)_X1+dx, (GLfloat)_Y1+dy); //_glVertex2i(_X0, _Y0); //_glVertex2i(_X1, _Y1); _glEnd(); _glDisable(GL_LINE_SMOOTH); */ GLfloat x0 = ToNormScreenX(_X0 + m_OffsetX, m_WndWidth); GLfloat y0 = ToNormScreenY(_Y0 + m_OffsetY, m_WndHeight); GLfloat x1 = ToNormScreenX(_X1 + m_OffsetX, m_WndWidth); GLfloat y1 = ToNormScreenY(_Y1 + m_OffsetY, m_WndHeight); GLfloat vertices[] = { x0, y0, 0, x1, y1, 0 }; _glBindBuffer(GL_ARRAY_BUFFER, m_LineRectBuffer); _glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); _glUseProgram(m_LineRectProgram); _glBindVertexArray(m_LineRectVArray); GLint vlocation = _glGetAttribLocation(m_LineRectProgram, "vertex"); _glVertexAttribPointer(vlocation, 3, GL_FLOAT, GL_TRUE, 0, NULL); _glEnableVertexAttribArray(vlocation); _glDrawArrays(GL_LINES, 0, 2); CHECK_GL_ERROR; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11) { assert(m_Drawing==true); /* // border adjustment if(_X0<_X1) ++_X1; else if(_X0>_X1) ++_X0; if(_Y0<_Y1) --_Y0; else if(_Y0>_Y1) --_Y1; const GLfloat dx = +0.0f; const GLfloat dy = +0.0f; _glDisable(GL_TEXTURE_2D); _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); //GLubyte r = GLubyte(_Color>>16); //GLubyte g = GLubyte(_Color>>8); //GLubyte b = GLubyte(_Color); //GLubyte a = GLubyte(_Color>>24); //_glColor4ub(GLubyte(_Color>>16), GLubyte(_Color>>8), GLubyte(_Color), GLubyte(_Color>>24)); //_glColor4ub(r, g, b, a); _glBegin(GL_QUADS); _glColor4ub(GLubyte(_Color00>>16), GLubyte(_Color00>>8), GLubyte(_Color00), GLubyte(_Color00>>24)); _glVertex2f((GLfloat)_X0+dx, (GLfloat)_Y0+dy); _glColor4ub(GLubyte(_Color10>>16), GLubyte(_Color10>>8), GLubyte(_Color10), GLubyte(_Color10>>24)); _glVertex2f((GLfloat)_X1+dx, (GLfloat)_Y0+dy); _glColor4ub(GLubyte(_Color11>>16), GLubyte(_Color11>>8), GLubyte(_Color11), GLubyte(_Color11>>24)); _glVertex2f((GLfloat)_X1+dx, (GLfloat)_Y1+dy); _glColor4ub(GLubyte(_Color01>>16), GLubyte(_Color01>>8), GLubyte(_Color01), GLubyte(_Color01>>24)); _glVertex2f((GLfloat)_X0+dx, (GLfloat)_Y1+dy); _glEnd(); */ } // --------------------------------------------------------------------------- void *CTwGraphOpenGLCore::NewTextObj() { return new CTextObj; } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DeleteTextObj(void *_TextObj) { assert(_TextObj!=NULL); delete static_cast(_TextObj); } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth) { assert(m_Drawing==true); assert(_TextObj!=NULL); assert(_Font!=NULL); if( _Font != m_FontTex ) { UnbindFont(m_FontTexID); m_FontTexID = BindFont(_Font); m_FontTex = _Font; } CTextObj *TextObj = static_cast(_TextObj); TextObj->m_TextVerts.resize(0); TextObj->m_TextUVs.resize(0); TextObj->m_BgVerts.resize(0); TextObj->m_Colors.resize(0); TextObj->m_BgColors.resize(0); int x, x1, y, y1, i, Len; unsigned char ch; const unsigned char *Text; color32 LineColor = COLOR32_RED; for( int Line=0; Line<_NbLines; ++Line ) { x = 0; y = Line * (_Font->m_CharHeight+_Sep); y1 = y+_Font->m_CharHeight; Len = (int)_TextLines[Line].length(); Text = (const unsigned char *)(_TextLines[Line].c_str()); if( _LineColors!=NULL ) LineColor = (_LineColors[Line]&0xff00ff00) | GLubyte(_LineColors[Line]>>16) | (GLubyte(_LineColors[Line])<<16); for( i=0; im_CharWidth[ch]; TextObj->m_TextVerts.push_back(Vec2(x , y )); TextObj->m_TextVerts.push_back(Vec2(x1, y )); TextObj->m_TextVerts.push_back(Vec2(x , y1)); TextObj->m_TextVerts.push_back(Vec2(x1, y )); TextObj->m_TextVerts.push_back(Vec2(x1, y1)); TextObj->m_TextVerts.push_back(Vec2(x , y1)); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV0[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU1[ch], _Font->m_CharV1[ch])); TextObj->m_TextUVs.push_back(Vec2(_Font->m_CharU0[ch], _Font->m_CharV1[ch])); if( _LineColors!=NULL ) { TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); TextObj->m_Colors.push_back(LineColor); } x = x1; } if( _BgWidth>0 ) { TextObj->m_BgVerts.push_back(Vec2(-1 , y )); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y )); TextObj->m_BgVerts.push_back(Vec2(-1 , y1)); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y )); TextObj->m_BgVerts.push_back(Vec2(_BgWidth+1, y1)); TextObj->m_BgVerts.push_back(Vec2(-1 , y1)); if( _LineBgColors!=NULL ) { color32 LineBgColor = (_LineBgColors[Line]&0xff00ff00) | GLubyte(_LineBgColors[Line]>>16) | (GLubyte(_LineBgColors[Line])<<16); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); TextObj->m_BgColors.push_back(LineBgColor); } } } } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor) { assert(m_Drawing==true); assert(_TextObj!=NULL); CTextObj *TextObj = static_cast(_TextObj); if( TextObj->m_TextVerts.size()<4 && TextObj->m_BgVerts.size()<4 ) return; // nothing to draw /* _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); _glTranslatef((GLfloat)_X, (GLfloat)_Y, 0); _glEnableClientState(GL_VERTEX_ARRAY); if( (_BgColor!=0 || TextObj->m_BgColors.size()==TextObj->m_BgVerts.size()) && TextObj->m_BgVerts.size()>=4 ) { _glDisable(GL_TEXTURE_2D); _glVertexPointer(2, GL_FLOAT, 0, &(TextObj->m_BgVerts[0])); if( TextObj->m_BgColors.size()==TextObj->m_BgVerts.size() && _BgColor==0 ) { _glEnableClientState(GL_COLOR_ARRAY); _glColorPointer(4, GL_UNSIGNED_BYTE, 0, &(TextObj->m_BgColors[0])); } else { _glDisableClientState(GL_COLOR_ARRAY); _glColor4ub(GLubyte(_BgColor>>16), GLubyte(_BgColor>>8), GLubyte(_BgColor), GLubyte(_BgColor>>24)); } _glDrawArrays(GL_TRIANGLES, 0, (int)TextObj->m_BgVerts.size()); } _glEnable(GL_TEXTURE_2D); _glBindTexture(GL_TEXTURE_2D, m_FontTexID); _glEnableClientState(GL_TEXTURE_COORD_ARRAY); if( TextObj->m_TextVerts.size()>=4 ) { _glVertexPointer(2, GL_FLOAT, 0, &(TextObj->m_TextVerts[0])); _glTexCoordPointer(2, GL_FLOAT, 0, &(TextObj->m_TextUVs[0])); if( TextObj->m_Colors.size()==TextObj->m_TextVerts.size() && _Color==0 ) { _glEnableClientState(GL_COLOR_ARRAY); _glColorPointer(4, GL_UNSIGNED_BYTE, 0, &(TextObj->m_Colors[0])); } else { _glDisableClientState(GL_COLOR_ARRAY); _glColor4ub(GLubyte(_Color>>16), GLubyte(_Color>>8), GLubyte(_Color), GLubyte(_Color>>24)); } _glDrawArrays(GL_TRIANGLES, 0, (int)TextObj->m_TextVerts.size()); } _glDisableClientState(GL_VERTEX_ARRAY); _glDisableClientState(GL_TEXTURE_COORD_ARRAY); _glDisableClientState(GL_COLOR_ARRAY); */ } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY) { /* if( _Width>0 && _Height>0 ) { GLint vp[4]; vp[0] = _X0; vp[1] = _Y0; vp[2] = _Width-1; vp[3] = _Height-1; _glViewport(vp[0], m_WndHeight-vp[1]-vp[3], vp[2], vp[3]); GLint matrixMode = 0; _glGetIntegerv(GL_MATRIX_MODE, &matrixMode); _glMatrixMode(GL_PROJECTION); _glLoadIdentity(); _glOrtho(_OffsetX, _OffsetX+vp[2], vp[3]-_OffsetY, -_OffsetY, -1, 1); _glMatrixMode(matrixMode); } */ } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::RestoreViewport() { /* _glViewport(m_ViewportInit[0], m_ViewportInit[1], m_ViewportInit[2], m_ViewportInit[3]); GLint matrixMode = 0; _glGetIntegerv(GL_MATRIX_MODE, &matrixMode); _glMatrixMode(GL_PROJECTION); _glLoadMatrixf(m_ProjMatrixInit); _glMatrixMode(matrixMode); */ } // --------------------------------------------------------------------------- void CTwGraphOpenGLCore::DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode) { assert(m_Drawing==true); const GLfloat dx = +0.0f; const GLfloat dy = +0.0f; /* GLint prevCullFaceMode, prevFrontFace; _glGetIntegerv(GL_CULL_FACE_MODE, &prevCullFaceMode); _glGetIntegerv(GL_FRONT_FACE, &prevFrontFace); GLboolean prevCullEnable = _glIsEnabled(GL_CULL_FACE); _glCullFace(GL_BACK); _glEnable(GL_CULL_FACE); if( _CullMode==CULL_CW ) _glFrontFace(GL_CCW); else if( _CullMode==CULL_CCW ) _glFrontFace(GL_CW); else _glDisable(GL_CULL_FACE); _glDisable(GL_TEXTURE_2D); _glMatrixMode(GL_MODELVIEW); _glLoadIdentity(); _glBegin(GL_TRIANGLES); for(int i=0; i<3*_NumTriangles; ++i) { color32 col = _Colors[i]; _glColor4ub(GLubyte(col>>16), GLubyte(col>>8), GLubyte(col), GLubyte(col>>24)); _glVertex2f((GLfloat)_Vertices[2*i+0]+dx, (GLfloat)_Vertices[2*i+1]+dy); } _glEnd(); _glCullFace(prevCullFaceMode); _glFrontFace(prevFrontFace); if( prevCullEnable ) _glEnable(GL_CULL_FACE); else _glDisable(GL_CULL_FACE); */ } // --------------------------------------------------------------------------- ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwOpenGLCore.h0000644000000000000000000001010412635011627025164 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwOpenGLCore.h // @brief OpenGL Core graph functions // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // notes: Private header, // Work In Progress, Disabled. // // --------------------------------------------------------------------------- #if !defined ANT_TW_OPENGL_CORE_INCLUDED #define ANT_TW_OPENGL_CORE_INCLUDED #include "TwGraph.h" // --------------------------------------------------------------------------- class CTwGraphOpenGLCore : public ITwGraph { public: virtual int Init(); virtual int Shut(); virtual void BeginDraw(int _WndWidth, int _WndHeight); virtual void EndDraw(); virtual bool IsDrawing(); virtual void Restore(); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color0, color32 _Color1, bool _AntiAliased=false); virtual void DrawLine(int _X0, int _Y0, int _X1, int _Y1, color32 _Color, bool _AntiAliased=false) { DrawLine(_X0, _Y0, _X1, _Y1, _Color, _Color, _AntiAliased); } virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color00, color32 _Color10, color32 _Color01, color32 _Color11); virtual void DrawRect(int _X0, int _Y0, int _X1, int _Y1, color32 _Color) { DrawRect(_X0, _Y0, _X1, _Y1, _Color, _Color, _Color, _Color); } virtual void DrawTriangles(int _NumTriangles, int *_Vertices, color32 *_Colors, Cull _CullMode); virtual void * NewTextObj(); virtual void DeleteTextObj(void *_TextObj); virtual void BuildText(void *_TextObj, const std::string *_TextLines, color32 *_LineColors, color32 *_LineBgColors, int _NbLines, const CTexFont *_Font, int _Sep, int _BgWidth); virtual void DrawText(void *_TextObj, int _X, int _Y, color32 _Color, color32 _BgColor); virtual void ChangeViewport(int _X0, int _Y0, int _Width, int _Height, int _OffsetX, int _OffsetY); virtual void RestoreViewport(); protected: bool m_Drawing; GLuint m_FontTexID; const CTexFont * m_FontTex; GLfloat m_PrevLineWidth; GLint m_PrevTexture; GLint m_PrevArrayBuffer; GLint m_PrevElementArrayBuffer; GLboolean m_PrevVertexProgram; GLboolean m_PrevFragmentProgram; GLuint m_PrevProgramObject; GLboolean m_PrevTexture3D; GLboolean m_PrevActiveTexture1D[32]; GLboolean m_PrevActiveTexture2D[32]; GLboolean m_PrevActiveTexture3D[32]; GLint m_PrevActiveTexture; GLboolean m_PrevTexRect; GLint m_PrevBlendEquation; GLint m_PrevBlendEquationRGB; GLint m_PrevBlendEquationAlpha; GLint m_PrevBlendSrcRGB; GLint m_PrevBlendDstRGB; GLint m_PrevBlendSrcAlpha; GLint m_PrevBlendDstAlpha; GLint m_ViewportInit[4]; GLuint m_LineRectVS; GLuint m_LineRectFS; GLuint m_LineRectProgram; GLuint m_LineRectVArray; GLuint m_LineRectBuffer; int m_WndWidth; int m_WndHeight; int m_OffsetX; int m_OffsetY; struct Vec2 { GLfloat x, y; Vec2(){} Vec2(GLfloat _X, GLfloat _Y):x(_X),y(_Y){} Vec2(int _X, int _Y):x(GLfloat(_X)),y(GLfloat(_Y)){} }; struct CTextObj { std::vector m_TextVerts; std::vector m_TextUVs; std::vector m_BgVerts; std::vectorm_Colors; std::vectorm_BgColors; }; }; // --------------------------------------------------------------------------- #endif // !defined ANT_TW_OPENGL_CORE_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwPrecomp.cpp0000644000000000000000000000002712635011627025172 0ustar rootroot#include "TwPrecomp.h" ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/TwPrecomp.h0000644000000000000000000000457112635011627024647 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwPrecomp.h // @brief Precompiled header // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- #if !defined ANT_TW_PRECOMP_INCLUDED #define ANT_TW_PRECOMP_INCLUDED #if defined _MSC_VER # pragma warning(disable: 4514) // unreferenced inline function has been removed # pragma warning(disable: 4710) // function not inlined # pragma warning(disable: 4786) // template name truncated # pragma warning(disable: 4530) // exceptions not handled # define _CRT_SECURE_NO_DEPRECATE // visual 8 secure crt warning #endif #include #include #include #include #include #include #include #if defined(_MSC_VER) && _MSC_VER<=1200 # pragma warning(push, 3) #endif #include #include #include #include #include #include #if defined(_MSC_VER) && _MSC_VER<=1200 # pragma warning(pop) #endif #if defined(_UNIX) || defined(__unix__) # define ANT_UNIX # include # define GLX_GLXEXT_LEGACY # include # include # include # include # undef _WIN32 # undef WIN32 # undef _WIN64 # undef WIN64 # undef _WINDOWS # undef ANT_WINDOWS # undef ANT_OSX #elif defined(_MACOSX) # define ANT_OSX # include # include # include # include # undef _WIN32 # undef WIN32 # undef _WIN64 # undef WIN64 # undef _WINDOWS # undef ANT_WINDOWS # undef ANT_UNIX #elif defined(_WINDOWS) || defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64) # define ANT_WINDOWS # define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers # include # include #endif #if !defined(ANT_OGL_HEADER_INCLUDED) # if defined(ANT_OSX) # include # else # include // must be included after windows.h # endif # define ANT_OGL_HEADER_INCLUDED #endif #endif // !defined ANT_TW_PRECOMP_INCLUDED ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/d3d10vs2003.h0000644000000000000000000000144512635011627024415 0ustar rootroot// Workaround to include D3D10.h with VS2003 #ifndef __out #define __out #endif #ifndef __in #define __in #endif #ifndef __inout #define __inout #endif #ifndef __in_opt #define __in_opt #endif #ifndef __out_opt #define __out_opt #endif #ifndef __inout_opt #define __inout_opt #endif #ifndef __in_ecount #define __in_ecount(x) #endif #ifndef __in_ecount_opt #define __in_ecount_opt(x) #endif #ifndef __out_ecount #define __out_ecount(x) #endif #ifndef __out_ecount_opt #define __out_ecount_opt(x) #endif #ifndef __inout_ecount #define __inout_ecount(x) #endif #ifndef __inout_ecount_opt #define __inout_ecount_opt(x) #endif #ifndef __in_bcount_opt #define __in_bcount_opt(x) #endif #ifndef __out_bcount_opt #define __out_bcount_opt(x) #endif #ifndef __inout_bcount_opt #define __inout_bcount_opt(x) #endif ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/0000775000000000000000000000000012635012023023331 5ustar rootrootode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/FontChars.txt0000644000000000000000000000352212635011627025772 0ustar rootroot !"#$%&'()*+,-./0123456789:;<=>? @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ `abcdefghijklmnopqrstuvwxyz{|}~√ €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ  ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ 032 033 ! 034 " 035 # 036 $ 037 % 038 & 039 ' 040 ( 041 ) 042 * 043 + 044 , 045 - 046 . 047 / 048 0 049 1 050 2 051 3 052 4 053 5 054 6 055 7 056 8 057 9 058 : 059 ; 060 < 061 = 062 > 063 ? 064 @ 065 A 066 B 067 C 068 D 069 E 070 F 071 G 072 H 073 I 074 J 075 K 076 L 077 M 078 N 079 O 080 P 081 Q 082 R 083 S 084 T 085 U 086 V 087 W 088 X 089 Y 090 Z 091 [ 092 \ 093 ] 094 ^ 095 _ 096 ` 097 a 098 b 099 c 100 d 101 e 102 f 103 g 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 √ 128 € 129  130 ‚ 131 ƒ 132 „ 133 … 134 † 135 ‡ 136 ˆ 137 ‰ 138 Š 139 ‹ 140 Œ 141  142 Ž 143  144  145 ‘ 146 ’ 147 “ 148 ” 149 • 150 – 151 — 152 ˜ 153 ™ 154 š 155 › 156 œ 157  158 ž 159 Ÿ 160   161 ¡ 162 ¢ 163 £ 164 ¤ 165 ¥ 166 ¦ 167 § 168 ¨ 169 © 170 ª 171 « 172 ¬ 173 ­ 174 ® 175 ¯ 176 ° 177 ± 178 ² 179 ³ 180 ´ 181 µ 182 ¶ 183 · 184 ¸ 185 ¹ 186 º 187 » 188 ¼ 189 ½ 190 ¾ 191 ¿ 192 À 193 Á 194  195 à 196 Ä 197 Å 198 Æ 199 Ç 200 È 201 É 202 Ê 203 Ë 204 Ì 205 Í 206 Î 207 Ï 208 Ð 209 Ñ 210 Ò 211 Ó 212 Ô 213 Õ 214 Ö 215 × 216 Ø 217 Ù 218 Ú 219 Û 220 Ü 221 Ý 222 Þ 223 ß 224 à 225 á 226 â 227 ã 228 ä 229 å 230 æ 231 ç 232 è 233 é 234 ê 235 ë 236 ì 237 í 238 î 239 ï 240 ð 241 ñ 242 ò 243 ó 244 ô 245 õ 246 ö 247 ÷ 248 ø 249 ù 250 ú 251 û 252 ü 253 ý 254 þ 255 ÿ ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/FontLargeAA.pgm0000644000000000000000000025212312635011627026135 0ustar rootrootP2 # Created by Paint Shop Pro 276 120 255 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 59 245 125 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 12 235 201 89 255 166 0 0 0 0 0 172 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 138 247 34 0 12 232 89 138 225 21 0 0 0 0 138 125 7 199 34 0 0 0 0 138 125 0 0 0 0 138 255 255 201 0 0 0 59 215 21 0 0 0 0 59 245 255 255 166 0 0 0 59 241 89 0 7 206 201 0 0 89 251 89 0 59 215 21 172 89 59 192 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 0 0 138 255 251 89 0 0 0 0 0 138 201 0 0 0 7 206 255 255 255 166 0 0 7 206 255 255 255 201 0 0 0 0 0 0 138 251 89 0 0 175 255 255 255 255 225 21 0 0 12 235 255 255 125 89 255 255 255 255 255 251 89 0 12 235 255 255 225 21 0 0 59 245 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 12 232 89 138 201 0 0 0 0 7 202 89 59 215 21 0 0 12 235 255 255 255 166 0 59 241 89 12 235 125 0 0 172 89 0 0 0 0 7 206 166 0 89 251 89 0 0 12 228 34 0 89 247 34 0 0 0 175 201 0 0 89 251 191 194 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 175 201 0 12 235 125 0 0 138 255 255 201 0 0 0 12 182 0 0 59 245 125 0 12 206 21 0 12 235 166 0 0 0 0 89 255 251 89 0 0 175 201 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 0 0 89 251 89 12 235 166 0 7 206 201 0 59 245 125 0 12 235 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 166 0 0 138 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 12 228 34 89 201 0 0 0 0 12 206 21 89 166 0 0 12 235 125 138 125 59 192 0 89 247 34 7 206 166 0 89 201 0 0 0 0 0 12 235 125 0 12 232 89 0 0 12 228 34 0 175 201 0 0 0 0 59 241 89 0 0 7 206 166 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 225 21 59 241 89 0 0 138 225 21 0 0 0 175 201 0 0 0 0 0 0 0 7 206 201 0 0 0 0 0 0 175 201 0 0 0 59 241 132 241 89 0 0 175 201 0 0 0 0 0 7 206 166 0 0 0 0 0 0 0 0 7 206 201 0 59 241 89 0 0 138 225 21 138 225 21 0 0 138 225 21 89 255 125 0 0 89 255 125 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 89 255 255 255 255 255 255 255 125 59 238 34 138 125 0 0 0 89 247 34 7 206 166 7 202 89 0 0 0 0 0 0 175 225 21 138 225 21 0 0 0 0 0 12 235 125 0 0 0 0 7 206 125 0 89 251 191 194 247 34 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 89 247 34 0 0 89 247 34 0 0 0 175 201 0 0 0 0 0 0 0 12 235 166 0 0 0 0 0 59 245 125 0 0 12 235 125 59 241 89 0 0 175 201 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 89 247 34 0 12 235 201 0 0 175 201 0 138 225 21 0 0 89 247 34 89 255 125 0 0 89 255 125 0 0 0 0 0 12 235 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 175 255 251 89 0 0 0 0 0 0 0 0 138 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 175 125 7 199 34 0 0 12 235 166 138 125 0 0 0 59 241 89 12 235 125 89 201 12 235 255 251 89 0 0 7 206 255 166 0 59 241 89 0 0 0 59 238 34 0 0 0 0 0 175 166 59 215 21 172 89 59 192 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 138 247 34 0 0 89 247 34 0 0 0 175 201 0 0 0 0 0 0 0 89 251 89 0 0 0 89 255 247 34 0 0 7 206 166 0 59 241 89 0 0 175 255 255 255 225 21 0 89 251 226 255 255 247 34 0 0 0 7 206 166 0 0 0 12 235 255 255 201 0 0 89 255 125 0 0 138 247 34 0 0 0 0 0 0 0 0 0 0 0 89 255 255 166 0 0 0 0 0 175 255 255 255 255 255 255 225 21 0 0 0 0 59 245 255 201 0 0 0 0 0 175 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 7 199 34 59 215 21 0 0 0 59 245 255 255 201 0 0 0 138 255 255 201 12 228 34 175 166 0 138 201 0 12 235 125 89 255 125 59 241 89 0 0 0 59 238 34 0 0 0 0 0 138 201 0 0 0 172 89 0 0 0 7 206 255 255 255 255 255 255 247 34 0 0 0 0 89 255 255 255 166 0 0 0 0 0 59 238 34 0 138 247 34 0 0 89 247 34 0 0 0 175 201 0 0 0 0 0 0 59 245 166 0 0 0 0 0 0 12 235 166 0 138 201 0 0 59 241 89 0 0 0 0 0 12 235 201 0 138 251 89 0 0 175 225 21 0 0 89 247 34 0 0 7 206 166 0 175 255 166 0 0 89 255 255 255 223 247 34 0 0 0 0 0 0 0 0 0 0 175 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 225 21 0 0 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 59 215 21 0 0 0 0 0 0 0 12 235 255 255 255 255 255 255 166 0 0 0 0 138 125 175 225 21 0 0 0 0 0 138 166 7 206 125 0 89 247 34 138 225 21 0 89 255 166 215 21 0 0 0 59 238 34 0 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 201 0 0 89 247 34 0 0 89 247 34 0 0 0 175 201 0 0 0 0 0 12 235 201 0 0 0 0 0 0 0 0 138 225 21 175 255 255 255 255 255 255 125 0 0 0 0 0 138 247 34 89 247 34 0 0 59 241 89 0 7 206 166 0 0 0 138 247 34 0 0 138 247 34 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 89 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 201 0 0 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 166 0 175 125 0 0 0 0 0 0 138 125 89 247 34 0 0 0 0 12 228 34 7 206 125 0 89 247 34 138 247 34 0 0 89 255 166 0 0 0 0 59 238 34 0 0 0 0 0 175 166 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 0 59 241 89 0 0 138 225 21 0 0 0 175 201 0 0 0 0 12 235 201 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 59 241 89 0 0 0 0 0 0 138 225 21 59 241 89 0 0 59 241 89 0 89 247 34 0 0 0 138 247 34 0 0 89 251 89 0 0 0 0 7 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 225 21 0 0 175 255 255 255 255 255 255 225 21 0 0 175 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 175 125 7 199 34 0 0 0 89 201 0 138 125 175 201 0 0 0 0 0 138 166 0 0 175 166 0 138 201 0 89 255 166 0 0 89 255 255 125 0 0 0 12 235 125 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 138 255 125 0 0 0 0 0 0 175 247 34 59 238 34 0 0 0 175 201 0 12 235 125 0 0 0 0 175 201 0 0 0 12 235 166 0 0 0 0 0 89 166 0 0 59 245 166 0 0 0 0 0 59 241 89 0 59 215 21 0 12 235 166 0 7 206 201 0 0 175 225 21 7 206 166 0 0 0 0 59 245 166 0 7 206 225 21 0 0 0 0 175 225 21 0 89 255 125 0 0 12 235 201 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 7 199 34 59 215 21 0 0 0 12 235 255 255 255 201 0 0 0 0 0 59 215 21 0 0 12 235 255 251 89 0 0 89 255 255 255 201 0 89 255 0 0 0 0 175 201 0 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 175 247 34 138 201 0 0 0 0 0 138 255 251 89 0 0 0 138 255 255 255 255 166 0 89 255 255 255 255 255 247 34 12 235 255 255 255 166 0 0 0 0 0 0 59 241 89 0 12 235 255 255 255 166 0 0 0 7 206 255 255 225 21 0 138 247 34 0 0 0 0 0 59 245 255 255 201 0 0 0 175 255 255 201 0 0 0 89 255 125 0 0 89 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 52 4 4 4 4 4 4 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 201 0 0 89 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 201 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 4 4 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 201 0 0 201 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 201 0 138 201 0 0 0 0 89 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 175 255 255 255 247 34 0 0 0 0 0 7 206 251 89 0 0 12 0 235 255 255 255 255 201 0 0 0 0 59 245 255 255 255 201 12 0 235 255 255 255 255 166 0 0 0 12 235 255 255 255 255 255 127 12 235 255 255 255 255 251 89 0 0 12 235 255 255 255 251 89 12 235 166 0 0 0 12 235 125 89 255 255 255 201 0 0 175 255 255 225 21 12 235 166 0 0 7 206 251 102 0 235 166 0 0 0 0 12 235 251 89 0 0 0 89 255 225 21 12 235 251 89 0 0 12 235 125 0 0 0 138 255 255 166 0 0 0 12 235 255 255 255 251 89 0 0 0 0 175 255 255 201 0 0 0 12 235 255 255 255 251 89 0 0 0 12 235 255 255 255 247 47 235 255 255 255 255 255 255 255 138 0 235 125 0 0 0 59 245 133 206 166 0 0 0 0 59 245 255 133 201 0 0 0 138 251 89 0 0 12 235 133 206 247 34 0 0 0 175 229 216 225 21 0 0 0 138 247 124 255 255 255 255 255 255 125 7 206 125 0 0 0 59 238 34 0 0 0 0 0 12 235 125 0 0 0 0 175 247 34 0 0 0 0 0 0 0 0 0 0 127 0 0 59 245 166 0 0 0 59 245 166 0 0 0 0 59 245 255 166 0 0 12 0 235 166 0 0 59 245 125 0 0 138 255 125 0 0 7 202 102 0 235 166 0 0 59 245 225 21 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 89 255 166 0 0 0 89 127 12 235 166 0 0 0 12 235 125 0 12 235 125 0 0 0 0 0 138 225 21 12 235 166 0 7 206 225 21 12 0 235 166 0 0 0 0 12 235 255 166 0 0 7 206 255 225 21 12 235 255 201 0 0 12 235 125 0 59 245 166 0 0 138 251 89 0 12 235 166 0 0 138 251 89 0 89 255 125 0 0 89 255 125 0 12 235 166 0 0 138 251 89 0 12 235 166 0 0 7 202 89 0 0 0 138 225 21 0 0 12 0 235 125 0 0 0 59 245 125 138 225 21 0 0 0 138 225 151 34 247 34 0 0 175 255 125 0 0 89 247 34 12 235 166 0 0 89 247 34 59 245 125 0 0 59 245 125 0 0 0 0 0 138 247 34 7 206 125 0 0 0 7 206 125 0 0 0 0 0 12 235 125 0 0 0 138 225 187 201 0 0 0 0 0 0 0 0 0 0 127 0 12 232 89 0 0 0 0 0 12 232 89 0 0 0 138 225 151 225 21 0 12 0 235 166 0 0 12 235 166 0 12 235 166 0 0 0 0 0 12 0 235 166 0 0 0 12 235 166 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 166 0 0 0 12 235 125 0 12 235 125 0 0 0 0 0 138 225 21 12 235 166 0 175 225 21 0 12 0 235 166 0 0 0 0 12 235 166 238 34 0 59 215 187 225 21 12 235 166 245 125 0 12 235 125 12 235 125 0 0 0 0 138 247 34 12 235 166 0 0 12 235 166 12 235 125 0 0 0 0 138 247 34 12 235 166 0 0 12 235 166 0 89 247 34 0 0 0 0 0 0 0 0 138 225 21 0 0 12 0 235 125 0 0 0 59 245 125 59 241 89 0 0 7 206 166 59 0 241 89 0 12 232 194 201 0 0 138 225 21 0 89 251 89 12 235 166 0 0 138 247 34 7 206 201 0 0 0 0 0 59 245 125 0 7 206 125 0 0 0 0 138 201 0 0 0 0 0 12 235 125 0 0 59 241 89 12 235 166 0 0 0 0 0 0 0 0 0 127 0 175 166 0 59 245 255 255 247 34 138 201 0 0 7 206 166 59 241 89 0 12 0 235 166 0 0 89 251 89 0 89 247 34 0 0 0 0 0 12 0 235 166 0 0 0 0 138 225 21 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 89 247 34 0 0 0 0 0 0 12 235 166 0 0 0 12 235 125 0 12 235 125 0 0 0 0 0 138 225 21 12 235 166 175 247 34 0 0 12 0 235 166 0 0 0 0 12 235 133 206 166 0 175 166 175 225 21 12 235 125 138 225 21 12 235 125 89 247 34 0 0 0 0 59 245 125 12 235 166 0 0 12 235 166 89 247 34 0 0 0 0 59 245 125 12 235 166 0 0 12 235 125 0 89 255 125 0 0 0 0 0 0 0 0 138 225 21 0 0 12 0 235 125 0 0 0 59 245 125 7 206 201 0 0 59 241 89 7 0 206 166 0 59 215 111 225 21 7 206 166 0 0 0 175 225 187 225 21 0 0 12 235 166 89 247 34 0 0 0 0 7 206 201 0 0 7 206 125 0 0 0 0 89 225 21 0 0 0 0 12 235 125 0 12 235 166 0 0 59 241 89 0 0 0 0 0 0 0 0 127 0 202 89 12 235 125 0 12 228 34 59 215 0 0 59 241 89 7 206 166 0 12 0 235 255 255 255 255 166 0 0 138 225 21 0 0 0 0 0 12 0 235 166 0 0 0 0 89 247 34 12 235 255 255 255 255 247 34 12 235 255 255 255 255 247 0 163 225 21 0 0 0 0 0 0 12 235 255 255 255 255 255 255 125 0 12 235 125 0 0 0 0 0 138 225 21 12 235 255 247 34 0 0 0 12 0 235 166 0 0 0 0 12 235 125 89 225 34 228 34 175 225 21 12 235 125 12 235 125 12 235 125 138 225 21 0 0 0 0 12 235 166 12 235 166 0 0 175 247 34 138 225 21 0 0 0 0 12 235 166 12 235 166 0 0 175 225 21 0 0 175 255 255 225 21 0 0 0 0 0 138 225 21 0 0 12 0 235 125 0 0 0 59 245 125 0 138 247 34 0 138 225 21 0 0 175 201 0 138 201 12 232 89 12 235 125 0 0 0 12 235 251 89 0 0 0 0 89 255 255 125 0 0 0 0 0 138 247 34 0 0 7 206 125 0 0 0 0 12 232 89 0 0 0 0 12 235 125 7 206 201 0 0 0 0 138 251 89 0 0 0 0 0 0 0 127 7 228 34 89 225 21 0 12 228 34 12 228 0 0 138 225 21 0 138 225 21 12 0 235 166 0 0 12 235 201 0 138 225 21 0 0 0 0 0 12 0 235 166 0 0 0 0 89 247 34 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 138 225 21 0 12 235 255 255 127 12 235 166 0 0 0 12 235 125 0 12 235 125 0 0 0 0 0 138 225 21 12 235 229 216 225 21 0 0 12 0 235 166 0 0 0 0 12 235 125 12 235 223 201 0 175 225 21 12 235 125 0 138 225 34 235 125 138 225 21 0 0 0 0 12 235 166 12 235 255 255 255 247 34 0 138 225 21 0 0 0 0 12 235 166 12 235 255 255 255 166 0 0 0 0 0 0 89 255 255 247 34 0 0 0 138 225 21 0 0 12 0 235 125 0 0 0 59 245 125 0 59 245 125 7 206 166 0 0 0 89 247 34 175 125 7 206 125 89 247 34 0 0 0 12 235 251 89 0 0 0 0 7 206 225 21 0 0 0 0 59 245 125 0 0 0 7 206 125 0 0 0 0 0 175 166 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 12 228 34 89 225 21 0 12 228 34 59 215 0 7 206 255 255 255 255 251 89 12 0 235 166 0 0 0 138 247 0 124 247 34 0 0 0 0 0 12 0 235 166 0 0 0 0 138 225 21 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 89 247 34 0 0 0 0 175 127 12 235 166 0 0 0 12 235 125 0 12 235 125 0 0 0 0 0 138 225 21 12 235 166 59 245 201 0 0 12 0 235 166 0 0 0 0 12 235 125 0 138 251 89 0 175 225 21 12 235 125 0 12 235 138 235 125 89 247 34 0 0 0 0 59 245 125 12 235 166 0 0 0 0 0 89 247 34 0 0 0 0 59 245 125 12 235 166 0 175 247 34 0 0 0 0 0 0 0 59 245 166 0 0 0 138 225 21 0 0 12 0 235 125 0 0 0 59 241 89 0 7 206 201 59 241 89 0 0 0 59 241 102 232 89 0 138 201 138 225 21 0 0 0 175 201 175 225 21 0 0 0 0 175 225 21 0 0 0 7 206 201 0 0 0 0 7 206 125 0 0 0 0 0 89 225 21 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 12 232 89 59 241 89 0 89 247 34 89 201 0 59 241 89 0 0 7 206 166 12 0 235 166 0 0 0 138 225 0 81 245 166 0 0 0 0 0 12 0 235 166 0 0 0 12 235 166 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 175 127 12 235 166 0 0 0 12 235 125 0 12 235 125 0 0 0 0 0 138 225 21 12 235 166 0 89 255 166 0 12 0 235 166 0 0 0 0 12 235 125 0 12 182 0 0 175 225 21 12 235 125 0 0 138 232 245 125 12 235 125 0 0 0 0 138 247 34 12 235 166 0 0 0 0 0 12 235 125 0 0 0 0 138 247 34 12 235 166 0 7 206 225 21 0 0 0 0 0 0 12 235 166 0 0 0 138 225 21 0 0 12 0 235 166 0 0 0 89 251 89 0 0 138 247 163 225 21 0 0 0 7 206 200 215 21 0 89 225 187 166 0 0 0 89 251 89 12 235 166 0 0 0 0 175 225 21 0 0 0 138 247 34 0 0 0 0 7 206 125 0 0 0 0 0 12 232 89 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 12 175 166 0 89 255 255 210 235 255 255 125 0 138 225 21 0 0 0 138 247 47 0 235 166 0 0 59 245 166 0 0 138 255 125 0 0 7 202 102 0 235 166 0 0 12 235 225 21 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 138 255 125 0 0 0 175 127 12 235 166 0 0 0 12 235 125 0 12 235 125 0 0 0 0 7 206 201 0 12 235 166 0 0 138 255 125 12 0 235 166 0 0 0 12 0 235 125 0 0 0 0 0 175 225 21 12 235 125 0 0 12 235 255 125 0 89 255 125 0 0 89 251 89 0 12 235 166 0 0 0 0 0 0 89 255 125 0 0 89 255 125 0 12 235 166 0 0 12 235 201 0 138 166 0 0 0 138 251 89 0 0 0 138 225 21 0 0 0 0 138 247 34 0 7 206 225 21 0 0 12 235 255 166 0 0 0 0 0 175 255 201 0 0 12 235 255 125 0 0 12 235 166 0 0 138 251 89 0 0 0 175 225 21 0 0 89 251 89 0 0 0 0 0 7 206 125 0 0 0 0 0 0 175 166 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 59 241 89 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 59 245 138 0 235 255 255 255 255 125 0 0 0 0 59 245 255 255 255 201 12 0 235 255 255 255 255 166 0 0 0 12 235 255 255 255 255 255 127 12 235 166 0 0 0 0 0 0 0 59 245 255 255 255 225 21 12 235 166 0 0 0 12 235 125 89 255 255 255 210 127 235 255 255 225 21 0 12 235 166 0 0 0 175 255 127 0 235 255 255 255 247 47 0 235 125 0 0 0 0 0 175 225 21 12 235 125 0 0 0 138 255 125 0 0 0 175 255 255 201 0 0 0 12 235 166 0 0 0 0 0 0 0 0 175 255 255 201 0 0 0 12 235 166 0 0 0 89 255 225 34 235 255 255 255 247 34 0 0 0 0 138 225 21 0 0 0 0 0 138 255 255 255 201 0 0 0 0 0 175 251 89 0 0 0 0 0 89 255 166 0 0 7 206 247 34 0 7 206 225 21 0 0 7 206 225 21 0 0 175 225 21 0 0 138 255 255 255 255 255 255 166 7 206 125 0 0 0 0 0 0 138 201 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 89 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 0 0 0 0 0 59 238 34 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 7 206 255 255 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 0 0 0 0 0 7 206 125 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 245 255 255 255 255 255 255 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 201 0 0 0 0 0 0 89 89 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 59 245 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 12 235 255 247 0 0 0 0 0 0 0 12 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 251 89 0 7 206 125 0 89 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 84 84 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 0 12 12 235 125 0 0 0 0 0 59 245 102 0 89 247 34 12 235 125 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 7 206 125 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 100 252 252 84 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 12 0 235 125 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 7 206 125 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 20 236 252 164 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 12 235 255 255 255 166 0 12 235 166 245 255 247 34 0 0 12 235 255 255 247 34 0 34 235 255 255 255 225 21 0 12 235 255 255 225 29 0 206 255 255 255 127 0 12 235 255 255 255 225 21 12 235 138 235 255 247 34 0 12 235 102 175 255 247 34 12 235 125 0 59 245 201 0 12 235 125 12 0 235 166 245 255 225 29 206 255 251 89 0 12 235 138 235 255 247 34 0 0 12 235 255 255 201 0 0 12 235 166 245 255 251 89 0 0 12 235 255 255 255 225 21 12 235 138 235 247 127 34 138 255 255 255 206 0 206 255 255 255 201 59 241 89 0 0 89 247 42 206 201 0 0 0 138 225 187 201 0 0 138 225 21 0 59 241 187 226 247 34 0 7 206 206 206 201 0 0 0 138 225 151 255 255 255 255 247 0 0 89 247 34 0 0 0 7 206 125 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 148 252 236 20 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 12 206 21 0 59 245 125 12 235 247 34 0 138 225 21 12 235 166 0 0 134 102 0 235 166 0 0 138 225 21 12 235 125 0 0 175 201 12 0 235 125 0 0 12 235 166 0 0 138 225 21 12 235 247 34 0 175 201 0 12 235 102 0 89 247 34 12 235 125 12 235 166 0 0 12 235 125 12 0 235 225 21 12 235 251 89 0 175 201 0 12 235 247 34 0 175 201 0 12 235 166 0 7 206 201 0 12 235 225 21 0 175 225 21 12 235 166 0 0 138 225 21 12 235 247 34 0 0 89 247 34 0 12 206 34 0 235 125 0 0 59 241 89 0 0 89 247 34 89 247 34 0 7 206 166 138 225 21 7 206 251 89 0 89 225 138 34 235 201 0 138 225 21 89 247 34 0 7 206 166 0 0 0 7 206 166 0 0 89 225 21 0 0 0 7 206 125 0 0 0 59 241 89 0 0 0 0 138 251 89 0 0 7 202 89 0 0 4 4 4 4 4 4 52 252 252 108 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 7 206 102 12 235 125 0 0 59 241 89 138 225 21 0 0 0 34 89 225 21 0 0 138 225 21 89 225 21 0 0 89 247 47 0 235 125 0 0 89 225 21 0 0 138 225 21 12 235 125 0 0 89 247 34 12 235 102 0 89 247 34 12 235 138 235 166 0 0 0 12 235 125 12 0 235 125 0 7 206 166 0 0 138 225 21 12 235 125 0 0 89 247 34 138 225 21 0 0 59 238 34 12 235 125 0 0 59 241 89 89 225 21 0 0 138 225 21 12 235 125 0 0 0 138 225 21 0 0 0 12 0 235 125 0 0 59 241 89 0 0 89 247 34 12 235 125 0 59 241 89 59 238 34 12 228 198 166 0 175 166 59 0 89 251 132 241 89 0 12 235 125 0 59 238 34 0 0 0 138 225 21 0 12 235 166 0 0 0 0 7 206 125 0 0 0 0 175 201 0 0 0 138 166 12 235 166 0 12 232 89 0 0 12 84 4 4 4 4 204 252 204 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 59 245 255 255 255 102 12 235 125 0 0 12 235 125 175 201 0 0 0 0 0 175 201 0 0 0 138 225 21 175 255 255 255 255 255 247 47 0 235 125 0 0 175 201 0 0 0 138 225 21 12 235 125 0 0 89 247 34 12 235 102 0 89 247 34 12 235 255 225 21 0 0 0 12 235 125 12 0 235 125 0 7 206 166 0 0 138 225 21 12 235 125 0 0 89 247 34 175 201 0 0 0 12 232 89 12 235 125 0 0 12 235 125 175 201 0 0 0 138 225 21 12 235 125 0 0 0 59 245 255 247 34 0 12 0 235 125 0 0 59 241 89 0 0 89 247 34 0 175 201 0 138 201 0 12 235 125 89 201 89 225 29 206 125 12 0 0 175 255 166 0 0 0 175 201 0 138 201 0 0 0 89 251 89 0 138 247 34 0 0 0 0 0 7 206 125 0 0 0 0 0 89 255 125 7 202 89 0 89 251 89 89 201 0 0 0 172 252 84 4 4 100 252 252 60 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 89 255 166 0 7 206 102 12 235 125 0 0 12 235 125 175 201 0 0 0 0 0 175 201 0 0 0 138 225 21 175 201 0 0 0 0 0 12 0 235 125 0 0 175 201 0 0 0 138 225 21 12 235 125 0 0 89 247 34 12 235 102 0 89 247 34 12 235 138 235 201 0 0 0 12 235 125 12 0 235 125 0 7 206 166 0 0 138 225 21 12 235 125 0 0 89 247 34 175 201 0 0 0 12 232 89 12 235 125 0 0 12 235 125 175 201 0 0 0 138 225 21 12 235 125 0 0 0 0 0 138 255 255 201 12 0 235 125 0 0 59 241 89 0 0 89 247 34 0 89 247 42 206 125 0 0 175 166 175 125 12 232 102 232 89 0 0 0 175 255 201 0 0 0 89 247 47 235 125 0 0 12 235 166 0 0 0 12 235 125 0 0 0 0 7 206 125 0 0 0 0 138 201 0 0 12 232 89 0 0 59 245 225 21 0 0 0 196 252 244 60 20 236 252 156 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 175 201 0 0 7 206 102 12 235 125 0 0 59 241 89 138 225 21 0 0 0 34 89 225 21 0 0 138 225 21 138 247 34 0 0 0 0 12 0 235 125 0 0 138 225 21 0 0 138 225 21 12 235 125 0 0 89 247 34 12 235 102 0 89 247 34 12 235 125 59 245 125 0 0 12 235 125 12 0 235 125 0 7 206 166 0 0 138 225 21 12 235 125 0 0 89 247 34 138 225 21 0 0 89 247 34 12 235 125 0 0 59 241 89 138 225 21 0 0 138 225 21 12 235 125 0 0 0 0 0 0 0 89 247 47 0 235 125 0 0 59 241 89 0 0 89 247 34 0 12 235 166 238 34 0 0 138 210 228 34 0 175 166 215 21 0 0 89 251 159 251 89 0 0 12 235 191 247 34 0 0 175 225 21 0 0 0 0 138 225 21 0 0 0 7 206 125 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 20 220 252 236 180 252 244 28 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 138 225 21 0 138 255 102 12 235 125 0 7 206 201 0 12 235 166 0 0 134 132 0 245 125 0 59 245 225 21 12 235 201 0 0 12 206 34 0 235 125 0 0 59 245 125 0 12 235 225 21 12 235 125 0 0 89 247 34 12 235 102 0 89 247 34 12 235 125 0 138 251 89 0 12 235 125 12 0 235 125 0 7 206 166 0 0 138 225 21 12 235 125 0 0 89 247 34 12 235 166 0 7 206 201 0 12 235 125 0 7 206 201 0 59 245 125 0 12 235 225 21 12 235 125 0 0 0 138 125 0 0 138 225 29 0 206 166 0 0 7 206 166 0 59 245 247 34 0 0 175 255 201 0 0 0 59 245 225 21 0 89 255 201 0 0 12 235 166 0 175 225 21 0 0 138 255 166 0 0 89 251 89 0 0 0 0 0 89 247 34 0 0 0 7 206 125 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 36 236 252 252 252 108 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 7 206 255 255 171 206 102 12 232 226 255 255 225 21 0 0 12 235 255 255 247 34 0 89 255 255 247 163 225 21 0 7 206 255 255 247 34 12 0 235 125 0 0 0 89 255 255 247 163 225 21 12 235 125 0 0 89 247 34 12 235 102 0 89 247 34 12 235 125 0 0 175 251 34 0 235 125 12 0 235 125 0 7 206 166 0 0 138 225 21 12 235 125 0 0 89 247 34 0 12 235 255 255 201 0 0 12 235 255 255 255 225 21 0 0 89 255 255 247 163 225 21 12 235 125 0 0 0 89 255 255 255 247 34 0 0 89 255 255 127 0 59 245 255 225 111 247 34 0 0 59 245 125 0 0 0 12 235 166 0 0 59 245 125 7 0 206 225 21 0 12 235 201 0 0 59 241 89 0 0 175 255 255 255 255 247 0 0 89 247 34 0 0 0 7 206 125 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 60 252 252 204 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 7 206 125 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 76 252 60 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 7 206 125 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 76 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 89 255 251 89 0 7 206 125 0 89 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 0 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 175 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 206 125 0 175 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 0 138 201 0 7 206 166 12 235 125 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 0 175 171 206 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 31 206 130 255 166 175 247 34 0 0 89 255 125 175 247 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 247 34 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 132 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 132 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 59 245 255 255 255 125 0 12 235 255 255 255 255 255 225 21 0 0 0 0 0 0 0 0 175 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 89 225 21 59 238 34 0 0 138 255 255 201 0 0 0 59 215 21 0 0 0 0 0 0 0 0 0 12 235 255 255 255 247 34 0 0 0 0 0 0 0 12 235 255 255 255 255 255 255 255 255 251 89 0 12 235 255 255 255 255 255 225 21 0 89 255 255 255 255 255 255 125 0 12 235 255 255 255 255 255 225 21 0 0 12 235 255 255 255 255 255 225 21 7 206 201 0 50 206 56 255 201 12 235 125 0 0 138 225 29 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 89 255 225 21 0 89 255 255 255 225 81 245 201 0 138 251 89 0 0 138 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 255 255 255 225 21 0 0 0 138 255 166 7 206 225 21 0 0 0 138 247 34 0 0 0 0 127 0 89 255 125 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 59 241 89 12 235 125 0 0 172 89 0 0 0 0 0 0 0 0 0 12 235 166 0 0 7 202 89 0 0 0 0 0 0 89 255 201 0 0 12 235 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 138 247 34 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 89 225 21 71 157 22 191 225 21 175 201 0 7 206 125 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 59 196 199 47 206 184 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 59 245 125 0 0 59 245 125 0 0 0 0 0 127 12 235 166 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 255 255 127 34 235 255 255 255 255 225 21 0 0 0 0 0 0 0 0 89 247 34 7 206 166 0 89 201 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 59 115 12 235 166 0 0 0 12 235 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 59 245 125 0 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 7 202 89 117 104 0 29 202 89 59 215 21 59 215 21 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 59 192 89 223 125 172 89 0 138 255 255 255 201 12 182 0 0 0 0 0 175 255 255 125 0 89 255 255 247 34 0 0 12 146 0 0 0 0 0 144 21 0 138 255 255 255 255 247 34 138 247 34 7 206 201 0 0 0 0 0 0 127 89 251 89 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 7 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 89 247 34 7 206 166 7 202 89 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 0 89 255 125 89 247 34 0 0 0 12 235 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 7 206 201 0 0 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 59 192 12 228 34 172 89 89 247 34 0 12 206 29 206 201 0 0 7 206 166 0 7 206 255 225 21 0 89 247 34 0 12 146 0 0 0 0 0 144 21 0 0 0 0 7 206 166 0 12 235 166 89 247 34 0 0 0 0 0 0 127 245 255 255 255 255 255 201 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 59 245 255 255 255 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 59 241 89 12 235 125 89 201 12 235 255 251 89 0 89 255 255 225 21 0 175 255 255 225 21 0 0 0 89 251 89 0 138 225 21 0 0 0 12 235 255 255 255 255 225 21 0 12 146 0 0 0 0 0 144 21 0 0 0 0 138 247 34 0 0 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 59 192 0 0 0 172 89 138 225 21 0 0 0 0 7 206 225 21 138 225 21 0 0 89 251 89 0 0 12 235 125 0 12 146 0 0 0 0 0 144 21 0 0 0 0 138 225 21 0 0 89 255 255 125 0 0 0 0 0 0 0 127 138 225 21 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 12 235 255 255 255 255 225 21 0 0 0 0 0 0 0 0 0 138 255 255 201 12 228 34 175 166 0 138 201 7 206 125 7 206 166 0 0 0 89 255 255 247 34 59 241 89 0 0 138 225 21 0 0 0 12 235 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 59 245 125 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 255 255 207 235 255 255 255 255 255 255 207 235 255 255 255 255 255 255 255 255 255 255 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 247 34 0 0 0 0 175 166 175 201 0 0 0 59 245 255 255 255 255 255 125 0 12 146 0 0 0 0 0 144 21 0 0 0 89 251 89 0 0 0 7 206 225 21 0 0 0 0 0 0 0 127 245 255 255 255 255 255 125 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 7 206 125 0 89 247 94 241 89 0 138 201 0 0 0 0 0 59 245 166 0 89 251 89 0 89 247 34 0 0 0 12 235 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 7 206 201 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 255 201 0 7 206 225 21 175 201 0 0 0 59 241 89 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 12 235 166 0 0 0 0 0 175 225 21 0 0 0 0 0 0 0 127 89 255 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 7 206 125 0 89 247 94 241 89 0 138 201 0 0 0 0 0 12 235 166 0 0 89 255 125 12 235 166 0 0 0 12 235 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 138 247 34 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 42 206 201 0 0 89 225 21 0 0 89 255 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 175 225 21 0 0 0 0 0 175 225 21 0 0 0 0 0 0 0 127 0 175 251 89 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 59 245 166 0 0 138 225 21 0 0 0 59 245 166 138 251 89 7 206 201 0 12 235 125 0 59 241 89 0 0 0 175 125 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 175 166 0 138 201 7 206 125 7 206 166 138 166 0 0 0 138 251 89 0 0 0 59 115 0 89 255 201 0 0 12 235 125 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 89 251 89 0 0 0 0 0 0 12 146 0 0 0 0 0 144 21 0 0 12 146 0 0 0 0 0 144 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 138 225 34 182 0 0 0 7 206 166 0 7 206 255 247 34 0 0 175 125 0 12 146 0 0 0 0 0 144 21 0 89 251 89 0 0 0 0 0 0 175 225 21 0 0 0 0 0 0 0 127 0 0 138 255 255 255 255 125 0 12 235 255 255 255 255 255 225 21 0 138 247 34 0 7 206 166 0 0 0 0 89 247 34 175 201 0 7 206 201 0 12 235 125 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 215 21 0 0 12 235 255 251 89 0 89 255 255 225 21 12 235 255 255 255 247 34 0 0 0 0 0 0 0 0 12 235 255 255 255 255 255 255 255 255 251 89 0 12 235 255 255 255 255 255 225 21 0 138 255 255 255 255 255 255 166 0 12 235 255 255 255 255 255 225 21 0 0 12 235 255 255 255 255 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 247 34 0 0 0 0 0 0 0 175 255 255 125 0 138 255 255 255 125 0 0 12 235 255 255 255 255 255 225 21 0 175 255 255 255 255 247 0 0 0 175 225 21 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 0 255 255 201 0 0 0 0 0 175 166 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 0 0 0 0 0 0 12 232 89 59 215 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 0 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 245 255 255 255 255 255 255 225 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 0 0 0 59 192 0 0 0 0 0 7 206 255 255 225 21 0 0 0 0 0 0 0 0 138 247 34 0 0 89 251 89 0 7 206 125 0 0 7 206 255 255 255 166 0 89 251 89 138 247 34 0 0 0 0 7 206 255 255 255 247 34 0 0 0 0 175 255 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 247 34 0 0 7 206 255 251 89 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 0 59 245 255 247 34 0 0 0 0 0 0 0 0 0 0 0 89 201 0 0 0 0 175 166 0 0 0 0 0 0 89 201 0 0 0 0 175 166 0 0 0 0 0 59 245 255 201 0 0 0 59 241 89 0 0 0 0 0 59 245 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 0 0 0 59 192 0 0 0 0 0 175 201 0 0 144 21 0 0 0 0 0 0 0 0 7 206 166 0 7 206 166 0 0 7 206 125 0 7 206 201 0 0 89 166 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 59 245 166 0 0 0 0 0 0 12 206 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 59 245 166 0 0 0 0 0 0 0 0 0 0 59 241 89 0 138 201 0 0 0 0 0 138 166 0 0 0 0 0 168 34 7 206 166 0 0 172 89 0 175 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 166 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 251 89 0 0 12 235 125 0 138 225 21 0 0 0 0 0 0 0 0 7 206 255 201 0 0 0 89 225 21 0 0 0 0 7 206 255 201 0 0 0 89 225 21 0 0 0 0 12 206 21 12 235 125 0 0 175 166 0 0 0 0 0 0 59 245 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 175 255 255 255 166 0 0 12 235 125 0 0 0 0 89 225 21 0 0 12 232 89 0 89 247 34 89 247 34 0 0 7 206 125 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 89 225 21 0 0 0 0 0 7 206 125 0 0 7 206 255 255 247 34 0 0 0 85 89 0 85 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 225 21 0 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 89 201 0 0 12 228 34 0 0 0 0 138 166 0 0 0 0 0 0 0 7 206 125 0 0 7 206 255 166 0 0 0 0 0 0 0 0 0 12 235 125 0 0 89 247 34 175 255 255 255 166 89 225 21 0 89 255 125 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 89 225 21 0 12 232 89 59 115 0 59 115 0 0 0 0 0 89 201 0 0 7 206 125 0 0 0 0 0 0 0 89 201 0 0 7 206 125 0 0 0 0 0 0 0 0 12 232 89 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 225 21 0 0 138 247 94 192 12 182 0 0 12 235 125 0 0 0 0 0 175 255 255 255 255 166 0 0 7 206 171 206 166 0 0 0 7 206 125 0 7 206 251 89 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 59 245 255 255 201 0 12 228 34 12 235 166 0 12 228 34 0 0 138 251 89 138 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 138 255 255 255 125 0 12 228 34 0 0 0 0 0 0 0 0 59 241 89 0 138 201 0 0 0 0 0 138 166 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 12 235 125 0 0 89 247 34 175 255 255 255 166 89 225 21 0 89 255 125 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 138 225 21 0 12 235 125 12 235 166 59 245 166 0 0 0 0 89 201 0 0 89 225 21 0 0 0 0 0 0 0 89 201 0 0 89 225 21 0 0 0 0 0 0 12 235 255 125 0 0 175 125 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 225 21 0 12 235 125 59 192 0 0 0 0 12 235 125 0 0 0 0 0 59 215 21 59 238 34 0 0 0 89 255 247 34 0 0 0 7 206 125 0 0 7 206 255 255 247 34 0 0 0 0 0 0 0 0 59 192 0 12 235 166 0 7 176 21 0 175 125 59 238 34 0 12 228 34 0 138 247 34 138 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 192 0 0 138 201 0 89 247 34 0 175 125 0 0 0 0 0 0 0 0 0 89 255 255 225 21 0 7 206 255 255 255 255 255 255 247 34 0 12 235 125 0 0 0 7 176 21 0 175 201 0 0 0 0 0 0 0 0 12 235 125 0 0 89 247 34 89 255 255 255 166 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 89 225 21 0 12 232 89 0 12 235 166 12 235 166 0 0 0 89 201 0 7 206 125 0 12 235 166 0 0 0 0 89 201 0 7 206 125 89 255 255 255 125 0 0 0 0 7 206 125 89 225 21 0 138 225 21 0 0 0 138 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 59 241 89 59 192 0 0 0 12 235 255 255 255 225 21 0 0 138 166 0 7 202 89 0 0 0 7 206 166 0 0 0 0 0 0 0 0 7 206 125 0 12 235 201 0 0 0 0 0 0 0 0 89 166 0 89 247 34 0 0 0 0 0 89 166 12 232 89 0 138 247 34 89 247 34 59 238 34 0 0 12 235 255 255 255 255 255 255 247 34 89 255 255 255 166 89 166 0 0 138 201 0 138 225 21 0 89 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 7 206 255 255 255 247 34 0 59 245 255 247 34 0 0 0 0 0 0 0 0 12 235 125 0 0 89 247 34 0 89 255 255 166 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 166 0 12 235 125 0 138 225 21 0 0 12 235 125 12 235 125 0 0 89 201 0 89 201 0 7 206 223 166 0 0 0 0 89 201 0 89 201 0 89 125 0 138 225 21 12 182 0 7 206 133 206 125 0 89 232 215 21 0 7 206 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 59 241 89 59 192 0 0 0 0 12 235 125 0 0 0 0 0 59 215 21 59 238 34 0 59 245 255 255 255 255 225 21 0 0 0 0 0 59 241 89 0 0 138 225 21 0 0 0 0 0 0 0 89 166 0 89 247 34 0 0 0 0 0 89 166 0 138 255 255 176 228 34 0 138 247 34 138 247 34 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 89 166 0 0 138 255 255 225 21 0 0 89 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 89 247 34 0 0 0 138 166 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 247 34 0 0 12 235 166 12 235 166 0 0 0 0 0 12 232 89 0 175 166 138 166 0 0 0 0 0 0 12 232 89 0 0 0 0 138 201 0 0 89 255 255 201 89 225 21 89 225 81 215 21 0 138 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 12 235 125 59 192 0 0 0 0 59 241 89 0 0 0 0 0 175 255 255 255 255 166 0 0 0 7 206 166 0 0 0 0 7 206 125 0 12 235 201 0 7 206 166 0 0 0 0 0 0 0 0 59 192 0 12 235 166 0 7 176 21 0 175 125 0 0 0 0 0 0 0 0 0 138 251 89 138 247 34 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 59 192 0 0 138 201 59 245 166 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 89 247 34 0 0 0 138 166 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 166 59 245 166 0 0 0 0 0 0 138 201 0 138 201 0 138 166 0 0 0 0 0 0 138 201 0 0 0 0 89 247 34 0 0 0 0 0 7 206 125 59 238 34 59 215 21 0 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 247 34 0 0 175 225 81 192 12 182 0 7 206 125 0 0 0 0 0 89 225 21 0 0 12 232 89 0 0 7 206 166 0 0 0 0 7 206 125 0 0 59 245 255 255 166 0 0 0 0 0 0 0 0 0 7 202 89 0 59 245 255 255 166 0 12 228 34 0 0 0 0 0 0 0 0 0 0 85 89 0 85 89 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 7 202 89 0 138 201 0 59 245 225 34 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 255 255 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 201 0 0 175 247 34 0 0 0 138 166 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 115 0 59 115 0 0 0 0 0 0 12 232 89 0 175 255 255 255 255 201 0 0 0 0 12 232 89 0 0 0 138 201 0 0 0 0 0 0 0 89 201 0 89 255 255 255 255 247 34 138 251 89 0 7 176 21 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 247 34 0 0 0 175 255 255 255 166 0 89 255 255 255 255 255 247 34 0 0 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 7 206 125 0 0 0 0 0 138 255 166 0 0 0 0 0 0 0 0 0 89 225 21 0 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 0 89 225 21 0 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 191 255 255 166 238 34 0 0 0 138 166 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 201 0 0 0 0 0 138 166 0 0 0 0 0 175 201 0 0 0 89 255 255 255 255 125 0 0 0 12 232 89 0 0 0 0 59 215 21 0 0 138 255 255 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 59 192 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 59 245 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 59 245 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 138 166 89 225 21 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 59 192 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 7 199 34 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 138 166 89 225 21 0 0 0 0 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 7 206 255 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 138 225 21 0 0 0 0 0 12 235 125 0 0 0 0 19 172 255 190 11 0 0 0 0 138 255 201 7 202 89 0 0 0 0 0 0 0 0 0 0 7 206 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 138 225 21 0 0 0 0 0 0 59 245 201 0 0 0 19 172 255 190 11 0 0 0 0 0 0 0 0 0 7 206 225 21 0 0 0 59 245 201 19 172 255 190 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 251 89 89 201 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 7 206 225 21 0 0 0 0 0 19 172 255 190 11 0 0 0 0 0 175 255 166 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 0 12 175 247 34 0 0 0 19 172 255 190 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 7 206 125 0 0 0 0 0 138 201 0 0 0 0 0 136 190 45 196 145 0 0 0 59 215 21 175 255 166 0 0 0 175 225 29 206 166 0 0 7 202 89 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 209 125 0 0 0 0 0 0 138 225 21 0 0 0 136 190 45 196 145 0 0 0 175 225 29 206 166 0 0 12 235 125 0 0 12 138 225 21 136 190 45 196 145 159 251 89 138 247 34 0 0 0 0 0 0 0 0 0 0 0 175 125 59 245 247 34 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 175 166 0 0 0 0 0 0 12 136 190 45 196 145 0 0 0 0 138 166 12 235 255 125 0 0 0 0 7 206 166 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 138 201 0 0 0 0 0 136 190 45 196 145 34 0 0 0 89 251 89 138 247 34 0 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 125 0 0 0 0 127 0 0 7 206 251 89 0 0 0 0 7 206 251 89 0 0 0 0 7 206 251 89 0 0 0 0 0 7 206 251 89 0 0 0 0 7 206 251 89 0 0 0 0 12 235 255 125 0 0 0 0 0 89 255 255 255 255 255 255 255 255 125 0 0 0 59 245 255 255 255 201 12 235 255 255 255 255 255 125 12 235 255 255 255 255 255 125 12 235 255 255 255 255 255 125 12 235 255 255 255 255 255 125 89 255 255 255 201 89 255 255 255 201 89 255 255 255 201 89 255 255 255 201 0 175 255 255 255 255 201 0 0 0 12 235 251 89 0 0 12 235 125 0 0 0 138 255 255 166 0 0 0 0 0 0 138 255 255 166 0 0 0 0 0 0 138 255 255 166 0 0 0 0 0 0 138 255 255 166 0 0 0 0 0 0 138 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 255 201 89 251 89 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 7 206 225 21 0 0 0 138 247 0 235 166 0 0 0 0 0 0 138 225 21 7 206 166 0 0 0 127 0 0 59 245 255 166 0 0 0 0 59 245 255 166 0 0 0 0 59 245 255 166 0 0 0 0 0 59 245 255 166 0 0 0 0 59 245 255 166 0 0 0 0 59 245 255 166 0 0 0 0 0 175 201 7 206 166 0 0 0 0 0 0 0 138 255 125 0 0 7 202 102 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 175 201 0 0 7 206 251 89 0 12 235 255 201 0 0 12 235 125 0 59 245 166 0 0 138 251 89 0 0 59 245 166 0 0 138 251 89 0 0 59 245 166 0 0 138 251 89 0 0 59 245 166 0 0 138 251 89 0 0 59 245 166 0 0 138 251 89 0 0 0 0 0 0 0 0 0 0 0 0 59 245 166 0 0 89 255 166 0 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 0 59 245 125 0 0 59 245 125 12 235 166 0 0 0 0 0 12 235 125 0 0 175 201 0 0 0 127 0 0 138 225 151 225 21 0 0 0 138 225 151 225 21 0 0 0 138 225 151 225 21 0 0 0 0 138 225 151 225 21 0 0 0 138 225 151 225 21 0 0 0 138 225 151 225 21 0 0 0 59 241 89 7 206 166 0 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 175 201 0 0 0 0 175 225 21 12 235 166 245 125 0 12 235 125 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 0 138 225 21 0 0 0 175 201 0 12 235 125 0 0 7 202 159 247 34 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 0 0 138 247 34 7 206 201 0 12 235 255 255 255 251 89 0 12 235 125 0 12 235 125 0 0 0 127 0 7 206 166 59 241 89 0 0 7 206 166 59 241 89 0 0 7 206 166 59 241 89 0 0 0 7 206 166 59 241 89 0 0 7 206 166 59 241 89 0 0 7 206 166 59 241 89 0 0 0 138 225 21 7 206 166 0 0 0 0 0 0 89 247 34 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 175 201 0 0 0 0 59 241 89 12 235 125 138 225 21 12 235 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 0 0 175 225 21 0 175 225 21 0 89 247 34 0 0 138 166 12 235 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 0 0 12 235 166 89 247 34 0 12 235 166 0 0 138 251 89 12 235 133 206 255 125 0 0 0 0 127 0 59 241 89 7 206 166 0 0 59 241 89 7 206 166 0 0 59 241 89 7 206 166 0 0 0 59 241 89 7 206 166 0 0 59 241 89 7 206 166 0 0 59 241 89 7 206 166 0 0 12 235 125 0 7 206 255 255 255 255 247 34 0 138 225 21 0 0 0 0 0 12 235 255 255 255 255 247 34 12 235 255 255 255 255 247 34 12 235 255 255 255 255 247 34 12 235 255 255 255 255 247 34 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 206 255 255 255 247 34 0 12 235 125 12 235 125 12 235 125 12 235 125 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 0 0 0 175 225 187 225 21 0 0 138 225 21 0 59 215 21 7 206 166 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 0 0 0 89 255 255 125 0 0 12 235 166 0 0 12 235 166 12 235 125 0 7 206 201 0 0 0 127 0 138 225 21 0 138 225 21 0 138 225 21 0 138 225 21 0 138 225 21 0 138 225 21 0 0 138 225 21 0 138 225 21 0 138 225 21 0 138 225 21 0 138 225 21 0 138 225 21 0 89 255 255 255 255 255 166 0 0 0 0 0 0 138 225 21 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 175 201 0 0 0 0 12 235 125 12 235 125 0 138 225 34 235 125 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 138 225 21 0 0 0 0 12 235 166 0 0 0 0 175 225 21 0 0 0 138 225 21 7 202 89 0 7 206 166 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 12 235 125 0 0 0 59 245 125 0 0 0 7 206 225 21 0 0 12 235 166 0 0 12 235 166 12 235 125 0 0 59 241 89 0 0 127 7 206 255 255 255 255 251 89 7 206 255 255 255 255 251 89 7 206 255 255 255 255 251 89 0 7 206 255 255 255 255 251 89 7 206 255 255 255 255 251 89 7 206 255 255 255 255 251 89 7 206 166 0 0 7 206 166 0 0 0 0 0 0 89 247 34 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 175 201 0 0 0 0 59 241 89 12 235 125 0 12 235 138 235 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 89 247 34 0 0 0 0 59 245 125 0 0 0 175 225 187 225 21 0 0 138 247 34 175 125 0 0 12 235 125 12 235 125 0 0 0 59 241 89 12 235 125 0 0 0 59 241 89 12 235 125 0 0 0 59 241 89 12 235 125 0 0 0 59 241 89 0 0 0 0 175 225 21 0 0 12 235 166 0 0 175 247 34 12 235 125 0 0 12 235 125 0 0 127 59 241 89 0 0 7 206 166 59 241 89 0 0 7 206 166 59 241 89 0 0 7 206 166 0 59 241 89 0 0 7 206 166 59 241 89 0 0 7 206 166 59 241 89 0 0 7 206 166 59 241 89 0 0 7 206 166 0 0 0 0 0 0 59 245 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 175 201 0 0 0 0 175 225 21 12 235 125 0 0 138 232 245 125 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 12 235 125 0 0 0 0 138 247 34 0 0 175 225 21 0 175 225 21 0 59 245 191 201 0 0 0 89 225 21 12 235 166 0 0 0 89 251 89 12 235 166 0 0 0 89 251 89 12 235 166 0 0 0 89 251 89 12 235 166 0 0 0 89 251 89 0 0 0 0 175 225 21 0 0 12 235 255 255 255 247 34 0 12 235 125 0 0 59 241 89 0 0 127 138 225 21 0 0 0 138 247 163 225 21 0 0 0 138 247 163 225 21 0 0 0 138 247 34 138 225 21 0 0 0 138 247 163 225 21 0 0 0 138 247 163 225 21 0 0 0 138 247 198 225 21 0 0 7 206 166 0 0 0 0 0 0 0 138 255 125 0 0 7 202 102 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 12 235 166 0 0 0 0 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 12 235 125 0 0 175 201 0 0 7 206 251 89 0 12 235 125 0 0 12 235 255 125 0 89 255 125 0 0 89 251 89 0 0 89 255 125 0 0 89 251 89 0 0 89 255 125 0 0 89 251 89 0 0 89 255 125 0 0 89 251 89 0 0 89 255 125 0 0 89 251 89 0 0 138 225 21 0 0 0 175 201 0 0 138 251 89 0 0 89 251 89 0 0 138 247 34 0 7 206 225 21 0 138 247 34 0 7 206 225 21 0 138 247 34 0 7 206 225 21 0 138 247 34 0 7 206 225 21 0 0 0 0 175 225 21 0 0 12 235 166 0 0 0 0 0 12 235 125 0 0 175 225 21 0 0 127 206 166 0 0 0 0 59 245 255 166 0 0 0 0 59 245 255 166 0 0 0 0 59 245 133 206 166 0 0 0 0 59 245 255 166 0 0 0 0 59 245 255 166 0 0 0 0 59 245 255 125 0 0 0 7 206 255 255 255 255 255 125 0 0 0 59 245 255 255 255 201 12 235 255 255 255 255 255 125 12 235 255 255 255 255 255 125 12 235 255 255 255 255 255 125 12 235 255 255 255 255 255 125 89 255 255 255 201 89 255 255 255 201 89 255 255 255 201 89 255 255 255 201 0 175 255 255 255 255 225 21 0 0 12 235 125 0 0 0 138 255 125 0 0 0 175 255 255 201 0 0 0 0 0 0 175 255 255 201 0 0 0 0 0 0 175 255 255 201 0 0 0 0 0 0 175 255 255 201 0 0 0 0 0 0 175 255 255 201 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 97 206 255 255 201 0 0 0 0 0 138 255 255 255 201 0 0 0 0 138 255 255 255 201 0 0 0 0 138 255 255 255 201 0 0 0 0 138 255 255 255 201 0 0 0 0 0 0 175 225 21 0 0 12 235 166 0 0 0 0 0 12 235 133 206 255 225 21 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 7 206 225 21 0 0 0 0 0 12 235 225 21 0 0 89 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 247 34 0 0 0 0 0 0 0 138 251 89 0 0 59 245 247 34 0 0 0 0 0 0 0 0 0 175 247 34 0 0 175 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 225 21 0 0 0 0 0 0 0 138 255 125 0 0 0 12 235 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 251 89 0 0 0 0 0 0 7 206 225 21 0 0 0 7 206 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 59 241 89 0 0 0 0 0 89 247 34 0 0 7 206 138 235 125 0 0 89 255 225 21 175 125 0 0 0 0 0 0 0 0 0 138 201 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 12 235 125 0 0 0 175 171 206 166 0 0 0 0 0 0 0 0 0 7 206 166 0 59 245 255 166 238 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 125 59 215 21 0 0 59 241 89 0 0 0 0 0 0 7 206 166 0 0 0 0 138 201 175 201 0 0 0 12 235 251 89 89 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 0 0 89 247 34 0 0 0 0 89 225 151 201 0 0 0 0 0 0 0 0 0 0 0 0 0 175 201 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 138 201 0 0 0 0 7 206 125 0 0 0 138 201 0 89 225 21 12 228 34 138 255 201 0 0 0 138 247 34 175 225 21 0 138 201 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 225 21 0 0 0 0 0 89 225 21 0 0 89 247 34 59 241 89 0 59 241 89 89 247 34 0 0 89 225 21 175 127 215 21 206 247 42 206 0 138 255 247 42 206 125 0 0 138 166 12 235 251 89 0 0 0 0 138 201 0 0 0 0 0 0 89 225 21 0 0 0 59 241 89 12 235 125 0 0 175 125 59 245 247 34 0 0 12 235 125 89 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 175 166 0 0 0 0 12 232 89 7 206 125 0 0 12 235 166 59 245 125 0 0 0 59 238 34 0 12 235 125 0 0 0 0 0 0 89 247 34 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 12 235 255 255 255 166 0 12 235 255 255 255 166 0 12 235 255 255 255 166 0 12 235 255 255 255 166 0 0 12 235 255 255 255 166 0 12 235 255 255 255 166 0 12 235 255 255 255 166 0 175 255 255 125 0 0 12 235 255 255 125 0 0 12 235 255 255 225 21 0 0 12 235 255 255 225 21 0 12 235 255 255 225 21 0 12 235 255 255 225 21 0 12 235 125 12 235 125 12 235 125 12 235 125 0 12 235 125 89 251 89 0 12 235 138 235 255 247 34 0 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 0 0 0 175 247 34 0 0 0 12 235 255 255 255 166 0 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 42 206 201 0 0 0 138 232 245 166 245 255 251 89 7 206 201 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 12 206 21 0 59 245 125 12 206 21 0 59 245 125 12 206 21 0 59 245 125 12 206 21 0 59 245 125 0 12 206 21 0 59 245 125 12 206 21 0 59 245 125 12 206 21 0 12 235 255 125 0 7 206 166 12 235 166 0 0 172 102 0 235 125 0 0 175 201 0 12 235 125 0 0 175 201 12 235 125 0 0 175 201 12 235 125 0 0 175 201 0 12 235 125 12 235 125 12 235 125 12 235 125 0 0 0 0 0 175 201 0 12 235 247 34 0 175 201 0 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 0 0 0 0 175 247 34 0 0 12 235 166 0 12 235 201 0 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 89 247 34 0 7 206 176 235 225 21 0 175 225 21 89 247 34 0 7 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 7 206 166 0 0 0 0 7 206 166 0 0 0 0 7 206 166 0 0 0 0 7 206 166 0 0 0 0 0 7 206 166 0 0 0 0 7 206 166 0 0 0 0 0 175 201 0 0 0 89 225 138 225 21 0 0 0 0 89 225 21 0 0 89 247 34 89 225 21 0 0 89 247 124 225 21 0 0 89 247 124 225 21 0 0 89 247 34 12 235 125 12 235 125 12 235 125 12 235 125 0 89 255 255 255 255 247 34 12 235 125 0 0 89 247 34 138 225 21 0 0 59 238 34 138 225 21 0 0 59 238 34 138 225 21 0 0 59 238 34 138 225 21 0 0 59 238 34 138 225 21 0 0 59 238 34 0 0 0 0 0 0 0 0 0 138 225 21 0 172 132 238 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 12 235 125 0 59 238 47 235 125 0 0 59 241 89 12 235 125 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 59 245 255 255 255 166 0 59 245 255 255 255 166 0 59 245 255 255 255 166 0 59 245 255 255 255 166 0 0 59 245 255 255 255 166 0 59 245 255 255 255 166 0 89 255 255 255 255 255 255 255 255 255 247 175 201 0 0 0 0 0 175 255 255 255 255 255 247 34 175 255 255 255 255 255 247 198 255 255 255 255 255 247 198 255 255 255 255 255 247 34 12 235 125 12 235 125 12 235 125 12 235 125 89 251 89 0 0 59 241 89 12 235 125 0 0 89 247 34 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 7 206 255 255 255 255 255 255 251 226 201 0 89 166 12 232 89 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 0 175 201 0 138 201 12 235 125 0 0 12 235 125 0 175 201 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 89 255 166 0 7 206 166 89 255 166 0 7 206 166 89 255 166 0 7 206 166 89 255 166 0 7 206 166 0 89 255 166 0 7 206 166 89 255 166 0 7 206 166 138 255 125 0 0 175 201 0 0 0 0 0 175 201 0 0 0 0 0 175 201 0 0 0 0 0 0 175 201 0 0 0 0 0 175 201 0 0 0 0 0 175 201 0 0 0 0 0 0 12 235 125 12 235 125 12 235 125 12 235 125 175 201 0 0 0 59 241 89 12 235 125 0 0 89 247 34 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 175 201 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 175 201 7 176 21 12 232 89 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 0 89 247 47 235 125 12 235 125 0 0 12 235 125 0 89 247 47 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 175 201 0 0 7 206 166 175 201 0 0 7 206 166 175 201 0 0 7 206 166 175 201 0 0 7 206 166 0 175 201 0 0 7 206 166 175 201 0 0 7 206 166 175 201 0 0 0 138 225 21 0 0 0 0 138 225 21 0 0 0 0 138 247 34 0 0 0 0 0 138 247 34 0 0 0 0 138 247 34 0 0 0 0 138 247 34 0 0 0 0 0 12 235 125 12 235 125 12 235 125 12 235 125 175 201 0 0 0 89 247 34 12 235 125 0 0 89 247 34 138 225 21 0 0 89 247 34 138 225 21 0 0 89 247 34 138 225 21 0 0 89 247 34 138 225 21 0 0 89 247 34 138 225 21 0 0 89 247 34 0 0 0 0 175 247 34 0 0 138 225 151 125 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 59 241 89 0 0 89 247 34 0 12 235 191 247 34 12 235 125 0 0 59 241 89 0 12 235 191 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 138 225 21 0 138 255 166 138 225 21 0 138 255 166 138 225 21 0 138 255 166 138 225 21 0 138 255 166 0 138 225 21 0 138 255 166 138 225 21 0 138 255 166 89 247 34 0 89 255 255 166 0 0 12 206 12 235 166 0 0 127 102 0 235 201 0 0 12 206 21 12 235 201 0 0 12 206 34 235 201 0 0 12 206 34 235 201 0 0 12 206 21 12 235 125 12 235 125 12 235 125 12 235 125 89 255 125 0 7 206 166 0 12 235 125 0 0 89 247 34 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 12 235 166 0 7 206 201 0 0 0 0 0 175 247 34 0 0 12 235 201 0 7 206 201 0 7 206 166 0 59 245 247 34 7 206 166 0 59 245 247 34 7 206 166 0 59 245 247 34 7 206 166 0 59 245 247 34 0 0 138 255 166 0 12 235 125 0 7 206 201 0 0 0 138 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 7 206 255 255 171 206 166 7 206 255 255 171 206 166 7 206 255 255 171 206 166 7 206 255 255 171 206 166 0 7 206 255 255 171 206 166 7 206 255 255 171 206 166 0 89 255 255 201 0 0 175 255 255 247 34 0 12 235 255 255 166 0 0 7 206 255 255 247 34 0 0 7 206 255 255 247 34 0 7 206 255 255 247 34 0 7 206 255 255 247 34 0 12 235 125 12 235 125 12 235 125 12 235 125 0 89 255 255 255 201 0 0 12 235 125 0 0 89 247 34 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 12 235 255 255 201 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 255 201 0 0 0 59 245 255 225 111 247 34 0 59 245 255 225 111 247 34 0 59 245 255 225 111 247 34 0 59 245 255 225 111 247 34 0 0 59 241 89 0 12 235 255 255 255 225 21 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 12 235 125 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 0 0 12 235 125 0 0 0 0 0 0 7 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 12 235 125 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 0 127 127 0 127 127 0 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/FontNormal.pgm0000644000000000000000000017753612635011627026147 0ustar rootrootP2 # Created by Paint Shop Pro 253 106 255 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 0 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 255 255 0 0 0 0 0 255 0 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 0 255 0 0 255 255 255 255 255 255 0 0 0 255 255 255 0 0 255 255 255 255 255 255 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 255 255 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 255 255 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 255 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 0 0 255 0 255 0 255 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 255 255 255 255 0 0 255 255 255 255 255 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 0 255 255 0 0 0 0 255 255 255 255 255 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 255 255 0 0 0 0 255 255 0 0 255 0 0 255 255 0 0 0 255 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 255 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 255 255 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 255 255 255 255 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 255 0 255 255 255 255 255 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 255 255 255 255 255 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 255 255 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 255 255 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 255 255 255 0 0 0 255 255 255 255 255 0 255 255 255 255 255 255 0 0 255 255 255 255 0 0 0 0 0 0 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 0 0 0 0 0 0 255 255 255 255 0 0 0 255 255 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 0 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 0 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 255 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 255 255 255 255 0 0 0 0 0 0 0 255 0 0 0 0 255 255 255 255 255 0 0 0 0 255 255 255 255 0 255 255 255 255 255 0 0 0 255 255 255 255 255 255 0 255 255 255 255 255 0 0 0 255 255 255 255 0 0 255 0 0 0 0 0 255 0 255 255 255 0 0 255 255 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 255 0 0 0 0 255 255 0 255 255 0 0 0 0 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 255 0 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 0 255 255 255 255 0 0 255 255 255 255 255 255 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 255 255 255 255 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 0 0 0 0 255 255 0 0 0 0 255 0 255 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 0 255 255 0 0 0 0 255 255 0 255 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 255 255 255 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 255 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 255 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 255 0 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 255 255 255 255 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 255 255 255 255 255 0 255 255 255 255 255 0 255 0 0 0 255 255 255 0 255 255 255 255 255 255 255 0 0 255 0 0 0 0 0 255 0 255 255 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 255 255 255 0 0 0 0 255 255 255 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 255 0 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 255 0 0 255 0 255 0 0 0 255 0 255 0 255 0 0 0 0 0 0 255 0 255 255 255 255 255 0 0 255 0 0 0 0 0 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 255 0 0 0 255 0 0 255 0 0 255 255 255 255 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 255 255 0 0 255 0 255 0 0 0 255 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 0 255 255 0 0 0 255 255 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 255 255 255 255 255 255 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 255 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 255 255 255 255 0 0 0 0 255 255 255 255 0 255 255 255 255 255 0 0 0 255 255 255 255 255 255 0 255 0 0 0 0 0 0 0 255 255 255 255 255 0 255 0 0 0 0 0 255 0 255 255 255 0 255 255 255 0 0 255 0 0 0 0 255 0 255 255 255 255 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 255 0 0 0 255 255 255 255 0 0 0 255 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 255 0 0 0 0 255 0 0 255 255 255 255 0 0 0 0 0 255 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 255 255 255 255 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 255 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 255 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 255 255 255 0 0 255 0 255 255 255 0 0 0 255 255 255 255 0 0 255 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 255 255 255 255 255 0 255 0 255 255 255 0 0 255 0 255 255 0 255 0 0 0 255 0 255 0 255 255 255 255 0 255 255 255 0 0 255 0 255 255 255 0 0 0 255 255 255 255 0 0 255 0 255 255 255 0 0 0 255 255 255 255 255 0 255 0 255 0 0 255 255 255 0 255 255 255 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 255 255 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 255 0 255 255 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 255 0 0 0 0 255 0 255 255 0 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 255 0 0 0 255 0 255 255 0 0 0 255 0 255 0 0 0 0 255 0 255 255 0 0 0 255 0 255 0 0 0 0 255 0 255 255 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 255 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 255 255 255 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 255 255 255 255 255 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 255 255 0 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 255 0 255 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 255 255 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 255 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 255 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 255 255 0 255 0 0 0 0 255 0 0 255 0 0 255 0 0 0 255 255 0 255 0 0 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 255 255 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 255 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 255 255 255 255 0 255 255 255 255 255 0 0 0 255 255 255 255 0 0 255 255 255 0 255 0 0 255 255 255 255 0 0 0 255 0 0 0 255 255 255 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 255 0 0 0 255 0 255 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 255 255 255 255 0 0 255 255 255 255 255 0 0 0 255 255 255 0 255 0 255 0 0 0 255 255 255 0 0 0 0 255 255 0 0 255 255 255 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 255 255 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 255 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 0 127 127 0 127 127 127 127 127 0 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 127 0 0 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 255 0 0 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 255 0 0 0 255 255 255 0 255 0 0 0 255 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 0 0 255 255 0 0 255 0 0 0 0 0 255 0 127 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 0 0 255 255 255 255 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 255 0 0 0 255 0 255 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 127 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 255 0 255 0 0 255 255 255 0 0 255 0 0 0 0 255 255 255 255 0 255 255 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 255 255 255 0 0 255 0 0 0 255 0 0 127 255 255 255 255 255 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 0 0 127 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 255 0 0 255 255 0 0 0 255 255 0 0 0 255 255 255 255 0 0 0 255 0 0 0 255 0 0 0 0 0 255 255 255 255 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 127 255 255 255 255 255 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 255 255 255 255 255 0 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 255 0 255 0 0 0 0 255 255 255 255 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 127 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 127 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 255 0 0 0 0 127 0 0 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 0 255 0 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 255 255 255 255 0 255 255 255 255 0 0 0 255 255 255 255 255 255 255 255 255 0 255 255 255 255 0 0 0 0 255 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 255 255 255 255 0 0 255 0 0 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 255 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 255 255 0 0 0 255 0 0 0 0 0 0 255 255 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 0 255 255 255 255 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 0 255 0 0 0 0 255 255 255 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 255 255 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 255 255 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 255 255 255 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 255 255 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 255 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 255 255 0 0 0 0 255 0 0 255 0 255 255 255 0 0 0 0 0 0 255 0 255 0 0 255 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 255 255 255 255 255 0 0 0 255 0 0 255 0 0 0 255 255 255 255 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 255 255 255 0 255 0 0 255 0 0 0 0 255 255 255 255 255 255 255 0 255 255 255 0 255 0 0 255 255 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 255 255 0 255 0 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 255 255 255 255 255 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 0 255 255 255 255 0 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 255 255 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 255 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 255 0 255 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 0 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 0 255 255 255 255 0 0 0 255 255 0 0 0 0 255 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 255 255 255 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 0 255 0 255 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 255 255 255 255 255 0 255 0 0 0 0 0 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 255 255 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 255 255 255 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 255 255 0 0 0 255 255 255 255 255 0 0 0 255 255 255 255 255 0 0 0 255 255 255 255 255 0 0 0 255 255 255 255 255 0 0 0 255 255 255 255 255 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 255 255 255 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 255 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 255 255 255 255 255 0 0 0 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 0 255 255 255 255 0 0 0 255 0 0 0 0 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 255 0 255 0 255 255 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 255 0 255 0 255 255 0 255 0 0 255 0 255 0 0 0 255 0 255 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 255 255 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 255 255 255 0 0 255 255 0 0 0 0 255 255 255 255 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 0 255 0 0 255 0 0 255 0 0 255 255 0 255 0 0 255 0 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 255 255 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 255 255 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 0 0 0 0 255 0 255 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 255 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 255 255 255 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 255 255 255 255 255 0 255 0 0 0 0 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 255 255 255 255 255 255 0 255 0 0 255 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 255 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 255 0 0 0 255 255 0 255 0 0 0 255 255 0 255 0 0 0 255 255 0 255 0 0 0 255 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 0 255 255 255 255 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 0 255 0 0 255 0 0 255 0 0 255 255 255 255 0 0 255 0 0 0 0 255 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 0 255 0 0 0 0 0 255 255 255 255 0 0 0 0 255 255 255 0 255 0 0 255 255 255 0 255 0 0 255 255 255 0 255 0 0 255 255 255 0 255 0 0 0 255 0 0 0 255 255 255 255 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 0 127 0 127 127 0 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/FontNormalAA.pgm0000644000000000000000000021775612635011627026350 0ustar rootrootP2 # Created by Paint Shop Pro 264 106 255 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 59 241 97 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 168 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 251 89 0 0 89 255 125 89 255 125 0 0 0 0 7 199 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 59 238 42 206 125 0 0 0 0 7 199 34 89 166 0 0 0 0 168 34 0 0 0 175 255 255 166 0 0 7 202 89 0 0 0 0 59 245 255 251 89 0 0 0 59 238 34 0 12 232 89 0 0 89 247 34 0 59 245 206 199 124 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 12 235 255 247 34 0 0 0 0 12 232 89 0 0 12 235 255 255 251 89 0 7 206 255 255 255 125 0 0 0 0 138 251 89 0 0 59 245 255 255 255 251 89 0 0 89 255 255 166 0 89 255 255 255 255 255 201 0 0 59 245 255 255 125 0 0 12 235 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 59 238 34 175 125 0 0 0 0 59 192 0 172 89 0 0 59 245 255 255 251 89 89 247 34 12 228 34 0 138 166 0 0 0 0 12 235 125 0 175 225 21 0 0 59 238 34 0 138 201 0 0 0 0 175 166 0 0 0 89 255 201 0 0 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 215 21 0 175 166 0 138 201 0 0 7 206 255 251 89 0 0 59 192 0 0 138 247 34 59 192 0 0 89 251 89 0 0 59 245 251 89 0 0 59 241 89 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 7 206 166 0 7 206 125 0 89 247 34 7 206 166 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 175 166 0 0 0 0 0 0 0 89 125 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 12 206 21 175 125 0 0 89 255 255 255 255 255 255 166 59 241 89 168 34 138 125 89 225 21 7 202 89 12 228 34 0 0 0 0 12 232 89 0 138 201 0 0 0 12 206 21 7 202 89 0 0 0 0 59 215 21 59 245 206 199 124 255 125 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 12 232 89 0 59 238 34 0 0 0 59 241 89 0 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 12 232 132 241 89 0 0 59 241 89 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 89 247 34 0 12 232 89 0 12 232 89 59 241 89 0 59 241 89 0 138 247 34 0 0 138 247 34 0 0 0 0 0 12 235 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 166 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 172 89 59 192 0 0 59 238 34 168 34 0 0 89 247 34 12 228 34 138 166 0 0 0 0 0 0 138 251 159 247 34 0 0 0 0 0 0 59 238 34 0 0 0 0 7 202 89 0 0 7 199 34 0 0 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 59 241 89 0 59 241 89 0 0 0 59 241 89 0 0 0 0 0 0 89 247 34 0 0 0 0 138 201 0 7 206 125 59 241 89 0 0 59 245 255 255 251 89 0 12 235 255 255 255 125 0 0 0 0 7 206 166 0 0 0 175 251 89 138 201 0 59 241 89 0 12 235 125 0 138 247 34 0 0 138 247 34 0 0 0 59 245 247 34 0 0 0 0 7 206 255 255 255 255 255 255 125 0 0 0 0 138 255 201 0 0 0 0 0 0 89 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 12 206 21 138 125 0 0 7 206 255 247 34 0 0 0 175 255 255 166 59 215 21 175 255 255 125 0 0 138 171 206 166 0 175 201 0 0 0 0 89 201 0 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 12 235 255 255 255 255 255 255 125 0 0 0 0 138 255 255 251 89 0 0 0 0 0 59 215 21 0 59 241 89 0 59 241 89 0 0 0 59 241 89 0 0 0 0 0 12 235 166 0 0 0 138 255 255 125 0 175 201 0 59 241 89 0 0 0 0 0 0 175 247 34 59 241 89 0 89 247 34 0 0 0 89 247 34 0 0 0 89 255 255 255 125 0 12 235 166 0 59 245 125 0 0 0 0 0 0 0 0 0 0 0 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 251 89 0 0 7 206 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 201 0 0 0 0 0 0 0 12 235 255 255 255 255 255 225 21 0 0 0 175 255 251 89 0 0 0 0 0 175 125 89 225 21 59 238 34 89 225 21 12 235 166 175 166 0 0 0 0 89 201 0 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 0 0 0 0 12 235 166 0 0 0 0 0 0 59 241 97 206 255 255 255 255 255 125 0 0 0 0 0 59 241 89 59 238 34 0 12 235 125 0 0 12 235 125 0 0 0 12 232 89 0 59 245 125 0 89 255 255 232 241 89 0 0 0 0 0 0 0 0 0 0 0 0 59 245 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 201 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 125 12 206 21 0 0 0 0 0 168 34 175 166 0 0 0 0 59 215 21 138 201 0 12 228 34 138 225 21 0 12 235 251 89 0 0 0 0 59 215 21 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 12 232 89 0 59 238 34 0 0 0 59 241 89 0 0 0 12 235 166 0 0 0 0 0 0 0 12 235 125 0 0 0 59 241 89 0 0 0 0 0 0 59 241 89 12 232 89 0 12 232 89 0 0 138 225 21 0 0 0 59 238 34 0 7 206 166 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 247 34 0 0 7 206 255 255 255 255 255 255 125 0 0 138 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 172 89 89 166 0 0 0 89 166 0 168 42 206 125 0 0 0 7 202 89 0 89 225 21 59 238 34 89 251 89 0 0 175 255 201 0 0 0 0 7 202 89 0 0 0 0 59 215 21 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 0 0 138 247 34 0 0 0 0 0 7 206 201 0 12 228 34 0 0 0 175 166 0 138 201 0 0 0 0 59 241 89 0 0 12 235 166 0 0 0 0 89 166 0 0 89 251 89 0 0 0 59 241 89 0 0 59 192 0 0 175 225 21 0 175 201 0 138 225 21 0 12 235 125 0 0 0 0 12 235 166 0 59 241 89 0 0 0 7 206 166 0 0 138 247 34 0 0 59 245 125 0 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 175 166 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 12 206 21 138 125 0 0 0 12 235 255 255 255 166 0 0 0 0 138 201 0 0 0 175 255 255 125 0 0 138 255 255 255 125 12 235 247 0 0 0 0 138 201 0 0 0 0 175 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 0 0 7 206 201 0 89 201 0 0 0 0 12 235 255 247 34 0 0 7 206 255 255 255 225 21 89 255 255 255 255 255 166 59 245 255 255 251 89 0 0 0 0 59 241 89 0 0 12 235 255 255 225 21 0 0 12 235 255 251 89 0 0 175 225 21 0 0 0 0 0 59 245 255 255 125 0 0 89 255 255 166 0 0 0 138 247 34 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 168 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 4 4 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 168 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 89 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 201 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 127 127 127 127 0 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 125 138 166 0 0 0 89 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 89 255 255 255 255 166 0 0 0 0 0 12 235 225 21 0 0 59 245 255 255 255 251 89 0 0 0 59 245 255 255 251 89 59 245 255 255 255 247 34 0 0 59 245 255 255 255 255 127 81 245 255 255 255 255 127 0 0 59 245 255 255 255 166 0 59 241 89 0 0 0 59 241 89 89 255 255 255 125 7 206 255 251 89 59 241 89 0 0 89 255 166 59 241 89 0 0 0 0 59 245 225 21 0 0 7 206 251 89 59 245 247 34 0 0 59 241 89 0 0 138 255 255 255 166 0 0 59 245 255 255 255 225 21 0 0 0 138 255 255 255 166 0 0 59 245 255 255 255 251 89 0 0 0 59 245 255 255 201 89 255 255 255 255 255 255 255 125 59 241 89 0 0 0 59 241 97 206 166 0 0 0 0 175 201 175 201 0 0 7 206 201 0 0 0 175 171 206 225 21 0 0 59 245 166 245 125 0 0 0 89 251 89 89 255 255 255 255 255 127 0 228 34 0 0 59 215 21 0 0 0 0 12 228 34 0 0 0 59 245 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 175 225 21 0 0 0 175 225 21 0 0 0 89 232 241 89 0 0 59 241 89 0 0 138 225 21 0 89 255 125 0 0 59 192 59 241 89 0 0 175 251 89 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 89 255 125 0 0 7 199 34 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 0 0 0 59 245 255 125 0 0 89 255 251 89 59 245 255 201 0 0 59 241 89 0 138 251 89 0 12 235 166 0 59 241 89 0 7 206 225 21 0 138 251 89 0 12 235 166 0 59 241 89 0 0 138 247 34 0 12 235 125 0 7 176 21 0 0 59 241 89 0 0 0 59 241 89 0 0 0 59 241 89 138 225 21 0 0 12 235 125 89 225 21 0 59 245 247 34 0 12 232 89 12 235 166 0 7 206 166 0 89 247 34 0 7 206 125 0 0 0 0 0 7 206 166 12 228 34 0 0 7 202 89 0 0 0 0 12 228 34 0 0 12 235 133 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 138 201 0 138 255 255 255 125 138 166 0 0 7 206 166 175 166 0 0 59 241 89 0 0 89 247 34 7 206 166 0 0 0 0 0 59 241 89 0 0 0 175 225 21 59 241 89 0 0 0 0 59 241 89 0 0 0 0 7 206 166 0 0 0 0 0 0 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 59 241 89 0 0 59 241 89 0 0 0 0 59 241 159 225 21 0 175 166 241 89 59 241 132 241 89 0 59 241 89 12 235 166 0 0 0 89 247 34 59 241 89 0 0 89 247 34 12 235 166 0 0 0 89 247 34 59 241 89 0 0 59 241 89 0 59 238 34 0 0 0 0 0 0 59 241 89 0 0 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 89 225 21 59 241 89 0 89 206 202 89 0 59 238 34 0 89 251 89 138 225 21 0 0 175 201 0 138 225 21 0 0 0 0 0 175 225 21 12 228 34 0 0 0 138 166 0 0 0 0 12 228 34 0 7 206 166 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 7 202 89 89 225 21 7 206 125 12 206 21 0 59 238 34 89 247 34 0 59 241 89 0 0 175 201 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 0 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 102 232 89 0 0 0 59 241 89 0 0 0 0 59 241 102 232 89 59 215 81 241 89 59 241 89 138 225 21 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 7 206 201 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 175 201 0 0 12 235 166 0 0 0 0 0 0 59 241 89 0 0 0 59 241 89 0 0 0 59 241 89 7 206 166 0 0 175 166 0 7 206 125 0 175 125 175 166 0 138 201 0 0 0 175 255 251 89 0 0 0 59 245 166 241 89 0 0 0 0 0 89 247 34 0 12 228 34 0 0 0 89 201 0 0 0 0 12 228 34 12 235 201 0 0 0 59 245 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 59 215 21 175 125 0 7 206 125 7 199 34 0 138 201 0 12 235 125 0 59 245 255 255 255 247 34 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 59 241 89 59 245 255 255 255 255 127 59 245 255 255 255 255 127 59 241 89 0 0 0 0 0 0 59 245 255 255 255 255 255 251 89 0 59 241 89 0 0 0 59 241 89 59 245 255 247 34 0 0 0 59 241 89 0 0 0 0 59 241 89 138 201 175 166 59 241 89 59 241 89 12 235 125 59 241 89 59 241 89 0 0 0 12 235 125 59 245 255 255 255 201 0 0 59 241 89 0 0 0 12 235 125 59 245 255 255 255 125 0 0 0 0 59 245 255 255 125 0 0 0 59 241 89 0 0 0 59 241 89 0 0 0 59 241 89 0 138 225 21 59 241 89 0 0 175 201 7 202 89 89 201 0 175 166 0 0 0 12 235 166 0 0 0 0 0 138 255 166 0 0 0 0 0 59 245 125 0 0 12 228 34 0 0 0 12 228 34 0 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 59 215 21 175 125 0 7 206 125 7 199 34 7 206 125 0 0 175 201 0 59 241 89 0 0 89 247 34 59 241 89 0 0 0 0 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 59 245 255 251 89 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 175 225 21 0 0 59 241 89 0 0 0 0 59 241 89 12 235 247 34 59 241 89 59 241 89 0 89 247 94 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 0 0 59 241 89 0 0 0 59 241 89 59 241 89 12 235 166 0 0 0 0 0 0 0 138 251 89 0 0 59 241 89 0 0 0 59 241 89 0 0 0 59 241 89 0 12 232 89 138 225 21 0 0 89 225 81 215 21 12 228 47 232 89 0 0 0 175 255 251 89 0 0 0 0 59 241 89 0 0 0 0 7 206 201 0 0 0 12 228 34 0 0 0 0 175 125 0 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 12 228 34 89 201 0 7 206 125 59 215 21 59 245 255 255 255 255 247 34 59 241 89 0 0 59 241 89 7 206 166 0 0 0 0 0 59 241 89 0 0 0 138 225 21 59 241 89 0 0 0 0 59 241 89 0 0 0 0 7 206 166 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 7 206 201 0 0 59 241 89 0 0 0 0 59 241 89 0 175 166 0 59 241 89 59 241 89 0 7 206 200 241 89 12 235 166 0 0 0 89 247 34 59 241 89 0 0 0 0 0 12 235 166 0 0 0 89 247 34 59 241 89 0 59 245 125 0 0 0 0 0 0 12 232 89 0 0 59 241 89 0 0 0 12 232 89 0 0 0 59 238 34 0 0 175 171 206 166 0 0 0 12 232 159 201 0 7 202 132 215 21 0 0 89 247 34 175 225 21 0 0 0 59 241 89 0 0 0 0 138 225 21 0 0 0 12 228 34 0 0 0 0 89 201 0 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 138 201 7 206 255 251 226 255 255 166 0 138 201 0 0 0 12 235 125 59 241 89 0 0 138 247 34 0 89 255 125 0 0 59 192 59 241 89 0 0 138 251 89 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 89 255 125 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 89 247 34 59 241 89 0 12 235 166 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 59 241 89 59 241 89 0 0 59 245 251 89 0 138 251 89 0 59 245 166 0 59 241 89 0 0 0 0 0 0 138 251 89 0 59 245 166 0 59 241 89 0 0 138 251 89 0 89 166 0 0 89 247 34 0 0 59 241 89 0 0 0 0 138 225 21 0 7 206 166 0 0 0 89 255 251 89 0 0 0 7 206 255 125 0 0 138 255 201 0 0 12 235 125 0 12 235 166 0 0 0 59 241 89 0 0 0 89 251 89 0 0 0 0 12 228 34 0 0 0 0 12 228 34 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 7 206 225 21 0 0 0 0 0 0 7 206 125 0 0 0 0 175 201 59 245 255 255 255 247 34 0 0 0 59 245 255 255 251 89 59 245 255 255 255 225 21 0 0 59 245 255 255 255 255 127 81 241 89 0 0 0 0 0 0 59 245 255 255 255 201 0 59 241 89 0 0 0 59 241 89 89 255 255 255 138 235 255 255 125 0 59 241 89 0 0 89 255 201 59 245 255 255 255 255 166 59 241 89 0 0 0 0 59 241 89 59 241 89 0 0 0 175 251 89 0 0 138 255 255 255 166 0 0 59 241 89 0 0 0 0 0 0 0 138 255 255 255 166 0 0 59 241 89 0 0 0 175 251 89 12 235 255 255 251 89 0 0 0 59 241 89 0 0 0 0 0 59 245 255 251 89 0 0 0 0 12 235 201 0 0 0 0 0 138 251 89 0 0 89 255 125 0 7 206 225 21 0 0 89 255 125 0 0 59 241 89 0 0 0 175 255 255 255 255 255 127 0 228 34 0 0 0 0 0 175 125 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 89 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 0 0 0 89 201 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 125 0 0 0 12 228 124 255 255 247 34 0 0 0 0 0 0 0 0 0 245 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 89 255 125 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 89 255 255 166 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 255 201 0 12 228 34 0 0 89 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 116 116 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 59 241 89 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 89 251 89 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 225 21 0 0 12 228 34 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 28 244 252 52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 12 228 34 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 180 252 164 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 7 206 255 255 255 125 0 59 241 194 255 251 89 0 0 7 206 255 255 201 0 12 235 255 255 251 89 0 12 235 255 251 89 7 206 255 255 247 34 0 12 235 255 255 251 89 59 241 194 255 255 125 0 59 241 89 89 255 251 89 59 241 89 0 138 251 89 59 241 89 59 241 159 255 255 125 89 255 255 166 0 59 241 194 255 255 125 0 0 0 12 235 255 247 34 0 59 241 194 255 255 125 0 0 12 235 255 255 251 89 59 241 159 255 201 0 138 255 255 247 34 206 255 255 255 166 59 241 89 0 59 241 97 206 166 0 0 12 235 125 175 201 0 7 206 166 0 7 206 133 206 225 21 0 89 255 255 166 0 0 12 235 125 138 255 255 255 255 166 0 0 138 166 0 0 0 12 228 34 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 76 252 244 20 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 89 247 34 59 245 166 0 138 225 21 7 206 201 0 0 0 7 206 166 0 59 241 89 7 206 125 0 89 225 21 59 241 89 0 0 7 206 166 0 59 241 89 59 245 166 0 89 247 34 59 241 89 0 59 241 89 59 241 89 138 225 21 0 59 241 89 59 245 201 0 89 255 201 0 89 247 34 59 245 166 0 89 247 34 0 7 206 166 0 138 225 21 59 245 166 0 138 247 34 7 206 166 0 59 241 89 59 245 201 0 0 59 238 34 0 130 34 59 241 89 0 0 59 241 89 0 59 241 89 89 247 34 0 89 247 34 138 225 21 12 235 225 21 12 232 89 7 206 166 12 235 125 89 247 34 0 89 247 34 0 0 0 89 247 34 0 0 138 166 0 0 0 12 228 34 0 0 0 0 89 225 21 0 0 7 206 247 34 0 0 89 201 0 0 4 4 68 12 4 4 4 220 252 108 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 0 0 59 241 89 0 59 241 89 59 238 34 0 59 238 34 59 241 89 0 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 159 201 0 0 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 0 59 241 89 0 0 0 59 241 89 0 0 59 241 89 0 59 241 89 12 235 125 0 175 166 0 59 238 34 89 171 202 89 89 225 21 0 59 241 226 201 0 12 235 125 0 175 166 0 0 0 12 235 125 0 0 59 238 34 0 0 0 12 228 34 0 0 0 0 7 206 125 0 7 202 89 12 235 166 0 175 125 0 0 4 60 244 172 4 4 132 252 212 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 89 255 255 255 251 89 59 241 89 0 59 241 89 59 238 34 0 0 0 59 238 34 0 59 241 89 59 245 255 255 255 251 0 59 241 89 0 0 59 238 34 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 245 255 225 21 0 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 238 34 0 12 232 89 59 241 89 0 12 232 89 59 238 34 0 59 241 89 59 241 89 0 0 0 175 255 255 201 0 59 241 89 0 0 59 241 89 0 59 241 89 0 175 201 12 232 89 0 7 206 125 172 89 138 166 138 201 0 0 0 138 247 34 0 0 175 201 12 232 89 0 0 7 206 166 0 0 175 225 21 0 0 0 0 12 228 34 0 0 0 0 0 0 175 225 34 206 21 0 0 175 255 166 0 0 0 4 52 244 252 140 36 244 252 60 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 59 241 89 0 59 241 89 59 241 89 0 59 238 34 59 241 89 0 0 0 59 241 89 0 59 241 89 59 238 34 0 0 0 0 59 241 89 0 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 97 206 201 0 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 0 0 0 0 59 245 125 59 241 89 0 0 59 241 89 0 59 241 89 0 59 238 124 225 21 0 0 175 176 206 21 59 215 187 125 0 0 59 245 255 201 0 0 89 247 124 225 21 0 0 138 225 21 0 0 0 59 241 89 0 0 0 12 228 34 0 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 4 4 76 252 252 220 252 164 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 89 247 34 0 89 251 89 59 241 89 0 175 201 0 7 206 201 0 0 0 7 206 166 0 138 251 89 7 206 166 0 7 199 34 59 241 89 0 0 7 206 166 0 138 251 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 12 235 166 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 7 206 166 0 138 225 21 59 241 89 0 138 225 21 7 206 166 0 89 251 89 59 241 89 0 0 89 125 0 12 232 89 12 232 89 0 12 12 235 125 0 175 251 89 0 7 206 255 125 0 0 0 89 255 201 0 7 206 247 34 0 7 206 166 59 245 125 0 7 206 255 125 0 0 59 241 89 0 0 0 0 0 138 166 0 0 0 12 228 34 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 100 252 252 244 28 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 175 255 255 232 241 89 59 245 255 255 247 34 0 0 12 235 255 255 201 0 59 245 255 200 241 89 0 12 235 255 251 89 0 59 241 89 0 0 0 12 235 255 200 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 245 201 59 241 89 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 0 12 235 255 247 34 0 59 245 166 255 247 34 0 0 59 245 255 166 241 89 59 241 89 0 0 59 245 255 255 166 0 0 138 255 255 125 0 89 255 255 166 241 89 0 0 138 247 34 0 0 0 59 245 125 0 0 138 225 21 7 206 225 21 0 138 251 0 0 138 247 34 0 0 175 255 255 255 255 166 0 0 138 166 0 0 0 12 228 34 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 132 252 108 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 138 201 0 0 0 12 228 34 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 116 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 166 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 7 206 255 201 0 12 228 34 0 0 89 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 4 4 4 4 4 4 4 4 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 125 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 138 201 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 0 0 7 199 34 0 0 0 0 138 255 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 251 89 0 0 138 255 251 97 206 201 0 0 138 251 102 235 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 201 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 12 235 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 175 255 255 255 225 21 59 245 255 255 255 255 255 125 0 0 0 0 0 0 0 7 206 255 247 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 0 0 7 199 34 0 0 0 138 225 21 175 166 0 0 175 255 255 166 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 59 245 255 255 201 0 0 0 0 0 0 0 0 59 245 255 255 255 255 255 255 255 255 125 0 59 245 255 255 255 255 255 125 0 0 89 255 255 255 255 255 225 21 59 245 255 255 255 255 255 125 0 0 0 59 245 255 255 255 255 255 125 7 206 166 0 0 175 171 206 166 89 247 34 0 175 201 59 241 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 175 255 125 0 0 89 255 255 255 125 175 251 89 89 255 125 0 7 206 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 255 255 255 255 125 0 0 7 206 255 125 59 245 125 0 0 0 89 251 89 0 0 0 0 0 0 0 127 7 206 225 21 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 255 255 255 125 0 59 245 255 255 255 255 125 0 0 0 0 0 0 0 89 247 34 12 228 34 0 138 166 0 0 0 0 0 0 0 0 0 0 12 235 125 0 7 176 21 0 0 0 0 0 0 138 251 89 0 0 138 201 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 7 206 166 0 59 115 0 0 0 0 59 115 0 0 0 59 115 0 0 0 0 59 115 0 89 201 0 12 232 89 89 201 7 202 89 12 232 89 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 172 132 196 199 163 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 0 89 247 34 0 7 206 125 0 0 0 0 0 0 0 0 127 89 247 34 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 0 0 7 199 34 0 0 0 0 0 0 0 0 0 89 225 21 7 202 89 12 228 34 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 0 0 130 34 59 241 89 0 0 0 138 201 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 175 225 21 0 59 115 0 0 0 0 59 115 0 0 0 59 115 0 0 0 0 59 115 0 12 228 34 59 192 0 12 228 34 138 166 59 215 21 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 172 89 175 166 138 125 0 138 255 255 247 34 12 146 0 0 0 0 89 255 255 255 125 12 235 255 255 125 0 0 0 59 115 0 0 0 0 59 115 0 138 255 255 255 255 127 0 175 201 0 138 225 21 0 0 0 0 0 0 0 0 127 245 255 255 255 255 255 125 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 0 0 7 199 34 0 0 0 0 0 0 0 0 0 89 247 34 12 228 34 138 166 0 0 0 0 0 0 0 0 0 0 0 12 235 166 0 0 0 0 0 0 175 225 21 138 225 21 0 0 0 138 201 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 89 247 34 0 0 59 115 0 0 0 0 59 115 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 172 89 0 0 138 125 59 238 34 0 130 34 7 206 201 0 0 59 241 89 0 12 235 255 125 0 59 241 89 0 0 59 115 0 0 0 0 59 115 0 0 0 0 89 247 34 0 59 245 166 241 89 0 0 0 0 0 0 0 0 0 127 138 225 21 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 89 255 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 0 0 7 199 34 0 0 0 0 0 0 0 0 0 0 175 255 255 166 59 215 21 175 255 255 125 0 89 255 255 201 0 0 0 59 245 255 255 125 0 12 235 166 0 0 138 225 21 0 0 0 138 255 255 255 255 247 34 0 59 115 0 0 0 0 59 115 0 0 0 0 59 245 125 0 0 0 59 115 0 0 0 0 59 115 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 251 102 0 255 255 255 255 255 0 245 255 255 255 255 255 255 255 255 255 255 127 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 241 89 0 0 0 0 0 138 247 34 138 201 0 0 0 175 201 0 0 0 175 166 0 0 59 115 0 0 0 0 59 115 0 0 0 12 235 125 0 0 0 138 255 166 0 0 0 0 0 0 0 0 0 0 127 245 255 255 255 255 225 21 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 89 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 59 245 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 175 125 89 225 21 59 238 47 232 89 7 206 125 0 0 0 0 0 138 251 89 12 235 166 0 0 138 225 21 0 0 0 138 201 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 7 206 201 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 255 255 201 0 0 0 138 247 34 175 201 0 0 0 138 255 255 255 255 255 166 0 0 59 115 0 0 0 0 59 115 0 0 7 206 166 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 127 89 251 89 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 199 34 0 0 0 0 0 7 199 34 0 0 0 0 0 0 0 0 0 0 0 0 0 59 215 21 138 201 0 12 228 47 228 34 0 175 166 0 0 0 0 0 12 232 89 0 0 175 225 21 59 241 89 0 0 0 138 201 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 138 225 21 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 125 7 206 201 0 0 138 201 0 0 0 175 201 0 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 138 225 21 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 127 7 206 247 34 0 0 0 0 59 115 0 0 0 0 59 115 0 59 245 125 0 0 175 166 0 0 0 59 245 125 175 225 29 206 166 0 89 247 34 7 206 166 0 0 0 7 199 34 0 0 0 0 0 7 199 34 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 89 225 21 59 238 47 232 89 7 206 125 0 89 166 0 0 89 247 34 0 0 0 130 34 0 138 255 125 0 0 138 201 0 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 89 251 89 0 0 0 0 0 59 115 0 0 0 0 59 115 0 0 0 59 115 0 0 0 0 59 115 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 125 0 12 232 89 12 146 0 0 0 59 241 89 0 12 235 247 34 0 0 89 125 0 0 59 115 0 0 0 0 59 115 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 127 0 0 175 255 255 255 225 21 59 245 255 255 255 255 255 125 0 138 225 21 0 12 235 125 0 0 0 138 225 34 235 125 7 206 166 0 89 247 34 7 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 201 0 0 0 175 255 255 125 0 89 255 255 201 0 0 12 235 255 255 251 89 0 0 0 0 0 0 0 0 89 255 255 255 255 255 255 255 255 255 125 0 59 245 255 255 255 255 255 125 0 0 175 255 255 255 255 255 247 34 59 245 255 255 255 255 255 125 0 0 0 59 245 255 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 255 255 166 0 0 0 0 0 0 0 89 255 255 255 125 59 245 255 255 201 0 0 0 59 245 255 255 255 255 255 125 0 175 255 255 255 255 127 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 0 255 255 201 0 0 0 0 175 166 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 0 0 0 0 0 12 228 34 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 245 255 255 255 255 255 251 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 0 0 0 138 125 0 0 0 0 59 245 255 255 125 0 0 0 0 0 0 0 0 138 225 21 0 0 175 166 0 12 228 34 0 0 59 245 255 255 247 34 0 89 225 29 206 166 0 0 0 0 0 89 255 255 255 255 125 0 0 0 7 206 255 255 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 138 255 255 166 0 0 0 0 7 202 89 0 0 0 0 0 12 235 255 125 0 0 175 255 255 225 21 0 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 138 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 89 255 255 225 21 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 89 225 21 0 0 0 0 0 138 166 0 0 0 89 225 21 0 0 0 12 235 255 255 166 0 0 7 206 125 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 0 0 0 138 125 0 0 0 12 235 125 0 59 115 0 0 0 0 0 0 0 0 7 206 125 0 59 215 21 0 12 228 34 0 12 235 125 0 0 168 34 0 0 0 0 0 0 0 0 0 0 175 225 21 0 0 0 175 225 21 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 225 21 0 0 0 175 225 21 0 0 0 0 0 0 0 0 0 59 238 34 7 206 125 0 0 0 7 202 89 0 0 0 0 7 199 34 59 238 34 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 125 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 247 34 0 59 241 89 0 175 201 0 0 0 0 0 0 0 0 0 7 206 255 166 0 0 12 232 89 0 0 0 0 7 206 255 166 0 0 12 232 89 0 0 0 0 0 0 0 59 215 21 0 89 201 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 7 206 255 255 251 89 0 59 241 89 0 0 0 138 201 0 0 0 138 201 0 0 89 225 21 175 125 0 0 12 228 34 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 89 255 255 247 34 89 201 0 0 89 255 255 255 166 0 0 0 0 168 34 7 151 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 7 206 255 255 225 21 89 201 0 0 0 0 0 0 0 0 0 89 166 0 0 138 166 0 0 0 7 202 89 0 0 0 0 0 0 0 59 238 34 0 7 206 255 125 0 0 0 0 0 0 0 0 0 59 238 34 0 0 175 166 0 175 255 255 255 125 175 125 0 138 247 34 0 0 0 0 0 0 0 0 0 0 12 228 34 0 89 201 0 0 89 225 0 81 115 0 134 89 0 0 0 0 0 138 166 0 0 138 166 0 0 0 0 0 0 0 138 166 0 0 138 166 0 0 0 0 0 0 59 245 247 34 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 89 201 0 7 206 201 138 125 138 125 0 59 241 89 0 0 0 0 175 255 255 255 225 21 0 0 7 206 166 215 21 0 0 12 228 34 0 0 138 255 255 251 89 0 0 0 0 0 0 0 0 0 12 206 21 59 241 89 0 134 89 0 172 89 59 238 34 0 138 166 0 0 7 206 201 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 206 21 7 202 89 12 235 125 0 172 89 0 0 0 0 0 0 0 0 59 238 34 7 206 125 12 235 255 255 255 255 255 255 125 0 0 0 12 235 125 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 59 238 34 0 0 175 166 0 175 255 255 255 125 175 125 0 138 247 34 0 0 0 0 0 0 0 0 0 0 12 228 34 0 89 201 0 0 89 225 0 29 206 166 59 245 125 0 0 0 0 138 166 0 12 228 34 0 175 225 21 0 0 0 138 166 0 12 228 42 206 255 255 166 0 0 0 0 12 228 34 138 166 0 89 247 34 0 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 201 0 59 241 89 138 125 0 0 59 245 255 255 255 125 0 0 138 166 0 89 201 0 0 0 0 89 255 125 0 0 0 0 0 0 0 7 206 125 0 138 251 89 0 0 0 0 0 0 0 0 89 166 0 138 201 0 0 0 0 0 89 166 59 215 21 0 175 166 0 59 245 125 89 251 89 0 0 12 235 255 255 255 255 255 255 125 138 255 255 251 89 127 166 0 7 202 89 12 232 89 0 89 166 0 0 0 0 0 0 0 0 0 138 255 255 166 0 0 0 0 7 202 89 0 0 0 0 0 59 241 89 0 0 0 0 0 7 206 125 0 0 0 0 0 0 0 0 59 238 34 0 0 175 166 0 89 255 255 255 125 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 59 241 89 0 175 201 0 0 0 175 201 7 206 201 0 0 0 138 166 0 175 166 0 138 200 215 21 0 0 0 138 166 0 175 166 7 151 0 89 247 34 0 0 0 59 238 47 228 34 59 219 209 34 0 0 0 89 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 59 238 34 138 125 0 0 0 59 241 89 0 0 0 0 138 166 0 89 201 0 0 59 245 255 255 255 255 125 0 0 0 0 0 59 238 34 0 7 206 125 0 0 0 0 0 0 0 0 89 166 0 138 201 0 0 0 0 0 89 166 0 175 255 255 223 166 0 12 235 125 59 241 89 0 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 138 125 0 7 206 255 255 125 0 0 59 157 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 0 0 7 206 255 255 255 166 7 206 255 255 201 0 0 0 0 0 0 0 0 0 59 238 34 0 0 175 166 0 0 89 255 255 125 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 251 89 0 89 255 255 225 21 0 0 0 175 225 29 206 166 0 0 0 138 166 59 215 21 59 215 81 215 21 0 0 0 138 166 59 215 21 0 0 0 89 225 21 59 245 255 255 125 138 166 7 202 97 199 34 0 0 89 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 59 241 89 138 125 0 0 0 89 247 34 0 0 0 0 175 255 255 255 225 21 0 0 0 12 232 89 0 0 0 12 228 34 0 12 235 225 21 59 215 21 0 0 0 0 0 0 0 0 12 206 21 59 241 89 0 134 89 0 172 89 0 0 0 0 0 0 0 0 7 206 201 12 235 125 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 12 206 21 7 202 89 7 206 125 0 172 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 175 166 0 0 0 0 175 125 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 59 245 125 0 0 0 0 0 0 175 125 12 228 34 59 215 21 0 0 0 0 0 175 125 0 0 0 12 232 89 0 0 0 0 0 59 238 34 175 125 7 199 34 0 0 175 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 7 206 201 138 125 138 125 7 202 89 0 0 0 0 138 201 0 0 0 138 166 0 0 0 12 232 89 0 0 0 12 228 34 0 0 0 175 255 255 166 0 0 0 0 0 0 0 0 0 0 138 166 0 89 255 255 247 34 89 201 0 0 0 0 0 0 0 0 0 0 0 168 34 7 151 0 0 0 0 0 0 0 0 175 125 0 0 0 0 0 0 138 166 7 202 89 0 89 247 124 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 245 125 0 7 206 166 0 0 0 0 175 125 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 115 0 134 89 0 0 0 0 0 0 59 215 21 59 245 255 255 255 225 21 0 0 0 59 215 21 0 0 59 238 34 0 0 0 0 0 0 175 125 7 206 255 255 255 251 89 0 138 247 34 0 59 157 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 138 225 21 0 7 206 255 255 251 89 138 255 255 255 255 255 166 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 12 228 34 0 0 0 0 0 59 241 89 0 0 0 0 0 0 0 0 0 0 175 225 21 0 0 0 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 225 21 0 0 0 175 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 198 255 251 194 166 0 0 0 0 175 125 175 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 125 0 0 0 0 89 225 21 0 0 0 7 206 125 0 0 12 235 255 255 255 166 0 0 0 89 225 21 0 0 0 12 228 34 0 0 0 175 255 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 7 176 21 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 255 255 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 0 0 0 175 125 175 125 0 0 0 0 0 0 0 0 59 215 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 7 206 255 255 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 0 0 0 175 125 175 125 0 0 0 0 0 0 59 245 251 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 89 255 125 0 0 0 0 0 0 12 235 201 0 0 0 0 12 235 251 89 0 0 0 0 175 255 125 89 201 0 0 0 0 0 0 0 0 0 0 0 59 245 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 138 251 89 0 0 0 12 235 251 89 0 0 0 0 0 0 0 0 7 206 225 21 0 0 0 89 255 125 0 89 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 247 34 172 89 0 0 0 0 7 206 225 21 0 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 89 255 225 21 0 0 0 0 12 235 247 34 172 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 0 7 206 225 21 0 0 0 0 89 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 89 247 34 0 0 0 0 0 175 166 0 0 0 0 7 206 125 59 241 89 0 0 89 201 12 235 247 34 0 0 7 206 166 59 241 89 0 0 12 228 34 59 215 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 89 247 34 0 0 0 7 206 125 59 241 89 0 7 206 166 59 238 34 0 0 175 166 0 0 59 241 89 0 89 247 34 138 201 59 238 34 138 201 0 0 0 0 0 0 0 0 0 0 0 175 125 89 255 201 0 0 0 0 0 0 0 175 201 0 0 0 0 0 0 12 232 89 0 0 0 0 0 0 59 238 34 138 225 21 0 0 0 175 125 89 255 201 0 0 0 0 59 238 34 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 89 247 34 0 0 0 0 0 0 138 201 0 0 0 0 0 59 238 34 138 225 21 0 0 0 59 238 34 138 201 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 59 215 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 255 125 0 0 0 0 127 0 0 12 235 225 21 0 0 0 0 12 235 225 21 0 0 0 0 12 235 225 21 0 0 0 0 12 235 225 21 0 0 0 0 12 235 225 21 0 0 0 0 12 235 225 21 0 0 0 0 0 175 255 255 255 255 255 255 255 166 0 0 138 255 255 255 251 89 59 245 255 255 255 255 127 81 245 255 255 255 255 225 21 59 245 255 255 255 255 127 81 245 255 255 255 255 127 111 255 255 255 125 89 255 255 255 125 89 255 255 255 125 89 255 255 255 125 7 206 255 255 255 255 125 0 0 59 245 247 34 0 0 59 241 89 0 0 0 138 255 255 255 166 0 0 0 0 138 255 255 255 166 0 0 0 0 0 138 255 255 255 166 0 0 0 0 138 255 255 255 166 0 0 0 0 138 255 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 255 255 255 210 235 166 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 132 245 125 0 0 0 89 251 89 12 232 89 0 0 0 0 7 206 166 0 89 251 89 0 0 0 127 0 0 89 232 241 89 0 0 0 0 89 232 241 89 0 0 0 0 89 232 241 89 0 0 0 0 89 232 241 89 0 0 0 0 89 232 241 89 0 0 0 0 89 232 241 89 0 0 0 0 12 232 89 89 225 21 0 0 0 0 0 175 247 34 0 0 59 192 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 7 206 166 0 0 59 245 201 0 59 245 255 201 0 0 59 241 89 0 0 138 251 89 0 12 235 166 0 0 138 251 89 0 12 235 166 0 0 0 138 251 89 0 12 235 166 0 0 138 251 89 0 12 235 166 0 0 138 251 89 0 12 235 166 0 0 0 138 166 0 0 0 12 228 34 0 0 175 247 34 0 0 175 225 21 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 89 247 34 0 7 206 125 0 12 232 89 0 0 0 0 59 241 89 0 12 232 89 0 0 0 127 0 7 206 166 175 166 0 0 0 7 206 166 175 166 0 0 0 7 206 166 175 166 0 0 0 7 206 166 175 166 0 0 0 7 206 166 175 166 0 0 0 0 175 166 175 166 0 0 0 0 138 225 21 89 225 21 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 7 206 166 0 0 0 59 245 125 59 241 132 241 89 0 59 241 89 0 12 235 166 0 0 0 89 247 34 12 235 166 0 0 0 89 247 34 0 12 235 166 0 0 0 89 247 34 12 235 166 0 0 0 89 247 34 12 235 166 0 0 0 89 247 34 0 0 12 235 125 0 12 235 125 0 0 59 241 89 0 0 138 176 235 166 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 175 201 0 138 225 21 0 12 235 255 255 255 225 21 59 238 34 0 138 225 21 0 0 0 127 0 59 238 34 89 247 34 0 0 59 238 34 89 247 34 0 0 59 238 34 89 247 34 0 0 59 238 34 89 247 34 0 0 59 238 34 89 247 34 0 0 59 241 89 89 225 21 0 0 7 206 125 0 89 225 21 0 0 0 0 138 225 21 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 7 206 166 0 0 0 7 206 166 59 241 89 138 225 21 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 0 0 12 235 138 235 125 0 0 0 138 225 21 0 59 215 21 175 201 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 59 245 166 241 89 0 0 12 232 89 0 0 175 225 59 238 47 235 225 21 0 0 0 0 127 0 138 201 0 12 235 125 0 0 138 201 0 12 235 125 0 0 138 201 0 12 235 125 0 0 138 201 0 12 235 125 0 0 138 201 0 12 235 125 0 0 138 225 21 12 235 125 0 0 89 247 34 0 89 255 255 255 255 251 89 138 225 21 0 0 0 0 0 59 245 255 255 255 255 127 59 245 255 255 255 255 166 0 59 245 255 255 255 255 127 59 245 255 255 255 255 127 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 7 206 255 255 255 166 0 0 175 201 59 241 89 12 235 125 59 241 89 0 59 241 89 0 0 0 12 235 125 59 241 89 0 0 0 12 235 125 0 59 241 89 0 0 0 12 235 125 59 241 89 0 0 0 12 235 125 59 241 89 0 0 0 12 235 125 0 0 0 0 12 235 125 0 0 0 0 138 225 21 7 199 34 0 138 225 81 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 0 138 255 166 0 0 0 12 232 89 0 0 89 247 59 238 34 0 59 245 125 0 0 0 127 7 206 125 0 0 175 201 0 7 206 125 0 0 175 201 0 7 206 125 0 0 175 201 0 7 206 125 0 0 175 201 0 7 206 125 0 0 175 201 0 7 206 125 0 0 175 201 0 7 206 255 255 255 255 225 21 0 0 0 0 138 225 21 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 7 206 166 0 0 0 7 206 166 59 241 89 0 89 247 94 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 0 0 12 235 138 235 125 0 0 0 138 225 21 175 125 0 0 175 201 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 59 241 89 0 0 0 59 241 89 0 0 59 241 89 0 0 0 12 232 89 0 7 206 201 59 238 34 0 0 138 201 0 0 0 127 59 245 255 255 255 255 247 34 59 245 255 255 255 255 247 34 59 245 255 255 255 255 247 34 59 245 255 255 255 255 247 34 59 245 255 255 255 255 247 34 59 245 255 255 255 255 247 34 59 241 89 0 0 89 225 21 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 7 206 166 0 0 0 59 241 89 59 241 89 0 7 206 200 241 89 0 12 235 166 0 0 0 89 247 34 12 235 166 0 0 0 89 247 34 0 12 235 166 0 0 0 89 247 34 12 235 166 0 0 0 89 247 34 12 235 166 0 0 0 89 247 34 0 0 12 235 125 0 12 235 125 0 0 59 241 159 166 0 0 12 235 166 12 232 89 0 0 0 59 238 34 12 232 89 0 0 0 59 238 34 12 232 89 0 0 0 59 238 34 12 232 89 0 0 0 59 238 34 0 0 59 241 89 0 0 0 12 235 255 255 255 201 0 59 238 34 0 0 138 201 0 0 0 127 138 201 0 0 0 12 235 125 138 201 0 0 0 12 235 125 138 201 0 0 0 12 235 125 138 201 0 0 0 12 235 125 138 201 0 0 0 12 235 125 138 201 0 0 0 12 235 125 175 201 0 0 0 89 225 21 0 0 0 0 0 175 247 34 0 0 59 192 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 0 59 241 89 0 7 206 166 0 0 59 245 201 0 59 241 89 0 0 59 245 251 89 0 0 138 251 89 0 59 245 166 0 0 138 251 89 0 59 245 166 0 0 0 138 251 89 0 59 245 166 0 0 138 251 89 0 59 245 166 0 0 138 251 89 0 59 245 166 0 0 0 138 166 0 0 0 12 228 34 0 0 175 247 34 0 7 206 225 21 0 138 225 21 0 7 206 166 0 0 138 225 21 0 7 206 166 0 0 138 225 21 0 7 206 166 0 0 138 225 21 0 7 206 166 0 0 0 59 241 89 0 0 0 12 232 89 0 0 0 0 59 238 34 0 12 235 125 0 0 0 127 206 125 0 0 0 0 175 206 206 125 0 0 0 0 175 206 206 125 0 0 0 0 175 206 206 125 0 0 0 0 175 206 206 125 0 0 0 0 175 206 206 125 0 0 0 0 175 232 245 125 0 0 0 89 255 255 255 255 255 166 0 0 138 255 255 255 251 89 59 245 255 255 255 255 127 81 245 255 255 255 255 225 21 59 245 255 255 255 255 127 81 245 255 255 255 255 127 111 255 255 255 125 89 255 255 255 125 89 255 255 255 125 89 255 255 255 125 7 206 255 255 255 255 125 0 0 59 241 89 0 0 0 175 251 89 0 0 0 138 255 255 255 166 0 0 0 0 138 255 255 255 166 0 0 0 0 0 138 255 255 255 166 0 0 0 0 138 255 255 255 166 0 0 0 0 138 255 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 7 202 194 255 255 255 201 0 0 0 0 59 245 255 251 89 0 0 0 0 59 245 255 251 89 0 0 0 0 59 245 255 251 89 0 0 0 0 59 245 255 251 89 0 0 0 0 59 241 89 0 0 0 12 232 89 0 0 0 0 59 238 47 235 255 166 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 228 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 7 206 225 21 0 0 0 0 0 12 235 201 0 0 0 138 255 201 0 0 0 59 245 225 29 202 89 0 0 0 0 0 0 0 0 138 166 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 225 21 0 0 0 0 0 12 235 201 0 0 0 89 255 225 21 0 0 0 0 0 0 0 0 175 247 34 0 12 235 255 255 166 0 0 0 0 0 0 0 0 0 0 0 0 59 245 225 29 202 89 0 0 138 251 89 0 0 0 0 0 7 206 225 21 0 0 0 89 255 225 21 0 0 59 245 225 29 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 225 21 0 0 0 0 0 89 255 125 0 0 0 89 255 225 21 0 0 0 0 0 0 0 0 0 0 0 0 138 251 89 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 175 166 0 0 0 0 7 206 166 0 0 0 89 225 21 175 201 0 7 202 89 138 255 166 0 0 89 247 34 175 166 0 0 138 166 7 202 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 166 0 0 0 0 0 175 166 0 0 0 89 247 34 138 201 0 0 89 247 34 175 201 0 0 138 201 0 175 200 215 34 235 247 47 232 0 138 255 225 111 225 21 0 0 172 89 138 255 166 0 0 0 0 89 225 21 0 0 0 0 175 201 0 0 0 0 89 247 34 138 201 0 0 172 89 138 255 166 0 0 59 238 34 138 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 175 166 0 0 0 0 59 241 89 0 0 0 89 247 34 138 201 0 0 0 59 238 34 138 201 0 0 0 89 247 34 0 0 59 238 34 0 0 0 0 0 138 225 29 206 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 206 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 166 0 0 0 0 0 0 0 0 89 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 238 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 7 206 255 255 255 125 0 7 206 255 255 255 125 0 7 206 255 255 255 125 0 7 206 255 255 255 125 0 7 206 255 255 255 125 0 12 235 255 255 251 89 0 12 235 255 255 251 89 59 245 255 166 0 0 59 245 255 255 201 0 12 235 255 251 89 0 0 12 235 255 251 89 0 0 12 235 255 251 89 0 0 12 235 255 251 89 0 59 238 34 59 238 34 59 238 34 59 238 34 0 59 241 89 175 225 21 0 59 241 194 255 255 125 0 0 12 235 255 247 34 0 0 12 235 255 247 34 0 0 0 12 235 255 247 34 0 0 12 235 255 247 34 0 0 12 235 255 247 34 0 0 0 0 0 12 235 166 0 0 0 0 7 206 255 255 225 21 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 97 206 166 0 0 12 235 125 59 238 163 255 255 201 7 206 166 0 0 12 235 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 89 247 34 0 0 0 0 89 247 34 0 0 0 0 89 247 34 0 0 0 0 89 247 34 0 0 0 0 89 247 34 0 0 0 0 138 225 21 0 0 0 0 89 255 225 21 0 138 201 59 245 125 0 0 0 7 206 125 0 89 225 21 7 206 125 0 89 225 21 7 206 125 0 89 225 21 7 206 125 0 89 225 21 59 238 34 59 238 34 59 238 34 59 238 34 0 0 0 0 12 235 125 0 59 245 166 0 89 247 34 7 206 166 0 138 225 21 7 206 166 0 138 225 21 0 7 206 166 0 138 225 21 7 206 166 0 138 225 21 7 206 166 0 138 225 21 0 0 0 0 0 0 0 0 0 0 12 232 89 0 138 251 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 89 247 34 0 89 247 34 59 245 166 0 7 206 166 89 247 34 0 89 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 59 241 89 0 0 0 0 59 238 34 0 0 0 0 12 232 89 0 0 59 238 127 225 21 0 0 0 59 238 34 0 59 238 34 59 238 34 0 59 238 34 59 238 34 0 59 238 34 59 238 34 0 59 238 34 59 238 34 59 238 34 59 238 34 59 238 34 0 138 255 255 255 255 201 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 12 235 255 255 255 255 255 255 166 138 201 0 59 157 175 201 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 12 235 125 0 175 166 0 59 238 34 0 0 138 225 34 235 125 0 175 166 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 89 255 255 255 251 89 0 89 255 255 255 251 89 0 89 255 255 255 251 89 0 89 255 255 255 251 89 0 89 255 255 255 251 89 0 138 255 255 255 247 34 0 175 255 255 255 255 255 255 255 255 251 127 201 0 0 0 0 59 245 255 255 255 251 89 59 245 255 255 255 251 89 59 245 255 255 255 251 89 59 245 255 255 255 251 89 59 238 34 59 238 34 59 238 34 59 238 34 138 247 34 0 0 138 201 0 59 241 89 0 59 241 89 59 238 34 0 12 232 89 59 238 34 0 12 232 89 0 59 238 34 0 12 232 89 59 238 34 0 12 232 89 59 238 34 0 12 232 89 0 0 0 0 0 0 0 0 0 0 175 201 7 176 21 138 201 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 0 175 201 12 232 89 0 59 238 34 0 0 138 225 21 175 201 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 138 247 34 0 59 238 34 138 225 21 0 12 232 89 0 0 0 0 138 201 0 0 0 0 59 238 34 0 0 0 0 59 238 34 0 0 0 0 59 238 34 0 0 0 0 59 238 34 0 0 0 0 59 238 34 59 238 34 59 238 34 59 238 34 175 201 0 0 0 138 166 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 0 0 0 12 235 166 0 0 0 138 201 134 89 0 175 166 0 59 241 89 0 59 241 89 59 241 89 0 59 241 89 59 241 89 0 59 241 89 0 59 241 89 0 59 241 89 0 89 247 124 225 21 0 59 238 34 0 0 138 201 0 89 247 124 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 89 247 34 0 89 251 89 89 247 34 0 89 251 89 89 247 34 0 89 251 89 89 247 34 0 89 251 89 89 247 34 0 89 251 89 175 201 0 0 175 247 34 175 201 0 0 59 245 225 21 0 7 199 94 245 125 0 0 0 7 206 166 0 7 199 34 7 206 166 0 7 199 34 7 206 166 0 7 199 34 7 206 166 0 7 199 34 59 238 34 59 238 34 59 238 34 59 238 34 138 247 34 0 12 232 89 0 59 241 89 0 59 241 89 7 206 166 0 138 225 21 7 206 166 0 138 225 21 0 7 206 166 0 138 225 21 7 206 166 0 138 225 21 7 206 166 0 138 225 21 0 0 0 0 12 235 166 0 0 0 59 245 166 0 59 241 89 0 12 235 125 0 175 251 89 12 235 125 0 175 251 89 12 235 125 0 175 251 89 0 12 235 125 0 175 251 89 0 7 206 255 125 0 0 59 238 34 0 12 235 125 0 7 206 255 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 175 255 255 232 241 89 0 175 255 255 232 241 89 0 175 255 255 232 241 89 0 175 255 255 232 241 89 0 175 255 255 232 241 89 12 235 255 255 166 238 34 12 235 255 255 225 21 89 255 255 251 89 0 89 255 255 255 201 0 12 235 255 251 89 0 0 12 235 255 251 89 0 0 12 235 255 251 89 0 0 12 235 255 251 89 0 59 238 34 59 238 34 59 238 34 59 238 34 0 138 255 255 255 125 0 0 59 241 89 0 59 241 89 0 12 235 255 247 34 0 0 12 235 255 247 34 0 0 0 12 235 255 247 34 0 0 12 235 255 247 34 0 0 12 235 255 247 34 0 0 0 0 0 0 0 0 0 0 0 7 206 255 255 225 21 0 0 0 89 255 255 166 241 89 0 89 255 255 166 241 89 0 89 255 255 166 241 89 0 0 89 255 255 166 241 89 0 0 138 247 34 0 0 59 245 166 255 255 166 0 0 0 138 247 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 59 215 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 232 89 0 0 0 59 238 34 0 0 0 0 0 12 232 89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 235 255 125 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 138 225 21 0 0 0 59 238 34 0 0 0 0 0 138 225 21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 0 127 127 0 127 127 0 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/FontSmall.pgm0000644000000000000000000012566312635011627025761 0ustar rootrootP2 # Created by Paint Shop Pro 211 84 255 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 255 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 0 0 255 255 0 0 0 255 0 0 0 0 255 255 0 0 0 255 0 0 255 0 0 255 0 0 255 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 0 0 255 0 0 255 255 255 0 0 255 255 255 0 0 0 0 0 255 0 255 255 255 255 0 0 255 255 0 0 255 255 255 255 0 0 255 255 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 255 0 255 0 0 0 255 0 0 255 0 0 255 255 255 255 0 255 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 255 0 0 255 255 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 255 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 255 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 0 0 0 0 0 255 255 255 255 255 255 255 0 255 0 0 0 255 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 0 0 0 0 0 0 255 0 255 0 0 0 255 255 0 0 0 0 255 255 0 255 0 255 255 0 0 0 255 255 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 255 0 0 0 255 255 0 0 255 0 0 255 0 255 255 255 0 0 255 255 255 0 0 0 0 255 0 0 0 255 255 0 0 0 255 255 255 0 0 255 0 0 255 0 0 0 255 255 0 0 0 255 255 255 255 255 255 0 0 0 0 255 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 0 0 0 0 255 255 255 255 255 255 0 0 0 255 255 0 0 0 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 255 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 255 255 255 255 255 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 255 0 0 255 255 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 255 0 0 255 0 0 0 255 255 0 0 0 255 255 255 255 255 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 255 255 255 255 0 0 0 0 255 0 0 0 255 255 0 0 0 255 255 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 255 255 0 0 255 255 255 0 255 255 255 255 0 255 255 255 0 0 0 0 0 255 0 255 255 255 0 0 0 255 255 0 0 255 0 0 0 0 0 255 255 0 0 0 255 255 0 0 0 255 0 0 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 0 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 0 127 127 0 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 0 127 127 127 0 127 0 127 127 127 0 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 0 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 255 255 0 0 0 0 0 255 255 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 255 255 255 255 0 0 0 255 255 255 255 255 0 255 255 255 255 255 0 0 0 255 255 255 0 0 255 0 0 0 0 255 0 255 255 255 0 0 255 255 0 255 0 0 0 255 0 255 0 0 0 255 255 0 0 0 255 255 0 255 0 0 0 0 255 0 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 255 255 255 255 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 0 255 0 255 255 255 255 0 255 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 0 0 255 0 0 0 0 255 255 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 255 255 0 0 0 255 255 0 255 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 255 255 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 255 0 0 0 255 0 0 0 255 0 255 0 255 0 255 0 255 0 255 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 255 0 255 0 255 0 0 255 255 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 255 0 255 0 255 0 0 255 0 0 255 0 0 255 255 255 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 255 255 255 0 0 255 255 255 255 0 0 255 0 0 255 255 255 0 255 255 255 255 255 255 0 0 255 0 0 0 0 255 0 255 255 0 0 0 0 255 0 0 0 255 0 255 0 255 0 255 0 255 0 0 255 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 255 255 255 255 0 0 0 255 255 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 255 0 255 0 255 0 0 255 255 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 255 0 255 0 255 0 255 255 255 255 255 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 255 0 255 0 0 0 255 255 0 255 0 0 0 0 0 255 0 255 255 255 255 0 0 255 0 0 0 0 0 255 0 255 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 255 0 0 255 0 0 255 0 255 0 255 0 255 0 0 255 255 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 255 255 255 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 255 0 0 0 0 255 0 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 255 255 255 0 0 0 0 255 255 255 0 0 255 255 255 255 0 0 0 255 255 255 255 255 0 255 0 0 0 0 0 0 0 255 255 255 255 0 255 0 0 0 0 255 0 255 255 255 0 255 255 0 0 255 0 0 0 255 0 255 255 255 255 255 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 255 255 0 0 0 255 0 0 0 0 0 0 0 255 255 255 0 0 0 255 0 0 0 255 0 255 255 255 255 0 0 0 0 255 0 0 0 0 255 255 255 255 0 0 0 0 255 255 0 0 0 0 255 0 0 0 255 0 0 255 0 0 255 0 0 0 255 0 0 0 255 255 255 255 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 0 127 127 127 0 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 4 4 4 4 12 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 255 0 0 255 255 255 0 0 0 255 255 0 0 255 255 255 0 0 255 255 0 0 255 255 255 0 255 255 255 0 255 255 255 0 0 255 0 255 255 0 255 0 0 255 0 255 0 255 255 255 0 255 255 0 0 255 255 255 0 0 0 255 255 0 0 255 255 255 0 0 0 255 255 255 0 255 0 255 255 255 255 0 255 255 0 255 0 0 255 0 255 0 0 0 255 0 255 0 0 255 0 0 255 0 255 0 255 0 255 0 0 0 255 0 255 255 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 4 4 4 4 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 255 0 255 0 0 255 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 255 0 255 0 0 0 255 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 255 0 0 255 0 0 255 4 4 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 255 255 0 255 0 0 255 0 255 0 0 0 255 0 0 255 0 255 255 255 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 255 0 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 0 255 0 0 255 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 255 0 255 0 0 255 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 255 255 0 0 0 255 255 4 255 255 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 0 255 0 0 255 0 255 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 255 0 0 0 255 255 0 255 255 0 0 0 255 0 0 0 255 0 255 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 255 255 0 255 255 255 0 0 0 255 255 0 0 255 255 255 0 0 255 255 255 0 255 0 0 0 255 255 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 255 0 0 255 255 255 0 0 0 255 255 255 0 255 0 0 255 255 255 0 0 255 0 0 255 255 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 0 255 0 0 0 255 255 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 20 0 255 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 0 127 0 127 127 0 127 127 127 127 0 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 0 127 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 0 0 255 255 255 255 255 255 255 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 255 255 0 0 0 255 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 255 255 255 255 255 255 255 0 0 255 255 255 255 255 255 255 0 255 255 255 255 0 0 255 255 255 255 255 255 255 0 0 255 255 255 255 255 255 255 0 255 0 0 255 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 255 255 255 255 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 0 255 255 255 255 255 0 0 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 255 0 0 255 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 255 255 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 255 0 255 255 255 0 255 0 0 0 255 255 0 255 255 0 0 0 255 0 0 0 0 0 255 0 255 255 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 255 255 255 255 0 0 0 0 0 0 0 255 255 0 255 0 255 255 0 255 255 0 0 0 255 255 255 0 0 255 0 0 255 0 0 0 255 255 255 255 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 255 255 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 255 255 255 255 0 255 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 255 255 255 255 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 0 255 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 0 0 255 255 255 255 255 255 255 0 0 255 0 255 0 0 0 0 255 0 255 0 255 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 255 0 255 255 0 0 255 255 255 255 0 0 0 0 0 0 255 255 255 255 255 255 255 0 0 255 255 255 255 255 255 255 0 255 255 255 255 0 0 255 255 255 255 255 255 255 0 0 255 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 0 255 255 255 0 0 255 255 255 255 255 255 255 0 255 255 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 255 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 0 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 255 0 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 255 255 255 0 0 255 0 255 0 0 0 255 255 255 255 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 255 255 0 255 255 255 0 0 255 0 0 0 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 255 0 0 0 255 0 0 0 255 255 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 255 0 0 0 0 0 0 255 255 0 255 0 0 0 0 0 255 255 0 0 255 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 255 255 255 0 0 255 0 0 0 0 255 255 255 0 0 0 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 255 0 0 255 255 0 0 255 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 255 255 255 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 255 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 255 0 255 0 255 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 255 0 255 0 0 255 255 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 255 0 255 0 255 0 0 0 255 255 255 255 255 0 0 0 0 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 0 0 255 255 255 0 255 255 0 0 0 0 0 0 255 0 0 255 0 255 255 0 255 0 0 255 0 0 0 0 0 0 0 255 255 255 0 255 255 0 0 0 255 0 255 0 0 255 255 0 0 255 255 0 0 0 255 0 255 0 255 255 0 0 255 255 0 255 0 255 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 255 0 255 0 0 0 255 0 0 0 0 255 255 255 0 0 0 255 255 255 0 0 0 0 255 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 255 0 255 255 0 255 0 255 255 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 255 0 255 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 255 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 255 255 0 0 0 0 0 0 255 0 0 255 255 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 0 0 0 0 255 0 255 255 255 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 255 0 0 255 255 255 0 255 255 255 255 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 255 255 0 0 255 0 0 0 0 255 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 0 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 255 0 255 255 0 0 0 255 0 0 255 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 255 0 255 0 0 0 0 0 0 0 0 0 255 0 255 255 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 255 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 127 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 255 255 255 0 0 0 255 255 255 0 0 255 255 255 255 255 0 255 255 255 255 255 0 255 255 255 255 255 0 255 255 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 255 0 0 0 255 0 0 0 0 255 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 0 0 0 0 0 0 0 255 255 255 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 127 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 0 255 255 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 255 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 255 255 0 0 255 0 0 255 0 127 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 255 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 255 0 0 127 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 255 255 255 255 0 255 0 0 0 0 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 255 255 255 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 255 255 0 0 255 0 255 0 0 255 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 127 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 255 255 255 255 255 255 0 0 255 255 255 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 255 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 127 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 0 255 0 0 0 255 0 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 0 0 255 0 0 0 255 255 255 0 0 255 0 0 255 0 127 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 0 0 255 0 255 0 0 255 255 255 255 0 0 0 255 255 255 0 0 255 255 255 255 255 0 255 255 255 255 255 0 255 255 255 255 255 0 255 255 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 0 255 255 255 255 0 0 0 255 0 0 0 0 255 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 0 255 255 255 0 0 0 0 255 0 0 0 255 0 255 0 255 255 255 0 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 255 255 255 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 255 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 255 255 0 255 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 255 255 0 255 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 255 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 255 0 255 255 0 0 255 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 255 0 255 255 0 255 0 0 255 255 0 255 0 255 255 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 255 0 255 255 0 255 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 255 0 255 0 0 255 0 255 0 0 0 255 0 0 0 255 0 0 0 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 255 255 255 0 255 255 0 0 0 255 255 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 0 255 0 0 255 0 0 255 0 0 0 0 255 0 255 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 0 255 0 255 255 255 0 0 255 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 255 0 255 0 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 255 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 255 255 255 255 0 255 0 0 255 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 255 255 255 0 255 0 0 0 255 255 255 255 0 255 255 255 255 0 255 255 255 255 0 255 255 255 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 0 0 0 0 0 0 255 0 255 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 0 0 255 0 0 0 255 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 255 0 0 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 0 255 255 255 0 0 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 0 255 0 0 255 0 0 255 0 0 255 255 0 0 255 0 0 255 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 255 255 0 0 0 0 0 0 0 0 0 0 255 255 255 0 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 255 255 255 0 0 0 255 0 0 0 255 255 255 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 255 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 0 0 0 0 255 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 127 0 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 0 127 0 127 127 0 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 127 127 127 127 0 127 127 127 127 127 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/TwXCursors.h0000644000000000000000000027130312635011627025622 0ustar rootroot// --------------------------------------------------------------------------- // // @file TwXCursors.h // @brief Bitmaps data for cursors // @author Philippe Decaudin - http://www.antisphere.com // @license This file is part of the AntTweakBar library. // For conditions of distribution and use, see License.txt // // note: Private header // // --------------------------------------------------------------------------- static int g_CurHot[][2] = { {16, 15}, // curs00 {16, 15}, // curs01 {16, 15}, // curs02 {16, 15}, // curs03 {16, 15}, // curs04 {16, 15}, // curs05 {16, 15}, // curs06 {16, 15}, // curs07 {16, 15}, // curs08 {16, 15}, // curs09 {16, 15}, // curs10 {16, 15}, // curs11 {16, 15}, // curs12 {16, 15} // curs13 }; static bool g_CurPict[][32*32] = { { // curs00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs01 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs02 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs03 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs04 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs05 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs06 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs07 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs08 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs09 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs10 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs11 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs12 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // curs13 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; static bool g_CurMask[][32*32] = { { // mask00 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask01 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask02 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask03 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask04 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask05 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask06 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask07 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask08 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask09 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { // mask10 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, { // mask11 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask12 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { // mask13 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00000.cur0000644000000000000000000000050612635011627025225 0ustar rootroot 0( @  @A  A@  <<?8?8?8?<?<ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00001.cur0000644000000000000000000000050612635011627025226 0ustar rootroot 0( @   @@@ @@@?8x??????????x8?ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00002.cur0000644000000000000000000000050612635011627025227 0ustar rootroot 0( @l       ?Ǐ ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00003.cur0000644000000000000000000000050612635011627025230 0ustar rootroot 0( @ pP8 q  o!?ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00004.cur0000644000000000000000000000050612635011627025231 0ustar rootroot 0( @0 0 | ?|?ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00005.cur0000644000000000000000000000050612635011627025232 0ustar rootroot 0( @@  80????xx| ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00006.cur0000644000000000000000000000050612635011627025233 0ustar rootroot 0( @ ((     cqq?ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00007.cur0000644000000000000000000000050612635011627025234 0ustar rootroot 0( @x$D@@  @@D$x~ ~?????????? ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00008.cur0000644000000000000000000000050612635011627025235 0ustar rootroot 0( @À     (( ?qqqode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00009.cur0000644000000000000000000000050612635011627025236 0ustar rootroot 0( @08  @ xxp????ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00010.cur0000644000000000000000000000050612635011627025226 0ustar rootroot 0( @ | 0 0?|?ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00011.cur0000644000000000000000000000050612635011627025227 0ustar rootroot 0( @q 8Pp ?!oode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00012.cur0000644000000000000000000000050612635011627025230 0ustar rootroot 0( @     l ?ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/cur00013.cur0000644000000000000000000000050612635011627025231 0ustar rootroot 0( @ @@ ????~?<?<?~?????ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs00.pbm0000644000000000000000000000410212635011627025151 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs01.pbm0000644000000000000000000000410212635011627025152 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs02.pbm0000644000000000000000000000410212635011627025153 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs03.pbm0000644000000000000000000000410212635011627025154 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs04.pbm0000644000000000000000000000410212635011627025155 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs05.pbm0000644000000000000000000000410212635011627025156 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs06.pbm0000644000000000000000000000410212635011627025157 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs07.pbm0000644000000000000000000000410212635011627025160 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs08.pbm0000644000000000000000000000410212635011627025161 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs09.pbm0000644000000000000000000000410212635011627025162 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs10.pbm0000644000000000000000000000410212635011627025152 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs11.pbm0000644000000000000000000000410212635011627025153 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs12.pbm0000644000000000000000000000410212635011627025154 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/curs13.pbm0000644000000000000000000000410212635011627025155 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask00.pbm0000644000000000000000000000410212635011627025130 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask01.pbm0000644000000000000000000000410212635011627025131 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask02.pbm0000644000000000000000000000410212635011627025132 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask03.pbm0000644000000000000000000000410212635011627025133 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask04.pbm0000644000000000000000000000410212635011627025134 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask05.pbm0000644000000000000000000000410212635011627025135 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask06.pbm0000644000000000000000000000410212635011627025136 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask07.pbm0000644000000000000000000000410212635011627025137 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask08.pbm0000644000000000000000000000410212635011627025140 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask09.pbm0000644000000000000000000000410212635011627025141 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask10.pbm0000644000000000000000000000410212635011627025131 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask11.pbm0000644000000000000000000000410212635011627025132 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask12.pbm0000644000000000000000000000410212635011627025133 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/res/mask13.pbm0000644000000000000000000000410212635011627025134 0ustar rootrootP1 # Created by Paint Shop Pro 32 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ode-0.14/contrib/InteractiveCollisions/deps/AntTweakBar/src/resource.h0000644000000000000000000000176212635011627024555 0ustar rootroot//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by AntTweakBar.rc // #define IDC_CURSOR1 101 #define IDC_CURSOR2 102 #define IDC_CURSOR3 103 #define IDC_CURSOR4 104 #define IDC_CURSOR5 105 #define IDC_CURSOR6 106 #define IDC_CURSOR7 107 #define IDC_CURSOR8 108 #define IDC_CURSOR9 109 #define IDC_CURSOR10 110 #define IDC_CURSOR11 111 #define IDC_CURSOR12 112 #define IDC_CURSOR13 113 #define IDC_CURSOR14 114 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 115 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ode-0.14/contrib/InteractiveCollisions/deps/Makefile.am0000644000000000000000000000002712635011627021650 0ustar rootrootSUBDIRS = AntTweakBar ode-0.14/contrib/InteractiveCollisions/src/0000775000000000000000000000000012635012023017442 5ustar rootrootode-0.14/contrib/InteractiveCollisions/src/Makefile.am0000644000000000000000000000055612635011627021513 0ustar rootrootAM_CPPFLAGS = $(ODE_CFLAGS) $(OPENGL_CFLAGS) \ -I${top_srcdir}/deps/AntTweakBar/include AM_LDFLAGS = ../deps/AntTweakBar/src/libAntTweakBar.la \ $(ODE_LIBS) $(OPENGL_LIBS) if GLFW AM_CPPFLAGS += $(GLFW_CFLAGS) AM_LDFLAGS += $(GLFW_LIBS) endif bin_PROGRAMS = icollision icollision_SOURCES = main.cpp \ camera.cpp camera.hpp ode-0.14/contrib/InteractiveCollisions/src/camera.cpp0000644000000000000000000000730512635011627021412 0ustar rootroot#include #include #include #include #include #include #include "camera.hpp" using std::clog; using std::endl; Camera::Camera() : fov(50), aspect(1), znear(.01), zfar(50), width(0), height(0), window_x(0), window_y(0) { reset(); } void Camera::transform_proj() const { glLoadIdentity(); gluPerspective(fov, aspect, znear, zfar); } void Camera::transform_model() const { glLoadIdentity(); gluLookAt(x, y, z, tx, ty, tz, up[0], up[1], up[2]); } void Camera::reset() { x = 0; y = 0; z = 0; tx = 0; ty = 0; tz = 0; up[0] = 0; up[1] = 1; up[2] = 0; right[0] = 1; right[1] = 0; right[2] = 0; } void Camera::reshape(int w, int h) { aspect = float(w)/h; width = w; height = h; } float Camera::normx(int x) const { return (2.0*(x-window_x)) / width - 1.0; } float Camera::normy(int y) const { return -((2.0*(y-window_y)) / height - 1.0); } void Camera::press(int x, int y) { old_x = normx(x); old_y = normy(y); } float Camera::to_sphere_z(float r, float x, float y) { float delta = x*x + y*y; if (delta > r*r) return 0; else return std::sqrt(r*r - delta); } void showm(dMatrix3 m) { for (int i=0; i<3; ++i) { for (int j=0; j<3; ++j) clog << " " << std::setw(12) << m[i*4 + j]; clog << endl; } clog << endl; } void showv(dVector3 v) { for (int i=0; i<3; ++i) clog << " " << std::setw(12) << v[i]; clog << endl << endl; } void Camera::arcball(int mx, int my) { const float radius = 2; float new_x, new_y; new_x = normx(mx); new_y = normy(my); float old_z, new_z; old_z = to_sphere_z(radius, old_x, old_y); new_z = to_sphere_z(radius, new_x, new_y); dVector3 m = { old_x, old_y, old_z }; dVector3 n = { new_x, new_y, new_z }; //std::clog << "old: " << old_x << " , " << old_y << std::endl; //std::clog << "new: " << new_x << " , " << new_y << std::endl; old_x = new_x; old_y = new_y; dNormalize3(m); dNormalize3(n); // axis of rotation r is along m cross n dVector3 r; dCROSS(r, =, m, n); float s = dLENGTH(r); s = std::min(1.f, std::max(-1.f, s)); float angle = std::asin(s); // build the local matrix dVector3 f = {x-tx, y-ty, z-tz}; dNormalize3(f); //showv(f); dCROSS(right, =, up, f); dNormalize3(right); dCROSS(up, =, f, right); dNormalize3(up); dMatrix3 localR = { right[0], right[1], right[2], 0, up[0], up[1], up[2], 0, f[0], f[1], f[2] }; //showm(localR); // bring the axis to global coordinates dVector3 global_r; dMultiply1_331(global_r, localR, r); dMatrix3 R; dRFromAxisAndAngle(R, global_r[0], global_r[1], global_r[2], -2*angle); // we re-position the camera, maintaining the distance dVector3 p = { x, y, z }; dVector3 t = { tx, ty, tz }; dVector3 d; dSubtractVectors3(d, p, t); // d = p - t dVector3 nd; dMultiply0_331(nd, R, d); x = nd[0] + tx; y = nd[1] + ty; z = nd[2] + tz; dVector3 nup; dMultiply0_331(nup, R, up); dCopyVector3(up, nup); dNormalize3(up); dVector3 nright; dMultiply0_331(nright, R, right); dCopyVector3(right, nright); dNormalize3(right); } double Camera::dist() const { double dx = tx - x; double dy = ty - y; double dz = tz - z; return std::sqrt(dx*dx + dy*dy + dz*dz); } void Camera::zoom(float d) { double dx = x - tx; double dy = y - ty; double dz = z - tz; dx *= d; dy *= d; dz *= d; x = tx + dx; y = ty + dy; z = tz + dz; } ode-0.14/contrib/InteractiveCollisions/src/camera.hpp0000644000000000000000000000140012635011627021405 0ustar rootroot#ifndef CAMERA_H #define CAMERA_H #include /* Simple implementatino of a camera that orbits the origin */ struct Camera { float fov, aspect, znear, zfar; float x, y, z; // eye pos float tx, ty, tz; // target dVector3 up; dVector3 right; int width, height, window_x, window_y; Camera(); void transform_proj() const; void transform_model() const; void reshape(int w, int h); void press(int x, int y); void arcball(int x, int y); double dist() const; void zoom(float d); // >1 to zoom out, <1 to zoom in private: float old_x, old_y; void reset(); float normx(int x) const; float normy(int y) const; float to_sphere_z(float r, float x, float y); }; #endif ode-0.14/contrib/InteractiveCollisions/src/main.cpp0000644000000000000000000006103412635011627021105 0ustar rootroot#include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #if USE_GLFW #include #endif #include #include #include "camera.hpp" using std::cout; using std::cerr; using std::clog; using std::endl; TwBar *left_bar = 0; TwBar *right_bar = 0; float left_x=-1, left_y=0, left_z=0; float left_quat[4] = {0, 0, 0, 1}; // x y z w float right_x=1, right_y=0, right_z=0; float right_quat[4] = {0, 0, 0, 1}; // x y z w int left_geom_type = 0; int right_geom_type = 0; // left float left_sphere_radius = 1; float left_box_width = 1; float left_box_height = 1; float left_box_depth = 1; float left_capsule_radius = 1; float left_capsule_length = 1; float right_sphere_radius = 1; float right_box_width = 1; float right_box_height = 1; float right_box_depth = 1; float right_capsule_radius = 1; float right_capsule_length = 1; struct Color { float r, g, b, a; Color() : r(0), g(0), b(0), a(0) {} Color(float x, float y, float z, float w=1.0) : r(x), g(y), b(z), a(w) {} }; Color left_fill, left_wire, right_fill, right_wire, contact_p, contact_d, contact_n; dGeomID left_geom=0, right_geom=0; Camera cam; enum GeomType { Sphere, Box, Capsule }; void draw(); void left_update_position(); void right_update_position(); #if USE_GLFW void GLFWCALL mouse_moved(int x, int y); void GLFWCALL mouse_button(int button, int action); void GLFWCALL mouse_wheel(int pos); void GLFWCALL resize(int width, int height) { // Set OpenGL viewport and camera glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40, (double)width/height, 1, 10); gluLookAt(-1,0,3, 0,0,0, 0,1,0); cam.reshape(width, height); // Send the new window size to AntTweakBar TwWindowSize(width, height); } void init_gl() { if (!glfwInit()) { cerr << "Failed to initialize GLFW" << endl; exit(EXIT_FAILURE); } std::atexit(glfwTerminate); if (!glfwOpenWindow(1024, 768, 0,0,0,0, 16, // depth 0, // stencil GLFW_WINDOW)) { exit(EXIT_FAILURE); } glfwEnable(GLFW_MOUSE_CURSOR); glfwEnable(GLFW_KEY_REPEAT); glfwSetWindowTitle("ODE collision test environment"); // Initialize AntTweakBar TwInit(TW_OPENGL, NULL); // Set GLFW event callbacks // - Redirect window size changes to the callback function WindowSizeCB glfwSetWindowSizeCallback(resize); glfwSetMouseButtonCallback(mouse_button); glfwSetMousePosCallback(mouse_moved); glfwSetMouseWheelCallback((GLFWmousewheelfun)mouse_wheel); // - Directly redirect GLFW key events to AntTweakBar glfwSetKeyCallback((GLFWkeyfun)TwEventKeyGLFW); // - Directly redirect GLFW char events to AntTweakBar glfwSetCharCallback((GLFWcharfun)TwEventCharGLFW); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void loop() { bool running = true; while (running) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw(); TwDraw(); glfwSwapBuffers(); running = glfwGetWindowParam(GLFW_OPENED) && !glfwGetKey(GLFW_KEY_ESC); } } static bool left_dragging = false; static bool right_dragging = false; static bool left_dragging_geom = false; static bool right_dragging_geom = false; static int prev_x = 0; static int prev_y = 0; void GLFWCALL mouse_moved(int x, int y) { int dx = x - prev_x; int dy = y - prev_y; // don't let Tw eat the events if we are doing something if (!right_dragging && !left_dragging && !left_dragging_geom && !right_dragging_geom) TwEventMousePosGLFW(x, y); else { if (right_dragging) { cam.arcball(x, y); } if (left_dragging) { float s = 0.001*cam.dist(); cam.tx += s*(-dx * cam.right[0] + dy*cam.up[0]); cam.ty += s*(-dx * cam.right[1] + dy*cam.up[1]); cam.tz += s*(-dx * cam.right[2] + dy*cam.up[2]); } if (left_dragging_geom) { float s = 0.001*cam.dist(); left_x += s*(dx * cam.right[0] - dy*cam.up[0]); left_y += s*(dx * cam.right[1] - dy*cam.up[1]); left_z += s*(dx * cam.right[2] - dy*cam.up[2]); left_update_position(); } if (right_dragging_geom) { float s = 0.001*cam.dist(); right_x += s*(dx * cam.right[0] - dy*cam.up[0]); right_y += s*(dx * cam.right[1] - dy*cam.up[1]); right_z += s*(dx * cam.right[2] - dy*cam.up[2]); right_update_position(); } } prev_x = x; prev_y = y; } void GLFWCALL mouse_button(int button, int action) { int x, y; glfwGetMousePos(&x, &y); int handled = TwEventMouseButtonGLFW(button, action); if (!handled) { if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) { cam.press(x, y); right_dragging = true; } if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_RELEASE) { right_dragging = false; } if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) { GLdouble model[16]; GLdouble proj[16]; GLint viewport[4]; glGetDoublev(GL_MODELVIEW_MATRIX, model); glGetDoublev(GL_PROJECTION_MATRIX, proj); glGetIntegerv(GL_VIEWPORT, viewport); GLdouble ox, oy, oz; if (gluUnProject(x, viewport[3] - y, 0, model, proj, viewport, &ox, &oy, &oz) == GLU_TRUE) { double dx, dy, dz; dx = ox - cam.x; dy = oy - cam.y; dz = oz - cam.z; dGeomID ray = dCreateRay(0, 100); dGeomRaySet(ray, cam.x, cam.y, cam.z, dx, dy, dz); dContactGeom left_contact, right_contact; int leftn, rightn; leftn = dCollide(ray, left_geom, 1, &left_contact, sizeof left_contact); rightn = dCollide(ray, right_geom, 1, &right_contact, sizeof right_contact); if (leftn && !rightn) left_dragging_geom = true; if (rightn && !leftn) right_dragging_geom = true; if (leftn && rightn) { if (left_contact.depth < right_contact.depth) left_dragging_geom = true; else right_dragging_geom = true; } dGeomDestroy(ray); } if (!left_dragging_geom && !right_dragging_geom) left_dragging = true; } if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) { left_dragging = false; left_dragging_geom = false; right_dragging_geom = false; } } } static int prev_wheel = 0; void GLFWCALL mouse_wheel(int pos) { if (!TwEventMouseWheelGLFW(pos)) { int delta = pos - prev_wheel; // set the camera zoom if (delta > 0) cam.zoom(1.1); if (delta < 0) cam.zoom(1/1.1); } prev_wheel = pos; } #else void init_gl() {} void loop() {} #endif // generic getters void TW_CALL get_float(void *value, void *data) { float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *v = *d; } void TW_CALL get_int(void *value, void *data) { int *v = reinterpret_cast(value); int *d = reinterpret_cast(data); *v = *d; } void enable_sphere(TwBar *bar) { TwSetParam(bar, "SphereRadius", "visible", TW_PARAM_CSTRING, 1, "true"); } void disable_sphere(TwBar *bar) { TwSetParam(bar, "SphereRadius", "visible", TW_PARAM_CSTRING, 1, "false"); } void enable_box(TwBar *bar) { TwSetParam(bar, "BoxWidth", "visible", TW_PARAM_CSTRING, 1, "true"); TwSetParam(bar, "BoxHeight", "visible", TW_PARAM_CSTRING, 1, "true"); TwSetParam(bar, "BoxDepth", "visible", TW_PARAM_CSTRING, 1, "true"); } void disable_box(TwBar *bar) { TwSetParam(bar, "BoxWidth", "visible", TW_PARAM_CSTRING, 1, "false"); TwSetParam(bar, "BoxHeight", "visible", TW_PARAM_CSTRING, 1, "false"); TwSetParam(bar, "BoxDepth", "visible", TW_PARAM_CSTRING, 1, "false"); } void enable_capsule(TwBar *bar) { TwSetParam(bar, "CapsuleRadius", "visible", TW_PARAM_CSTRING, 1, "true"); TwSetParam(bar, "CapsuleLength", "visible", TW_PARAM_CSTRING, 1, "true"); } void disable_capsule(TwBar *bar) { TwSetParam(bar, "CapsuleRadius", "visible", TW_PARAM_CSTRING, 1, "false"); TwSetParam(bar, "CapsuleLength", "visible", TW_PARAM_CSTRING, 1, "false"); } void left_update_position() { if (left_geom) dGeomSetPosition(left_geom, left_x, left_y, left_z); } void right_update_position() { if (right_geom) dGeomSetPosition(right_geom, right_x, right_y, right_z); } void left_update_quat() { if (left_geom) { dQuaternion q = {left_quat[3], left_quat[0], left_quat[1], left_quat[2]}; dGeomSetQuaternion(left_geom, q); } } void right_update_quat() { if (right_geom) { dQuaternion q = {right_quat[3], right_quat[0], right_quat[1], right_quat[2]}; dGeomSetQuaternion(right_geom, q); } } void choose_left_geom(int type); void choose_right_geom(int type); void TW_CALL left_set_geom_type(const void *value, void *data) { const int *v = reinterpret_cast(value); int *d = reinterpret_cast(data); *d = *v; choose_left_geom(*d); } void TW_CALL right_set_geom_type(const void *value, void *data) { const int *v = reinterpret_cast(value); int *d = reinterpret_cast(data); *d = *v; choose_right_geom(*d); } void TW_CALL left_set_val(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; left_update_position(); } void TW_CALL right_set_val(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; right_update_position(); } void TW_CALL left_set_quat(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d++ = *v++; *d++ = *v++; *d++ = *v++; *d++ = *v++; left_update_quat(); } void TW_CALL right_set_quat(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d++ = *v++; *d++ = *v++; *d++ = *v++; *d++ = *v++; right_update_quat(); } void TW_CALL get_quat(void *value, void *data) { float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *v++ = *d++; *v++ = *d++; *v++ = *d++; *v++ = *d++; } void TW_CALL left_sphere_set_radius(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomSphereSetRadius(left_geom, left_sphere_radius); } void TW_CALL right_sphere_set_radius(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomSphereSetRadius(right_geom, right_sphere_radius); } void TW_CALL left_box_set_size(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomBoxSetLengths(left_geom, left_box_width, left_box_height, left_box_depth); } void TW_CALL right_box_set_size(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomBoxSetLengths(right_geom, right_box_width, right_box_height, right_box_depth); } void TW_CALL left_capsule_set_radius(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomCapsuleSetParams(left_geom, left_capsule_radius, left_capsule_length); } void TW_CALL left_capsule_set_length(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomCapsuleSetParams(left_geom, left_capsule_radius, left_capsule_length); } void TW_CALL right_capsule_set_radius(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomCapsuleSetParams(right_geom, right_capsule_radius, right_capsule_length); } void TW_CALL right_capsule_set_length(const void *value, void *data) { const float *v = reinterpret_cast(value); float *d = reinterpret_cast(data); *d = *v; dGeomCapsuleSetParams(right_geom, right_capsule_radius, right_capsule_length); } void choose_left_geom(int g) { if (left_geom) { dGeomDestroy(left_geom); left_geom = 0; } // TODO: update ODE geom if (g == Sphere) { enable_sphere(left_bar); left_geom = dCreateSphere(0, left_sphere_radius); } else disable_sphere(left_bar); if (g == Box) { enable_box(left_bar); left_geom = dCreateBox(0, left_box_width, left_box_height, left_box_depth); } else disable_box(left_bar); if (g == Capsule) { enable_capsule(left_bar); left_geom = dCreateCapsule(0, left_capsule_radius, left_capsule_length); } else disable_capsule(left_bar); left_update_position(); left_update_quat(); } void choose_right_geom(int g) { if (right_geom) { dGeomDestroy(right_geom); right_geom = 0; } // TODO: update ODE geom if (g == Sphere) { enable_sphere(right_bar); right_geom = dCreateSphere(0, right_sphere_radius); } else disable_sphere(right_bar); if (g == Box) { enable_box(right_bar); right_geom = dCreateBox(0, right_box_width, right_box_height, right_box_depth); } else disable_box(right_bar); if (g == Capsule) { enable_capsule(right_bar); right_geom = dCreateCapsule(0, right_capsule_radius, right_capsule_length); } else disable_capsule(right_bar); right_update_position(); right_update_quat(); } void TW_CALL reset_camera(void*) { cam.x = 0; cam.y = 0; cam.z = 8; cam.tx = 0; cam.ty = 0; cam.tz = 0; cam.up[0] = 0; cam.up[1] = 1; cam.up[2] = 0; cam.right[0] = 1; cam.right[1] = 0; cam.right[2] = 0; } void TW_CALL reset_geoms(void*) { choose_left_geom(Sphere); choose_right_geom(Sphere); left_x = -1; left_y = 0; left_z = 0; right_x = 1; right_y = 0; right_z = 0; left_quat[0] = 1; left_quat[1] = 0; left_quat[2] = 0; left_quat[3] = 0; right_quat[0] = 1; right_quat[1] = 0; right_quat[2] = 0; right_quat[3] = 0; left_update_position(); left_update_quat(); right_update_position(); right_update_quat(); } void init_ui() { TwBar *bar = TwNewBar("Controls"); TwAddButton(bar, "ResetCamera", reset_camera, 0, "label='Reset camera'"); TwAddButton(bar, "ResetGeoms", reset_geoms, 0, "label='Reset geoms'"); TwType gtype = TwDefineEnumFromString("GeomType", "Sphere,Box,Capsule"); left_bar = TwNewBar("Left"); TwAddVarCB(left_bar, "Geom", gtype, left_set_geom_type, get_int, &left_geom_type, NULL); TwSetParam(left_bar, NULL, "position", TW_PARAM_CSTRING, 1, "50 50"); TwAddVarCB(left_bar, "X", TW_TYPE_FLOAT, left_set_val, get_float, &left_x, "min=-100 max=100 step=0.01"); TwAddVarCB(left_bar, "Y", TW_TYPE_FLOAT, left_set_val, get_float, &left_y, "min=-100 max=100 step=0.01"); TwAddVarCB(left_bar, "Z", TW_TYPE_FLOAT, left_set_val, get_float, &left_z, "min=-100 max=100 step=0.01"); TwAddVarCB(left_bar, "Quat", TW_TYPE_QUAT4F, left_set_quat, get_quat, left_quat, "showval=true opened=true"); TwAddVarCB(left_bar, "SphereRadius", TW_TYPE_FLOAT, left_sphere_set_radius, get_float, &left_sphere_radius, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(left_bar, "BoxWidth", TW_TYPE_FLOAT, left_box_set_size, get_float, &left_box_width, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(left_bar, "BoxHeight", TW_TYPE_FLOAT, left_box_set_size, get_float, &left_box_height, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(left_bar, "BoxDepth", TW_TYPE_FLOAT, left_box_set_size, get_float, &left_box_depth, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(left_bar, "CapsuleRadius", TW_TYPE_FLOAT, left_capsule_set_radius, get_float, &left_capsule_radius, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(left_bar, "CapsuleLength", TW_TYPE_FLOAT, left_capsule_set_length, get_float, &left_capsule_length, " min=0.001 max=100 step=0.01 visible=false"); #if 1 right_bar = TwNewBar("Right"); TwAddVarCB(right_bar, "Geom", gtype, right_set_geom_type, get_int, &right_geom_type, NULL); TwSetParam(right_bar, NULL, "position", TW_PARAM_CSTRING, 1, "650 50"); TwAddVarCB(right_bar, "X", TW_TYPE_FLOAT, right_set_val, get_float, &right_x, "min=-100 max=100 step=0.01"); TwAddVarCB(right_bar, "Y", TW_TYPE_FLOAT, right_set_val, get_float, &right_y, "min=-100 max=100 step=0.01"); TwAddVarCB(right_bar, "Z", TW_TYPE_FLOAT, right_set_val, get_float, &right_z, "min=-100 max=100 step=0.01"); TwAddVarCB(right_bar, "Quat", TW_TYPE_QUAT4F, right_set_quat, get_quat, right_quat, "showval=true opened=true"); TwAddVarCB(right_bar, "SphereRadius", TW_TYPE_FLOAT, right_sphere_set_radius, get_float, &right_sphere_radius, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(right_bar, "BoxWidth", TW_TYPE_FLOAT, right_box_set_size, get_float, &right_box_width, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(right_bar, "BoxHeight", TW_TYPE_FLOAT, right_box_set_size, get_float, &right_box_height, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(right_bar, "BoxDepth", TW_TYPE_FLOAT, right_box_set_size, get_float, &right_box_depth, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(right_bar, "CapsuleRadius", TW_TYPE_FLOAT, right_capsule_set_radius, get_float, &right_capsule_radius, " min=0.001 max=100 step=0.01 visible=false"); TwAddVarCB(right_bar, "CapsuleLength", TW_TYPE_FLOAT, right_capsule_set_length, get_float, &right_capsule_length, " min=0.001 max=100 step=0.01 visible=false"); #endif } void draw_sphere(float radius, Color fill, Color wire) { const int stacks = std::max(16, int(radius * 16)); const int slices = std::max(32, int(radius * 32)); GLUquadric* q = gluNewQuadric(); gluQuadricDrawStyle(q, GLU_FILL); glColor4f(fill.r, fill.g, fill.b, fill.a); gluSphere(q, radius, slices, stacks); gluQuadricDrawStyle(q, GLU_LINE); glColor4f(wire.r, wire.g, wire.b, wire.a); gluSphere(q, radius, slices, stacks); gluDeleteQuadric(q); } void draw_box_face(float w, float h, float d, Color fill, Color wire) { const int partsw = std::max(2, int(w*4)); const int partsh = std::max(2, int(h*4)); glLineWidth(1); glBegin(GL_QUADS); glColor4f(fill.r, fill.g, fill.b, fill.a); glVertex3f(-w/2, -h/2, d/2); glVertex3f( w/2, -h/2, d/2); glVertex3f( w/2, h/2, d/2); glVertex3f(-w/2, h/2, d/2); glEnd(); glBegin(GL_LINES); glColor4f(wire.r, wire.g, wire.b, wire.a); for (int i=0; i<=partsw; ++i) { // vertical lines glVertex3f(-w/2 + i*w/partsw, -h/2, d/2); glVertex3f(-w/2 + i*w/partsw, h/2, d/2); } for (int i=0; i<=partsh; ++i) { // horizontal lines glVertex3f(-w/2, -h/2+i*h/partsh, d/2); glVertex3f( w/2, -h/2+i*h/partsh, d/2); } glEnd(); } void draw_box(float w, float h, float d, Color fill, Color wire) { draw_box_face(w, h, d, fill, wire); glPushMatrix(); glRotatef(90, 0, 1, 0); draw_box_face(d, h, w, fill, wire); glPopMatrix(); glPushMatrix(); glRotatef(180, 0, 1, 0); draw_box_face(w, h, d, fill, wire); glPopMatrix(); glPushMatrix(); glRotatef(270, 0, 1, 0); draw_box_face(d, h, w, fill, wire); glPopMatrix(); glPushMatrix(); glRotatef(90, 1, 0, 0); draw_box_face(w, d, h, fill, wire); glPopMatrix(); glPushMatrix(); glRotatef(270, 1, 0, 0); draw_box_face(w, d, h, fill, wire); glPopMatrix(); } void draw_cylinder(float radius, float length, Color fill, Color wire) { GLUquadric *q = gluNewQuadric(); const int stacks = std::max(2, int(length*4)); const int slices = std::max(32, int(radius * 32)); glPushMatrix(); glTranslatef(0, 0, -length/2); gluQuadricDrawStyle(q, GLU_FILL); glColor4f(fill.r, fill.g, fill.b, fill.a); gluCylinder(q, radius, radius, length, slices, stacks); gluQuadricDrawStyle(q, GLU_LINE); glColor4f(wire.r, wire.g, wire.b, wire.a); gluCylinder(q, radius, radius, length, slices, stacks); glPopMatrix(); gluDeleteQuadric(q); } void draw_capsule(float radius, float length, Color fill, Color wire) { draw_cylinder(radius, length, fill, wire); glEnable(GL_CLIP_PLANE0); glPushMatrix(); glTranslatef(0, 0, length/2); GLdouble plane[4] = {0, 0, 1, 0}; glClipPlane(GL_CLIP_PLANE0, plane); draw_sphere(radius, fill, wire); glPopMatrix(); glPushMatrix(); glTranslatef(0, 0, -length/2); plane[2] = -1; glClipPlane(GL_CLIP_PLANE0, plane); draw_sphere(radius, fill, wire); glPopMatrix(); glDisable(GL_CLIP_PLANE0); } void draw_geom(dGeomID geom, Color fill, Color wire) { if (!geom) return; glPushMatrix(); const dReal *p = dGeomGetPosition(geom); const dReal *r = dGeomGetRotation(geom); GLfloat m[16] = { r[0], r[4], r[8], 0, r[1], r[5], r[9], 0, r[2], r[6], r[10], 0, p[0], p[1], p[2], 1 }; glMultMatrixf(m); glLineWidth(1); int c = dGeomGetClass(geom); switch (c) { case dSphereClass: { float r = dGeomSphereGetRadius(geom); draw_sphere(r, fill, wire); break; } case dBoxClass: { dVector3 lengths; dGeomBoxGetLengths(geom, lengths); draw_box(lengths[0], lengths[1], lengths[2], fill, wire); break; } case dCapsuleClass: { dReal radius, length; dGeomCapsuleGetParams(geom, &radius, &length); draw_capsule(radius, length, fill, wire); break; } } glPopMatrix(); } void draw_contact(const dContactGeom& c, Color p, Color d, Color n) { glPointSize(5); glBegin(GL_POINTS); glColor4f(p.r, p.g, p.b, p.a); glVertex3f(c.pos[0], c.pos[1], c.pos[2]); glEnd(); const float scale = c.depth; glLineWidth(3); glBegin(GL_LINES); glColor4f(d.r, d.g, d.b, d.a); glVertex3f(c.pos[0], c.pos[1], c.pos[2]); glVertex3f(c.pos[0]+c.normal[0]*scale, c.pos[1]+c.normal[1]*scale, c.pos[2]+c.normal[2]*scale); glEnd(); const float cscale = cam.dist() * 0.125; glLineWidth(1); glBegin(GL_LINES); glColor4f(n.r, n.g, n.b, n.a); glVertex3f(c.pos[0], c.pos[1], c.pos[2]); glVertex3f(c.pos[0]+c.normal[0]*cscale, c.pos[1]+c.normal[1]*cscale, c.pos[2]+c.normal[2]*cscale); glEnd(); } void draw_contacts() { if (!left_geom || !right_geom) return; const int max_contacts = 32; dContactGeom dg[max_contacts]; int n = dCollide(left_geom, right_geom, max_contacts, &dg[0], sizeof(dContactGeom)); for (int i=0; iӟRʝ- V^V Hg- 7aWTWmds/(#*ҪsT@p%}_OUiY(5֝-pW8Xа !TEou +P64?dCݐEb:x>(iZzkϪ^hȸ ݑ{s/+"@AMdT3W!4!6TcK=U4R:#DgwS|oဌ噩 ˀ}B]aK*jEKGssB2{AVi7;y0rn,g%0_wS%WNA_0P> g$PƄǵSV%[h:<g/(|!W~fQYd Zxg&_vN-+dJf1o1an^@9]S(?46f*G ϝ4OB:_ryXV̻Mi6/S = d;S"򚣭IW$(#Za 5#mwkf%/ z<ai 󮁄WI 4043%.'v*% ( ^Hk奴֩pʰ=n-׽c@2o0ˈ@z4短G&sst,dlyɐ11$SG֨ V).O.f^#,ԝ=m6+)@|8\6c ?Br+Yk5{THeGL@XO`X{E@s٤Ab% -BeFXߧȰٓw:8% 0|GCL^ĞƠnș4{&mj#3υ〻~o3*Xs.M[2߶v?'ްNYzն! 3dCz?'tԳjchϰVwrC (ruQ#v))?鄃هOQ%1{ H6V۲nƑl@3!ǻ=nl8E~HQ_i (!x*={NZEa:qNspJxW5oDZTnlbjJ.lHǤJ$&tZ̃+oaFFU%ZBJl @f)}XOYt{סRչ*`1hϹbCلVJ:ikD^Aċ~@lmiD's]zHƴr✂:!dD|էc˜C>OT*؆S&sBüyG/ 8x.j+ BT]WƵ"yGI72y{Y(9O+f7b=j,#<'E-&oS!I1a2 [i$gbR`bR /ow0a)RHȍ DWT43-F1wEGgFK pD~sG@W(4)HM{슨l+(/^&=1qDQ@MxB9Ų^Rk?II%,nWp@E<մbWN%7Iliwj>vKևkns( yfwp<:`SYnJҰ_Uz9>XIVp!@˼.t|U9CA{$hޜH5cNfq_u/Q+iµWS KpM2w͉j?hHIk ${ Gî@T]H1T rr/C$'~8^O|9P OK9r 5M!jS &z:TeKQW멢$>Y5"sخ1$KgZ!Lio=u8b{ϊ)>~,$D.xvRV1~i f+-BCrD8! V{U%}ɜ蹶$7ÂlsT,J co0 `1T7f_5=  D3in4u?5Mֆ(75ZN];ɍVx 3=\bWIܐU{j}˜tWy6D}{-XeŅS5nGHNIInɷwZW6 I,lA*:ĝvbZ1t k}ڡHMw/o Z `cgag&YIYTKG3Wdg /]âb*P'z*]!%z}cDr^ k8WkQQa! tU@.}W h){|)µX" PK-FB$b%ժ\P-Rk֢U+> $?ռ!ߗṘd`_ sHnj(/V`lAEx!O(P8oTKwP+H㺆kvcɰt\{QKV74"=pNp!mDj-i)e]hKgX vp#$Xw8ofJsd ~=cMӡ[v6rOR!&jɽ~%Y7`Q"ۿާ\Qĉo_C;'o2a5Dۅs0{hvcںη})v[5 4g[3^ ]識R_s  ߺ=hzokD󨫌H cy?*.vBMlIHzH&I0&8mVMi "s&S8C~Amiqʬ{5W!x2j|-}m@ A:nIsiZ`J=#tHn_qISXQQi5=qDxfo+N$;d ˍ:eW 9/;ɭj:,7݊# B%t4pkJǀA67sǟ$yAzkpȡd99 57PRHpw .F)4tL֭鹀̏@'WS4j-b,8,=Ku4Nm3ӓKn"YG79=A>s’tTpv0xr5USK7_Eָ2%zv?pvQT褣JTNRv.<4#!IM @'qy\ Րd doa oǹu3r%rJ^\)m6ڿ+0YGUVjFm(#ʱZT$ |phS1Ew%()ϼq W]ͿWT-sUfQ"pĕV$>mOmґ1$޵A ѯЮ,ZsfwXiɷzƣ"@tSz@ȢIR-X^ЭyX+q ]q5vfoN՚4Gm,[|yi\wj@HKpgU3-lPC59F54ϧX|B1_j =N|_1uX*+EX۝\~=;Yۺ=Ck8;w>է_G$͜9Cb4.^+Vј E OΈ 0?nFM/tI6z!LY" B 8:Mn׮i@ [,u<*|$ɪG5 L36y݇==~{9̓e$Y̘XS R:GkIvdǻ ]emtg}Լk fJ3''n:ٓ=*D;G sI! -[8-/&/9ĊJy^uItaOvo <,ۧX=k !++dM&4J0!sq<'gП樬X%o;-Ӷde,q8 s}6/ za~U3cGQ|6rGN(ωVbKa4 eJ8pIGbøfjK ^գCo豼 |U£TPGm kחRl}dg,*9g1:5ieTu#*f'JG7i^@5_|U$mTHG uvۢ5@1Tc+-d#ru<Տ~S[6"L7T|sRZ529>,p+ۢK=AIJDhhcOuY5'G+ !l钣(J>ߞnqIgMLH͜j,n-Cet\fGC|@w@UtnG ))AoT.v ",}_bVζsE֏kp2NPH.4Pi븱y/qÃ^=ucS}+*ikcL}_Wrϣ?pKh^d/$ھ7g#DFScKPؐ8Rʨm7p{ ;7բ &4, T`Yp> HYBb><\w;u JKZ(pz`Oۦ6W#,_MN5fårjf]" 6D8Ѷ9':hG->1.ރEM7;12مcSFy 92>Wݹ\1 Zȅa8Qi!RL}rKy|OAZ‘-FgH,#O8 $xS28:% h[DiSFhh1VW4 T0)"Xl4%+̵Hf)yu7pUMD-9tQs%q˪9Z3,\bX|R-7{9Ҹ66/ILݔk6R/rZ'!1k<0D|WFYp6\uPD|erگЌ؆#|e_nœM%QkWPp,˾Y]?B/ǝ?llde耱ˣĄkW*tm iH7-eM nUD#ÿٮXdK8x\+Oo~E2*X@)dB _Rvv>_{ޓ(\ӯ<7%I9cЄ7eju C%O)P4%.ACv/_F|/}h-iG-\zwL)6ԡ!%pw]AU6":"-Z.L2*7 ‹0s2I ,a7 >@^hXY a׿N؋*xj^|:ADžDj"9372-Ĉ(WrS'Pmz;sHˉ!i[/Dn JƊen5U;C~jlz'te+bdVv:'0S- ؖg;cwgԈn.#JgI˓eAXrD\ JO6-N>i썵2I~M {PbG9GJs N63i.h\7bW=nf\ Jk!/FoxAB"xw^ ed,qe̠l;mA^2lB+ Us%_\4>g]ݻ3<A|kJ`dеbO ̚T(Q6,E*k*$^~?` 64|hN3Ȅ_S2XIóEK /)ip(W5Ш9>npVqIעNr JVGhۈ rGz1ruua\>Rd;wX(iDkc5+;Ų}e[EĻcu&EݬrY Ke?*Kq=Rm wvLJ/~67ZR@Oz)AX m)O>äVHU N/~: ]KZ+9۶ѳTzW ׉Vz&MCn|>g O[cl]ƒۦ_Xiѻ.D9g#`So=v.N 7]a2d+qn0MP㜠ްXgq߳F2("()KY|Q6n>\@Ks;Q~{A86:{WUxIQKnڋP'1qXAeE*UV*>:Q345 [ uKPi7/3NsxcOó9@փ#I vGZkG>.%:V]dͣjA\u[m8,V?A-[ % #= $rl nV憑61)ZKd!2ANR*&FB4Յ <'06c/Dɨ~ ԛˀv8|F 3Vի'铚XB/[4# xą]{,$P;moX/ƒQy[Ucmc EVG, CB2QD pBݯNe^F ˦>(NCz&: k:8crC,RRi-QP*"e* æBa7r&l]e'&9ȫ"`/ue Ϭ~Lf8T#!Ǽn6NUgG"w^5_xtŢp.B܃L+5瞑rvTq[@zܸcm<ڭt i[`5CO^Mm(U8\%&l 5+7D|*36ąM+2p9J6Й rmpȓf糬g~.CF4Y hDq8@mTvϬYA3ݼVȹNbM0iP%p7{3^^Y,y󊇿 wև!:EFrڬ^{E FxvDa \LNMÅQbzeQ^<6)G`k|惽Q/OidS-VH U#; ډ6}a"|6?4*pJe1ڏ/Fc>6$N(5 TQ(bP`yU5s'q^gAX P6?#Oy3 5$Ḇ1%z;Vik5[OFDkN9O~PZ-\ʸKnE!FÏ| (w_vP0]',zi6 l NaO#LjLv]Ǜ>;;-F1D"#C(q5,N"j7mUԀU2Ky+w'[40_]ks'&\8IItR+hj{!.  Lڠ8MfgO4MZP)B )B_s)ڮw&laG:m4IjkhOQS+5"ZZ>ޯۺ˭{ WK"*i`lAB1o7Aac0N4' Ew~H"3yfeVE='mGUʀqcx֣X,MHL"Wɫ,Ɓ4,in.c' xiH&_[;Tb3|ސ->q@ba(Q-x hQlMut$[xYG!M\ʶEw@!h+Θ?ZV9Sl!LPm%׷d`gTY &^4g)@w*-q%D W#dJAReo:t'7q<*5sv0S8X|94ꆫ Qߟ! VtE6()NPB~?s%C(w#*3>Fqi{nnRO+t POzP0 gsU&6&x~<q(  nV5O)a0g-{V707XYiurX/}/%BKyb?Q|"/6jy #-:+)`EM5#Y-!7 iށkSbwι" -_B^!rGJW+]@3 ÜFj@opd,-_i'[ly1SɇEF̶Se&$|mh ,(?@ssH "WtU[ـ//wpJYSX(xۯr}+x0x2wdr LN Cnfy-UJv©-$% )3y [ 'xE(x ع B,tD{{;CAȑ:]=Y9wYC v|>D'ʟ-; `{ ݕHB>UIF VmjtfFBi$Ku]mcui‚@ktD7=N,H:Σ2i)`Nբ7aA܇xid##߱XNI4z8)7Ue(d&g+ '=̐Cȍ M#˜%|bY Y8F^g @lB!@ua žZ*rӛܵZ>dPeÆWN\KEX/R%5aI_.Q-Pnr* nYra@ Nl pxBU!-Hw\m3+1«p֟{s`rUkQ8u%14"5ߖ: JX[vB+F/Ή͉}$Q"%rdȀ? r&\~ y $FH4MB%Lja,{I=*Űt.&W8}q44҉ ;6s[4,$贡FCΆ"C;_+Os& O<bZM/Nlbc[7̂J}$DM\k%C؍;hpt c.X">}+~p\堺qy̜4S2rLй~5@)ŦClRjz̾ڶʹtkjB {q'/|g?i7R$xK3E`4Ŕ,PM vv: F?' E`~Y0V3Q.X4pYb/c\JV(3@;_EJ:ߊs:1L'v1Tg9OV.OOV.NB*cjG o:xPDv`ܿ 񷺶sYֲ M~#Cp ʭ]~c0n;k5Tn#| g+?S(ak2Yr7ߵv8nԃʒ@87'g-1`ˁR8GP2 GU/|DS&yQ f'ՙud2ՈE/"%S2l!ctf+ziE|_͊J% *\m~d-0>lD*;Äkrz46{oXy8q*S lh.BlV}}ԛATG:U8lНI"&ns֮VRDs>(Vw{YA 7T[ov"P&x13Y0{mpʊ |X t%(i4 EB̂WߵModT2j 9vkRIryJKrgRQ~N 6J]OHP ;oUJ "Mlr]*L!𧴀S> B,L ǁvS;[xBPH#;zԶZc5o0IVxXvcM ʴl%ePjg&\{B|"bXz!Pd{f]/*txd4*!x>ϰLDFT%}$XA܆J'#(>+5;;Nzԕ}R)?Mł|rEo둚Ԅl+;Sv~ #Y-V wAR3Jה`l08ش`׆c3F/My-@ HB0vI8eB: tܓUu.k 2}lЇ5r 1KI^jZ8ۧzȸwxmYO.5`GW>[=uehOFޱntQ3ʡ^[t9\͗"mKti6֭yڀ:<@W5^/`Fi!b'n~[a}O-k$`SVDy.Ls "Bƻ ųJ;HoJ^I kl6] %ZW `EDFtUQu~; wx3~\ebiNrIs3X<<}x:V:Y.Lד2Ftrwe)t FFs=Jlo~KmbFNX+ T"׍8֎ Yqa"4/Q(Z}?b1W^u.:`Ӿhb1ΐ7 _x h#a7(d%#zBIsJU9ОAQr*B$ ^,zo2x6C.A}ԯ'ю+s"RR`ËaNkM,i^a~| U*`B|G J F2E6^'(lW_ i)L,?#8eKSfHҷ x KmlOaWRfn؋metѾMD+aJbg? ^ I{4oJk0wh(?cdJ,z|aP"+j ܙR[pi0Uu 삚ҺK00=bŵ LvvF~,P0R3W[4iGTGXA<t.IF8"֖sLs%PNv\պDvSeB9G6[RKP{b)f#4/uCv2zO WѲV(Ppϝ15\0sN(KVͷ&Ԫ+JRS ,3aρb(pJawv4o1_4joD[f*߿SFD)NDZ$,3v>+ Ć[W8<=nY epiEz!oWoůέ&W/ɫV n fyQ9N-laҜ5nsQ" a\}[AϤs/(R$ }%F2}&83.^}]s S2||^?М9ƨ^Xmp5PKv:M=g7Rvv(p`KOd'32*j-=U|إ_ ,^@κʛyی֐w^x^h/ܻѪ#lp(i9mʯVc$1!bnPv&A ǤbI'thꮵSpHޠ"[ZUObžUXtCЬ(Iţ\9%u/;A5A'pP"ׯ-2U2ڨ2Z 򈒁%iyӏT(MT%VE:'EJ&^Y@}uO`F$!VRME)2!:WwRR TnNݿNuy3ѻŦ!p,TrE3@GΗ3KZ8ΚBKQ2E4B!ޖެO/Q݀waߣPJ}\N<}ܦIɋ=1<z]#ItQ5czxҐ`w"VvnF6@'blfqs<܍]׷};IiVssLz  LDDaۉ~iEmH?}*%`Yc_-im WER SgNs2>ƾA$zO?Qriܪ6bRs g#@^\p\ j7ڼ NGR U$.1"ޙ,yΉլͭ uQ 롉-aqLB:j)U>߮!E':@Xj z'"fBPF͉rzC ڵ-Mg߰)/ 53 6i88"^L4^џc%,wM1H'W7&Pߨ%qUUY.KM(bn؃\ Q1ߵK}NaZC?IgAa6ܗ:Ε*-Q6;IG"̐{ jKy/ݏCH#fy wJh+}@x?G fvDYTM &¨ls`w`fcg7_|O2Bb,΀yRG>xq>*O=p r.#ޱ<mq#|h\ 1faQ:Z&9f?^LsIk=Au<0An'‹7nF Ƕ!1vU$` Mln87V]'.o7uK[`7QK}BBMbF)ۑ'XC.~1$3z9VL2le 7ZC iB8kJ?yd,8+|^n[aڊTW^}x ~yq:ٷ zH=F,PD3!^RX<vaIl3{#؈+PcaJk: 5k4*ObPj"XFdzj6VYN:dKáBI-ܸM]*2_QGp'$ξy;tJYztz{tkkNb$ X5`Bt.eH wS!'n%{\wγNJ _k`k:ӡw3^zg90s'E" ÃqȀA]tGwڸ~,0fl`;+Ab`ob~)Lh5S#~B5J7 BS B+9ӐfBL`؆ CY 9?n*KT: fM\T']K[v25OZNky}yȺiHB"yh/ah,B hFW,țo`/ռܤ_\*\hCe}*9nƛ;pQ5_pQS2f-x7˜WyZ,2`xH0jd:#m$L:nLgCP&4$6<}&TޅGU~lc6NمfB{^<T8_T\jb26D"`L*´@&lX#sSJ7>j xnPDXq| 4:g{p5ͅӞuwu,[4N%#}>Bz bJgz7RNmNOj2|<)߼=XHഒ7˱^ƶ:/ 1)6!#k,LUY7R)_)9H}$_lfg Ǟm F<6TO4^ |_:{0k5gu@6ˁ_KYc:*ͤljQ, {ӄGqicPtiFYOKj#Y-jL2-`ͯa׋ ьp "R@cR|VÜ2B؁W׈ސeĽs:J8Bq7pIKJ% i0It~g]"l_ǨG~壆oPu}@俷sH{Sh*Zvϯ| Kbi}DuVadb!z,ӧ͎N2">:?Ǽ<<hs_}sFbدİvk4G #%48Q!e9hFif(`bH0'BRT8]W΅dM{2&$38\ѧ 5):ĹWR2F"bl\*n㮲/ NcïriI=H9W!@=BDo Y҃e['J_>Yc@IϠ!BԘ~ola ^KWG{+e,  +8j `@If& /v )}r%6`j=o?#)͗XĴwv^oBff y40.ob(7luz c!{ҬݣDlPF?OdIa{#ӼZ <0s' !+B^`':]d|@HN,eYePTE2݅lp*u,2^N Tl$VU٘R6/[ݢl/i F8MCʡ-Ȩv1CiUctS땰(IwS;Ip&5zJd=~QA!sȴHra궼&Аglexû5㾸{j-8Y KÊKx7GT (F3*uw/^]dRaS"afBč.Y[tRa|5fX* < 0"ɴב&-lQv<(L7EQ͍F .mWR>dnw LX ש˿(e 9*OkC\) 6-BY1%1W|W8):9.R*;#wq/|mȐG^6jsPDGd=44ٯ.\8EMen#ZJ'qs2{8Q`[ҁ.U_t !_#qJ*mMw1GUEH$\bE7(jG4W@ZVC"g[р2r.Xn.<4dd"VeG[5BO[&QYqn@9]gE;Fj{zCΛQx;0!Xtk _ġ3S:agrP'o#䶴[%H*s1->L><p1ܜ@lR}O>%S^p} 4Lxwp+(ߊor+uxtvZՆYU-ҾVI{jY/`-{ǍWsIj`̓*7'%hA$F`Ϸ=Ov!?32>ѹBsc?{UN+\ f]^˯&6$rڽY^Nx"5$]Տgf~}UV8K0B-t2uA tءh+LnaAS-wV" q?pf]b' p5 }7BM':A[hzA[aCI½cx/`G>n5OE~ua z)Ony17$c'3<>u iWFo%' @݁; M:1B};hF MTrAw*dh#`ԏ0.=[XIL1{x n pMgL~-Pz̩[h3Q3C*-4 N[} Q{D`X`MSDF*ŏ%җtJGI~?B{-E.gc0tmR{ل'9^BtB)B3U7 @BAs"4oi}DB/C2ۦ@X9eo}uG_!Nz#Ub*n}՞Ӹ v=V>IDd\tcwIa\E&;R6.&z2|^RcN&𝘝)oR9T ;œk7r aLode_CW7.mcpMMPrCWIE ?Bԣ`yVi5zVsX@c@|[ /=cNchhߙv-J饴V"5]5WSTN_llWc@z2x~-77 7W/WI,* 1AOUPؾq]> nŻGc^h› {ם2w+7ؕp<@Qͷ| 8X`l 6ZX}@b`ҼY1c_K X'o=B"-×d#G8].dn$<ލd 5nV6D?NB|~<(М$KLs,Wwe[BWe(E OK T'p1 b8.vF2znzyJ+0l>dX/C!cBտ;ʿ"~7D%S[@bN]R;<8cYul/Kl&kXlt ? Any4.{Y:!>LZg:<T/1|'J#71o-h;g.|lOpwmC}XHjupb/e/}.JKL@ G20 HnC*v2 ۸t 7{p5%FQ1i׌͠r|C^/h=S'# i礧\>A4Rq5::Na$јd(ooRE^ϥ!h̜Vp-?@WK}`sa̷tM<,PY@<*ㆱOwp'XJOaf08n Ye<"Q2 ж4tnN234FO3p;>ڨY9# &EZs&l?X_nVcP)-`^l+͏F_tKJ !Z.-Q̮N;=\C~'a{#FoIjaKĒio60IRha}%xŞpt` "&Iy/IUY"/¹PUoO5Zշ^t-`SF,A/3n#ѕfz혡\P$wċѰmpp Š^>mɃg"Qb'N":\#&&+"Q ֲVxjlRfk/@=sHF! 4o0G Dt%N # ՇO%JaS1ߎKѰ6K¨b-  e~Z+0uiV7wbozSdP\NߓnkfABX;SYд`U.S`L5S^֎(jXYu%j QgxXLGLWc_=/!~W^\ΰ2P<ß`Bs*QB&Wr! s lRn@B;,\8j7o^@Hd3[&Nh!WЎ>w:kR[8\tϺ).xLi=C`s2EvE7_롞hvo1w{~;p dX̔ w&_ XlPe~,R\0T0ӋS4ih3$"03FA&"'F'h;}U7/1<57IWs- 9æ:K0iiY>mL/x=*KӇ݅yb5?BЬ>L9iG9O \8wɮ+c|(۫KX*9F IWd_E$ʫI!$lx4ך'CAނ3m\ 0 K%N2K+Oe 鐽d/S&Sv+2wh(X5¨ ?F72 j\v H+ p̹F~%AǁRE Odp#嗅3>8H)G#No3 `=)9KA.7v2_KÂ@bmkS?jk|6"% S;PcAℓG1j_PGS,t>p-EZsl g2:?oCU!hJD07TuFr^Ms*8S8팤0`Վ5Yz i u3cIEuv7m5ptWYQ:]_-U[xƲ.)t#] SW߬j.W*!O(HB@WK͌/?,)ZmZIEꚖ}|uܥ6gB,A#@eπZ"IHX5@#I -I&0 ʔNC8>-eYg1c;h9%RPTPVS:8eϼ`rΒ0 m+$ocb}1vHрz#+f&vRdžSj ޹{SW+l/U{wEUOyG*OWss{h~nNZ\RhN-㺌VDr FjeǕf0HR\YT\XCLߥaVݵd7ÐTG"Ji0-JWNPs+[X遂J, ꭡMA{ HE:sQ_,PNW WqƊ BTz4p})| F Ѓ xPw^ Ѭ'g [uۇa~i֧~]2i/ Qǯ8ahœS|+^|+Q]1wo`v0~!4HJ*VJ9!عcLإ? xq=(6r Q$PIM1S2?$@hSRk άhGX*øH+sZ)1rQ'ܘq}6Iv>3 oy)/)ṾXj33=;E^] Hrӽvd:PG#0BG{q0pဍ{z Lt+I |"efb0C:v܋EvD.:4Xg]Y$l 2l<{,ig&L~tK%h{sLje2]M*fCF:aKE+IF K6"Hwfӓ nRHv{+ @Sq ]s*5/tB;\CZ{=3LNiD+I @) Lߑ"E&A kgDd1\.&TP#e %(~U sa-{#TʱjJ bB%qkdu`+@/vykxǹsܑ؛oT.5͢PZQ,O__ݮk4 B@ݪnrXH#%(Iq*Z;f+- ( L* {U5XgX{ehPI9\)3oT|As io|5}r#R}n\4jIwaېV]-8ij"< XsRfT'-5-rmwZ1=~#[SSsk||Rk֘yOh fy7([aa/`ㅾ7ŀLUФW2zЇDW 3wAzF}K;W0vJ~hDShКpVq0/[ h0}uB$tw{9H+;`iG׍3p<@ԑ+J F,ɃhPiXPUEݗq8}`$;K ad/Wҏ`n PfR֝B[< K ;p쳥p+n>5ˈŇ 1{\|c?v] uf!@9tw 8j3RteNk'VW*W|=w!XՋ4x좩>F'xU8gF8G)HX@\ ˉKb]w[}42%A̪ ߉qNcO͖ۤ TA/3^۱#ŽF,+Z4i( ^@nP@|d(`(T/0?%PUs֚嶢2YwiܶFA|ī+AcNeT\GD r{K7?6V`=Pn\V!8ܛ͕-!oh}iR+vXbC+ΰX|o<|U8Ü#ouwU99f@M(j ug`'oIQ9ط=lת՟M`pqaWοK|A3o{E/ bWx x(<*15PVrqJe딽Ft1*Zak_J.(]0yKME#u[zyҋ98Xڣ]҈ wc1߁-ϟZ’h609qoi*J9t6Π@vŚj!)rL\> Qky\=:;Gx~:QT$7Mu//eIskFmh-V Eu}I؇U:M ~0Fd JʚËٔy Tdl:V[LF!<o% %öS:h=wЖ)z&)N&S9ˊNK^?pq7^8A BBZS: G|oҸ~'iVߝTG8̦҇'[/UͣKt~tmճ1"I o,Wf.P S;Lq.ʍ 3 -k!׀CgJP t=,BJQt)HA-޼|8!nxh^58LT{:ܛ-szE 61 lf#.*dNAJ 9l"pUďy Hpr&z2['¨nhPN0 5蔉7 W3.S4G\EH iI>tT 㴾mI}X($Z,2+pN- tZ<tgA5YMs\u7GWX) 8ˢIE  :sĔM@boS>[%DWoˀ;叐^oiULuCNCK`my*:dz&NW1 .s'JwDk"|ݟFK\?!ݶ"Bf'4n%n @@u3㙴'x%Ӱ~qR%+ѽp 3pKc;~Q9* n[[&X1Uxw&;nf8(FU;F^ (&I،^j6퍴 ]!|Ϗjt!B| 9O1B9utg ̿pgγuYŖ}Vmr[HK n?⚵m AkDNeȼ?2auNƞ$lJ /~ެ\-;]_^ 1bjA{&gYoE; #Kڷ*e]1Yx9 9] :3E]1E.׺RFzh?I_l:q !fݬ]Jr7Rcrߞ$_"{,G0N&@?ǀhIj*=T~k| X|OAPDO9]ԝ, E~~ƑlDZeu`h3@RKlدe0A+Mvs*!tOdPp\𪉺<ѡK/9@XCPWfT[^I:Q5T#Q3#O&(!a49#jΦMY~j + =_?zò~O`?/otaѐU|y$^cW>d+Yc^; <33|.zp|zCܵ\R82#m!s,j&TXоYهɒ$4/8 f2/zL!h,ؼ, n]qlCqE=n`/ U /FIm7Sh QWhyXyXk[ʹrpIAԙ;Jg3ȖId`<5wJzk[Fx^扟wEء$w'21;˄8䐼RKǒ$Aeks1Q^ol?jM6\n 'ӌ(y5^nh >ڢ8k(Մl{+4fģ;/&"K^wb m١Qz]sj/p}{ Pd=D1TEɪZK)hA|8bnVOE ?-^y_q;l={xv+s%tfV4-{O/5Hp816:&*u*KDz8"=ۉ '"L5Z4e0V ?jfۡxN=k-?`pǭ(nfR%}cx4DBt_mdIIZ.`Ͻnz0xrrF½;uo~!;䎏#v~tx_VӃjfclG @o)9)g82ՃR77ɦ2gDI1o;BpK?W؊@ A-s[^/Z$(@zm`:m%f< 9LEuLtK58QuO JdjK._4l֟ ّDMvBܓWf5g8$?D 5O +$D[-gꁄ?8 I),R4Z 햧UHț`Qw [a9V.>?Ӈ ?Mǥj5*gY_N5V+B.`Ѳ{2{灰/Ԗ Z8gjq3x~N&UړgSFR2 ];M &RUSbnK{m)dlHw_Mי_['-az `S2H%!KfsXLrϬQDpSQ LcT j\8oVM%xj5'YZ:@`2woFtyJ𤤠"j@Qz;=bj }7S;~QMs+FJKFtW] .gUFZY6R܃ -a4?Arئ'v+[:!!6wet`+=njC>eW7wRe";(֥6vz1?(<'jsZDW%X?JZ5+>-.;]5,eS)j,sʂh׵Nu5_R)+X-5Bp w{c\?4 [:@hbHr-co^lx3^5T$f2 ᇔϦ6ǭл}'t'|jLP}EyRw GF_H<{tקZDKR4]u\ϟvN=.ށ^BO)&zz_T⌁SSP^M 8jH_Z fJA:UYF<%)溿;UY]L]?I1DHXlm;tvT>-)d|)0E/-!`K`xM σ-&a-8ͧ\ؖYf+bT105XOv<$>k9ˬ6vVy=x|slܷ'`PpY9^1![EPߑ8yuT q6tM@ Dl.`H- bG5fVN ?[Jv}:pg){ c^+b_ֹ KtXvĄѩC# 함}hSD5y~uoùE5h`]1ʲz?k\}T#[7Yż7FRrjr Ts S]?A̖~>#Oo^zQ1#r=RTmWX5,v9(S!WHP& LeK&r3M}'ap"M-g*9Sյ7ĐfT:{ov:\- g`85H'BhݑZJvwɑa:p+3Tjܠ7_6Zb6F!Ւr<4M#Xά*Z!RP-~}5rƫIe$&TH]µY/{ysI VO=-EgTEJz7񛐉 r^Pu⼽RTabqs戳W<%H +6C 4}¾L2L7'h~z1\ecQǥu?XIr.1@ٛ.Ę \t~RZ iiD)Q.VWlO*̈=@R"B,ˢ .fu )ڪ*aw:灣26Fq7>95{C2$BJ 1USqޞ=`ݯ\_7BpwlQ(\NBB,XXAp5 | z| ooawףQ !:/jQ{O)@jR4?vCLD hr[$QZMJZGM> <cYц?d27ÏzɰIgs RcEܴ8u @k"}- +gER2%XjTكw[Qy"L$ȞGK0 DtwS%zLX)O'x0R&}P:jqr9r@?Cj`#xjT'ie>*ZG P4`BxCӰRF5r$o|qjnדZ@U$=~4 "#O {TVZL=m!`sC&Yau6ORoSrWvC%y冎۳^.M_("(w C}%p 1~#;$vVބVw!KQn+ 9HER@$GgBL3S]pu EB=6s1L%IRː&cy}x1lRR)z˷1oÊcHYe?B—:l!O4|vAoXE/eRј -:ϫMz2d7}5<6qŭZ4ŋw<`,~O:w^L\ R(,sHۡd"='~oS P-M\/6Q|g?m:&4?Pc FХgʇ] p,զ"w/y-NybϻHf"u(p62Sw0pd|#إCZ?'Pғtݦɞ'pK5py6.$W}Pa6yu 8˝`D(r&XKA_Lkxs[5̖gF\|.x7\r W׃ _Z&kꗛ6(_1)2,}tt^ `p+B|abm4Tcuk7YW#b/CڴyNZL)P֜13*N (7Ea9W!u8XG u3Aj QkhMxx6qvdn[8QTPbZ~2_\) Ve޻:FfcJI΂"L;"Yܑ3&l+Њ1 ,BVAL]b|ρW08gM{b6v!bЊ9FukB2*aƣaEFdTmaIK(K@ko\ӡ4t^=ȹ @ab bj=` 'P50 ,aBHփLiP2 SDPyB01:XGC~#1rql^x4*7Ex˰)}{j/ sP  !6܌c:Ry%J|)L05 ۫hɹh3UDO)H}0v~|rfIkd!Ij<79V)ϥ7]]OmH}W14/wl˞P@}| i Ԛe!|~]%5Ι_,9bT/KGqb88%#݉QBJjƐȇ5o7og#=zcމ,l U@8B9cE* x7 \|j\՝qk94pdRRަɩc1V|LeHk+D$Pz]8gmRKl#ჄC(O} @P%t[x cqR  .R<}N1>!ᡖۤGk68CD4>zț#0 }Ҿ*Q{Mɇ(kpjYߺ JSe#cGZ)ޘ N}|YlZqPr7։qX'Yw}ߧVL99g"sM hgחl 6V'"wHZҐƙ+P3J_xu󑟀ݤ LbAV,{oŲD7C\Cjo`&]3Jk~8YGJ TiQ+Vk+ VQr<}vBp3R۫Gv.q(VPInxxy6fDlUDA6isʨo,VܙZ < 2́b~ixfo fq nGVY(*@(uCK3Xb_̛BЏ:w8PV62zQO{--QLMҲMW}T 饈TP.ZU"xs!?>Bj]Lb 2*CKbJȻ%ic+F=ݖ&zZ¿Auİ*(-tB4(7͂blҒ1LyS . .J,kQ`;s& 5/Y_!ީŲ}7綕<Umo9E! p ăhYqq8cU6*Q/0ЁF"~>ɽdZYM+AOJi8@ܞ H_;G.gqy-wA80ͯ<$[:.qּw7Q|cF 1MNr7(%'Z+UMi9X@yM | cҞZT`y)qX&; HJeP cfS*LiAJ(McE`^"gqVY9/ Eji_QZZmJ`Qmq1Q#pknHvΤ~~|n-+f獱hY= lVd;3)Qi)2&"і֕9h&O=.;7"\!b$Ǚ o[%N8CW|\ͷB017 aӭNAL&B/9 'rv[N$Pѳ#:xߜ]D`aԘdqB'qEj `s>q) y:3Ms Ԍ}߇G֍ezq֕}Qr<c&7婟 !|V_Pێ.M텿4–' pfTۀu1"㶡|9, B&^I&n\"k"Íbm;&-#<$e]nz^A`Jk.bޑ_ C@hu,G8F6I:m>JK_^c!ڃU~<">q]B\Aemm"X K{5/\߅[DR[_1D-v |h\Únqnk1tNQmX4{JvhpFㅩ51zD[6P,`EZT˞F4b<[%_^pEdHӏ6/AKfo㌂ ;hwdM^Ͻ5D&AWK+<=YZ(g砺?!TVeVLpd^DCt0Y "5 'eÒy˽B8C_&q_|CTȁd/#9ЄM+`(zpgzk.u/&εu.{0i0_@O]9M.묣,7oS.)z|V| m'(ewl&qJ ʓ6,ݧVc} !*2).[_%0e 8]*TsdO*rG-p' *u< zxXvEA-pObȠO-v|j9QANKuL犗Yt 4򪺞܏~=.ik< )>H,N-l2ځ6{ cm%KJ'8͇1U:2AeiA2W(nCH$oTG"eגInr5h'י$ em宼Yw }2۝yj+]hw">ߞ=ҐE -¨2ӪQͣ or 3h0TԒ~3hy7ۣ ̦Y׷v ]VwU,[Wt@r%( I(%Vkі`'̗O)6VCTw^>Bl S1Ӎ1>2/J۾J,"R|׊J \:49X@  _' jӣA=Fc\⍵+٧A7f|_i/=&1-9:7@>sET뻩X+AUnIyxE-~|AZEP9*BU@Xtcb?MMm7" k/#J4iߏ4ouP Ձ0hw0c1fPįK>ݓCrsow6.61Ks<?_5<:f4K7S0KB3,ZvKc)˙ sȰԙ}زxn-o/ EmDT>iV#~F%e '5-'#2ͅO86TRցJHe螣5滆TOf8σ eY.^F(we\=g<9w{0+} )* ?%x@ x`ZW0LIś}Z9 EbV :S>*HoO-]P\yk3xm) &I8$|̓MH&%s0V[.a*X8nωRbO2ӏq,:R6Pɀ”Gus@"jh+\_V(G1M@lOutP_|4x{ eI.C~+a< iGWWږf(?]G"-k{uawD߮DH@y۠YhI*xdW9Ӈb|q/Fr]ӮHNFS 8~kj-$C/͡E3NmwdC>LK l;9B\zn6X!x827m`" oY@YĂ>jVTlc30"6r+NgElĩ'I8WƩE\? SyI5HZE)0'.ggL2zƝϰ+ljb5yA!S[`j[E;ɐnq/0(aOHGn1='A) ' ʭ<+,|{ࡶ3Kp*[De%_2\0>{uOgu)Myd`22ݷ] -" 5?$ZĺwpEb1 H!$d .WRȍkYA#-gkS3"llR5hrYXrVO = &z'؛NF`l&ݮRBP56Z[ӷje`(;C3Hxgǃ Yr8yy 5 3_4#F܏$* `"O4uЃG#7>Mo`pgqyq22Yb]λUƿ&zbTEyb!Z0ɹVIV M=s|e!?<M TP]UژEode-0.14/contrib/Mac_CFMCarbon/README.txt0000644000000000000000000001101112635011627016350 0ustar rootroot----------------------------- ODE - Mac CFM Carbon Port (contact Frank Condello with questions regarding this port) Although ODE contains a MacOSX makefile, and some individuals have implemented ODE in Cocoa, I opted to use (and prefer) CodeWarrior. This also opens up ODE to MacOS8 & 9 users, without scarfing functionality in MacOSX (same binaries run on both platforms). The 'ode_CW7.mcp' project contains release and debug targets to create static ODE and DrawStuff libraries. 'examples_CW7.mcp' contains targets for the entire ODE test suite, plus a couple other test programs which were posted to the ODE mailing list. ----------------------------- Compiling Notes: You'll need to extract the CodeWarrior projects from the 'CW7_projects.sit.bin' archive (They're nearly a meg uncompressed so this was done to be bandwith friendly on the CVS). Projects require CodeWarrior 7 or above (recreating them with earlier versions shouldn't be too difficult). The projects use relative paths and are meant to be compiled from 'contrib/Mac_CFMCarbon/'. Don't move them! All the libraries build into the 'lib/' directory, all test applications build into 'contrib/Mac_CFMCarbon/mac_testbin/' (and must be run from that directory since the texture path is hard-coded). You'll need to compile the release ODE library, and the DrawStuff library before compiling the examples. The ODE 'configurator' has not been ported, but a Mac-friendly 'config.h' header has been manually hacked together (all PPC Macs should be fine with this header). Single or double precision can be defined in the 'CommonPrefix.h' header found in 'contrib/Mac_CFMCarbon/mac_source/'. 'contrib/Mac_CFMCarbon/mac_source/' also contains any mac specific additions to the main source. The directory structure here matches the main source tree, and I would recommend that this format is maintained when making additions, since the access paths are touchy (more below...) Some issues were encountered with duplicate header names. CodeWarrior tends to be unforgiving about this sort of thing but fudging with the access paths eventually cleared up the problem. If ODE fails to compile, make sure the and "objects.h" or and are actually pointing to the correct header. You'll need Apple's OpenGL SDK (with GLUT) in your compiler path to build DrawStuff. I've added redirection headers in 'contrib/Mac_CFMCarbon/mac_source/include/GL/' to properly link with the Apple headers (since the projects are set to follow DOS paths). The examples link against a crapload of static libraries, but my initial builds using ODE, MSL, GLUT, and DrawStuff shared/merged DLL's proved unstable (mostly problems with SIOUX spawning multiple sessions, and crashes in Classic). Static libs just worked better in the end, but the test apps are a little bloated as a result, and need to be re-linked whenever a change to a library is made. IMPORTANT: You must use the same 'CommonPrefix.h' settings for libraries, and test apps (i.e. double or single precision). ----------------------------- Running the test apps: The test apps will show the SIOUX CLI prompt when run. Just hit OK to ignore it, or add any DrawStuff arguments. You'll want to log output to a file for 'test_ode'. There are two extra test programs in the 'mac_source' directory. Both were posted to the ODE mailing list by OSX users. 'test_stability1' visualizes some internal issues with ODE, and 'test_stacktest' is a standalone GLUT program (doesn't use DrawStuff) that can be useful to stress test the library, and give you an idea of just how much stack memory you're going to need for large systems. ISSUES: The carbon DrawStuff lib uses GLUT to make life easy, but GLUT isn't exactly bug-free or stable on the Mac... Try moving the mouse around if a simulation is running slowly on OS9 (it's not ODE's fault, but rather a poor carbon GLUT implementation - seems GLUT stalls when it's not getting system events - I haven't seen this problem on OSX). The 3D view may not update if typing in the SIOUX console window. You cannot pass startup args to GLUT due to the way the DrawStuff library initializes. 'Write Frames' doesn't actually do anything at the moment. The 'test_joints' app seems broken (though I don't know what the intended effect should be) ----------------------------- TODO: - Re-add shared library targets (if stability issues are resolved). - Implement 'Write Frames' in DrawStuff. - Write a Carbon compatible configurator - Create CodeWarrior 8 projects (once I scrounge up enough dough for the update).ode-0.14/contrib/Mac_CFMCarbon/mac_source/0000775000000000000000000000000012635012023016771 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/CommonPrefix.h0000644000000000000000000000021212635011627021552 0ustar rootroot#define TARGET_API_MAC_CARBON 1 #define finite isfinite #define dNODEBUG 1 // Comment out for single precision #define PRECISION_DOUBLE 1ode-0.14/contrib/Mac_CFMCarbon/mac_source/DSPrefix.h0000644000000000000000000000012012635011627020626 0ustar rootroot#ifndef prefix_h #define prefix_h #include "CommonPrefix.h" #endif // prefix_hode-0.14/contrib/Mac_CFMCarbon/mac_source/DebugPrefix.h0000644000000000000000000000017012635011627021353 0ustar rootroot#ifndef prefix_h #define prefix_h #include "CommonPrefix.h" #ifdef dNODEBUG #undef dNODEBUG #endif #endif // prefix_hode-0.14/contrib/Mac_CFMCarbon/mac_source/ExamplesPrefix.h0000644000000000000000000000054412635011627022110 0ustar rootroot#ifndef prefix_h #define prefix_h #include "CommonPrefix.h" // Hack to automatically call SIOUX's CLI interface for the test apps #include #include int fmain (int argc, char **argv); int main (int argc, char **argv) { argc = ccommand(&argv); return fmain(argc, argv); } #define main(argc, argv) fmain(argc, argv) #endif // prefix_hode-0.14/contrib/Mac_CFMCarbon/mac_source/ODETestPrefix.h0000644000000000000000000000046112635011627021577 0ustar rootroot#ifndef prefix_h #define prefix_h #include "CommonPrefix.h" // Hack to automatically call SIOUX's CLI interface for the test apps #include #include int fmain (); int main (int argc, char **argv) { argc = ccommand(&argv); return fmain(); } #define main() fmain() #endif // prefix_hode-0.14/contrib/Mac_CFMCarbon/mac_source/ReleasePrefix.h0000644000000000000000000000012012635011627021700 0ustar rootroot#ifndef prefix_h #define prefix_h #include "CommonPrefix.h" #endif // prefix_hode-0.14/contrib/Mac_CFMCarbon/mac_source/drawstuff/0000775000000000000000000000000012635012023020776 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/drawstuff/src/0000775000000000000000000000000012635012023021565 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/drawstuff/src/mac_glut_carbon.cpp0000644000000000000000000001634612635011627025431 0ustar rootroot/************************************************************************* * * * DrawStuff Library, Copyright (C) 2001 Russell L. Smith. * * Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library (see the file LICENSE.TXT); if not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307 USA. * * * *************************************************************************/ // main window and event handling for Mac CFM Carbon #include #include #include #include #include #include #include #include #include #include #include #include "internal.h" //*************************************************************************** // error handling for unix (works just fine with SIOUX) static void printMessage (char *msg1, char *msg2, va_list ap) { fflush (stderr); fflush (stdout); fprintf (stderr,"\n%s: ",msg1); vfprintf (stderr,msg2,ap); fprintf (stderr,"\n"); fflush (stderr); } extern "C" void dsError (char *msg, ...) { va_list ap; va_start (ap,msg); printMessage ("Error",msg,ap); va_end (ap); exit (1); } extern "C" void dsDebug (char *msg, ...) { va_list ap; va_start (ap,msg); printMessage ("INTERNAL ERROR",msg,ap); va_end (ap); // *((char *)0) = 0; ... commit SEGVicide ? abort(); } extern "C" void dsPrint (char *msg, ...) { va_list ap; va_start (ap,msg); vprintf (msg,ap); va_end (ap); } //*************************************************************************** // openGL window // window and openGL static int width=0,height=0; // window size static int last_key_pressed=0; // last key pressed in the window static int pause=0; // 1 if in `pause' mode static int singlestep=0; // 1 if single step key pressed static int writeframes=0; // 1 if frame files to be written static dsFunctions *gfn; static int frame = 1; float getTime (void) { UnsignedWide ms; Microseconds(&ms); return ms.lo / 1000000.0; } static void captureFrame (int num) { // TODO } static void reshape(int w, int h) { width = w; height = h; } static void draw(void) { dsDrawFrame (width,height,gfn,pause && !singlestep); singlestep = 0; glutSwapBuffers(); if (pause==0 && writeframes) { captureFrame (frame); frame++; } } static void idle(void) { static float lasttime=0; float t; // Try to maintain a reasonable rate (good enough for testing anyway) t = getTime(); if (lasttime < t) { lasttime = t+0.005; draw(); } } static void key(unsigned char key, int x, int y) { if (!glutGetModifiers()) { if (key >= ' ' && key <= 126 && gfn->command) gfn->command (key); // GLUT_ACTIVE_CTRL doesn't seem to be working, so we use Alt } else if (glutGetModifiers()&GLUT_ACTIVE_ALT) { switch (key) { case 't': case 'T': dsSetTextures (dsGetTextures() ^ 1); break; case 's': case 'S': dsSetShadows (dsGetShadows() ^ 1); break; case 'p': case 'P': pause ^= 1; singlestep = 0; break; case 'o': case 'O': if (pause) singlestep = 1; break; case 'v': case 'V': { float xyz[3],hpr[3]; dsGetViewpoint (xyz,hpr); printf ("Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n", xyz[0],xyz[1],xyz[2],hpr[0],hpr[1],hpr[2]); break; } // No case 'X' - Quit works through the Mac system menu, or cmd-q case 'w': case 'W': writeframes ^= 1; if (writeframes) printf ("Write frames not done yet!\n");// TODO break; } } last_key_pressed = key; } static int mx=0,my=0; // mouse position static int mode = 0; // mouse button bits static void MouseDown(int button, int state, int x, int y) { if(button == GLUT_LEFT_BUTTON) { if(state == GLUT_DOWN) mode |= 1; else if(state == GLUT_UP) mode &= (~1); } else if (button == GLUT_MIDDLE_BUTTON) { if(state == GLUT_DOWN) mode |= 3; else if(state == GLUT_UP) mode &= (~3); } else if (button == GLUT_RIGHT_BUTTON) { if(state == GLUT_DOWN) mode |= 2; else if(state == GLUT_UP) mode &= (~2); } mx = x; my = y; } static void MouseMove(int x, int y) { dsMotion (mode, x - mx, y - my); mx = x; my = y; } static void createMainWindow (int _width, int _height) { // So GLUT doesn't complain int argc = 0; char **argv = NULL; // initialize variables width = _width; height = _height; last_key_pressed = 0; if (width < 1 || height < 1) dsDebug (0,"bad window width or height"); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(_width, _height); glutInitWindowPosition(100, 100); glutCreateWindow("ODE Simulation"); glutKeyboardFunc(key); glutMotionFunc(MouseMove); glutMouseFunc(MouseDown); glutReshapeFunc(reshape); glutDisplayFunc(idle); glutIdleFunc(idle); } void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn, int initial_pause) { SIOUXSettings.initializeTB = false; SIOUXSettings.standalone = false; SIOUXSettings.setupmenus = false; SIOUXSettings.autocloseonquit = true; SIOUXSettings.asktosaveonclose = false; gfn = fn; pause = initial_pause; printf ( "\n" "Simulation test environment v%d.%02d\n" " Option-P : pause / unpause (or say `-pause' on command line).\n" " Option-O : single step when paused.\n" " Option-T : toggle textures (or say `-notex' on command line).\n" " Option-S : toggle shadows (or say `-noshadow' on command line).\n" " Option-V : print current viewpoint coordinates (x,y,z,h,p,r).\n" " Option-W : write frames to ppm files: frame/frameNNN.ppm\n" "\n" "Change the camera position by clicking + dragging in the window.\n" " Left button - pan and tilt.\n" " Right button - forward and sideways.\n" " Left + Right button (or middle button) - sideways and up.\n" "\n",DS_VERSION >> 8,DS_VERSION & 0xff); createMainWindow (window_width, window_height); dsStartGraphics (window_width,window_height,fn); if (fn->start) fn->start(); glutMainLoop(); if (fn->stop) fn->stop(); dsStopGraphics(); } extern "C" void dsStop(){ }// GLUT/MSL hooks into the system to exit ode-0.14/contrib/Mac_CFMCarbon/mac_source/include/0000775000000000000000000000000012635012023020414 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/include/GL/0000775000000000000000000000000012635012023020716 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/include/GL/gl.h0000644000000000000000000000016112635011627021476 0ustar rootroot// A little hackaround (Apple use / in the FILENAME, which doesn't work when following DOS paths) #include ode-0.14/contrib/Mac_CFMCarbon/mac_source/include/GL/glu.h0000644000000000000000000000016212635011627021664 0ustar rootroot// A little hackaround (Apple use / in the FILENAME, which doesn't work when following DOS paths) #include ode-0.14/contrib/Mac_CFMCarbon/mac_source/include/ode/0000775000000000000000000000000012635012023021163 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/include/ode/config.h0000644000000000000000000000173712635011627022620 0ustar rootroot/* This file has been manually hacked together for the Mac CFM Carbon build - Frank. */ #ifndef _ODE_CONFIG_H_ #define _ODE_CONFIG_H_ /* standard system headers */ #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* #define PENTIUM 1 -- not a pentium */ /* integer types (we assume int >= 32 bits) */ typedef char int8; typedef unsigned char uint8; typedef int int32; typedef unsigned int uint32; /* an integer type that we can safely cast a pointer to and from without loss of bits. */ typedef unsigned int intP; #ifdef PRECISION_DOUBLE /*select the base floating point type*/ #define dDOUBLE 1 /* the floating point infinity */ #define dInfinity DBL_MAX #else /* select the base floating point type */ #define dSINGLE 1 /* the floating point infinity */ #define dInfinity FLT_MAX #endif #ifdef __cplusplus } #endif #endifode-0.14/contrib/Mac_CFMCarbon/mac_source/ode/0000775000000000000000000000000012635012023017540 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/ode/test/0000775000000000000000000000000012635012023020517 5ustar rootrootode-0.14/contrib/Mac_CFMCarbon/mac_source/ode/test/test_stability1.cpp0000644000000000000000000002047012635011627024361 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCappedCylinder dsDrawCappedCylinderD #endif // some constants #define DENSITY (5.0) // density of all objects // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom; // geometry representing this body }; static dWorldID world; static dSpaceID space; static MyObject fallingObject; static dGeomID box1, box2; static dJointGroupID contactgroup; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnected (b1,b2)) return; dContact contact[4]; // up to 3 contacts per box for (i=0; i<4; i++) { contact[i].surface.mode = dContactBounce; //dContactMu2; contact[i].surface.mu = dInfinity; contact[i].surface.mu2 = 0; contact[i].surface.bounce = 0.5; contact[i].surface.bounce_vel = 0.1; } if (int numc = dCollide (o1,o2,4,&contact[0].geom,sizeof(dContact))) { // dMatrix3 RI; // dRSetIdentity (RI); // const dReal ss[3] = {0.02,0.02,0.02}; for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command (int cmd) { int i,k; dReal sides[3]; dMass m; cmd = locase (cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c') { // Destroy the currently falling object and replace it by an instance of the requested type if (fallingObject.body) { dBodyDestroy (fallingObject.body); dGeomDestroy (fallingObject.geom); memset (&fallingObject, 0, sizeof(fallingObject)); } fallingObject.body = dBodyCreate (world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; // Start out centered above the V-gap dBodySetPosition (fallingObject.body, 0,0,5); #if 0 dMatrix3 R; dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); dBodySetRotation (fallingObject.body,R); dBodySetData (fallingObject.body,(void*) i); #endif if (cmd == 'b') { dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]); fallingObject.geom = dCreateBox (space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCappedCylinder (&m,DENSITY,3,sides[0],sides[1]); fallingObject.geom = dCreateCCylinder (space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); fallingObject.geom = dCreateSphere (space,sides[0]); } dGeomSetBody (fallingObject.geom,fallingObject.body); dBodySetMass (fallingObject.body,&m); } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R) { if (!g) return; if (!pos) pos = dGeomGetPosition (g); if (!R) R = dGeomGetRotation (g); int type = dGeomGetClass (g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths (g,sides); dsDrawBox (pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere (pos,R,dGeomSphereGetRadius (g)); } else if (type == dCCylinderClass) { dReal radius,length; dGeomCCylinderGetParams (g,&radius,&length); dsDrawCappedCylinder (pos,R,length,radius); } /* else if (type == dGeomTransformClass) { dGeomID g2 = dGeomTransformGetGeom (g); const dReal *pos2 = dGeomGetPosition (g2); const dReal *R2 = dGeomGetRotation (g2); dVector3 actual_pos; dMatrix3 actual_R; dMULTIPLY0_331 (actual_pos,R,pos2); actual_pos[0] += pos[0]; actual_pos[1] += pos[1]; actual_pos[2] += pos[2]; dMULTIPLY0_333 (actual_R,R,R2); drawGeom (g2,actual_pos,actual_R); } */ } // simulation loop static void simLoop (int pause) { dsSetColor (0,0,2); dSpaceCollide (space,0,&nearCallback); if (!pause) dWorldStep (world,0.0005); // remove all contact joints dJointGroupEmpty (contactgroup); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); // draw the falling object dsSetColor (1,0,0); drawGeom (fallingObject.geom,0,0); // draw the constraining boxes dsSetColor(0.8, 1, 0.8); drawGeom (box1,0,0); drawGeom (box2,0,0); } int main (int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = "../../drawstuff/textures"; if(argc==2) { fn.path_to_textures = argv[1]; } // create world world = dWorldCreate(); space = dHashSpaceCreate(); contactgroup = dJointGroupCreate (0); dWorldSetGravity (world,0,0,-0.5); dWorldSetCFM (world,1e-5); dCreatePlane (space,0,0,1,0); memset (&fallingObject,0,sizeof(fallingObject)); // Create two flat boxes, just slightly off vertical and a bit apart for stuff to fall in between. // Don't create bodies for these boxes -- they'll be immovable instead. { dReal sides[3]; dMatrix3 R; sides[0] = 4; sides[1] = 0.2; sides[2] = 3; box1 = dCreateBox (space,sides[0],sides[1],sides[2]); dGeomSetPosition (box1, 0, sides[1], sides[2]/2); dRFromAxisAndAngle (R, 1, 0, 0, -0.1); dGeomSetRotation (box1, R); box2 = dCreateBox (space,sides[0],sides[1],sides[2]); dGeomSetPosition (box2, 0, -sides[1], sides[2]/2); dRFromAxisAndAngle (R, 1, 0, 0, 0.1); dGeomSetRotation (box2, R); } // Pretend to drop a box to start command('b'); // run simulation dsSimulationLoop (argc,argv,640,480,&fn); dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); return 0; } ode-0.14/contrib/Mac_CFMCarbon/mac_source/ode/test/test_stacktest.c0000644000000000000000000001145112635011627023740 0ustar rootroot#include #include #include "ode.h" #define NUMBODIES 80 #define USE_SPHERE 0 #define USE_HELIX 1 #define USE_TORQUE 1 #define USE_WEIRD_MATRIX_OPS 0 #define CONTACTS 1 dWorldID aWorld; dSpaceID aSpace; float cycle = 0, fade; dJointGroupID aContactGroup; dBodyID bodies[NUMBODIES]; dGeomID geoms[NUMBODIES]; GLfloat colors[NUMBODIES][4]; unsigned int contactsThisFrame; void kglTransformByODEGeom(dGeomID geom) { const dReal *p = dGeomGetPosition(geom); const dReal *R = dGeomGetRotation(geom); GLdouble glm[16]; glm[0] = R[0]; glm[1] = R[4]; glm[2] = R[8]; glm[3] = 0; glm[4] = R[1]; glm[5] = R[5]; glm[6] = R[9]; glm[7] = 0; glm[8] = R[2]; glm[9] = R[6]; glm[10] = R[10];glm[11] = 0; glm[12] = p[0]; glm[13] = p[1]; glm[14] = p[2]; glm[15] = 1; glMultMatrixd(glm); } static void odeNearCallback(void *data, dGeomID g1, dGeomID g2) { dBodyID b1 = dGeomGetBody(g1), b2 = dGeomGetBody(g2); dContact contact[CONTACTS]; int contactsUsed, i; if (b1 && b2 && dAreConnected(b1, b2)) return; contactsUsed = dCollide(g1, g2, CONTACTS, &contact[0].geom, sizeof(dContact)); if (contactsUsed > CONTACTS) contactsUsed = CONTACTS; for (i = 0; i < contactsUsed; i++) { contact[i].surface.mode = 0; contact[i].surface.mu = 20.0; dJointAttach(dJointCreateContact(aWorld, aContactGroup, &(contact[i])), b1, b2); contactsThisFrame++; } } void myGlutResize(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (GLfloat)w / h, 1.0, 120.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, -6, -20); } void myGlutIdle(void) { const float step = 1.0/120; int i; cycle = fmod(cycle + step / 4, 1); fade = fabs(cycle * 2 - 1); contactsThisFrame = 0; dSpaceCollide(aSpace, NULL, &odeNearCallback); //printf("%u\n", contactsThisFrame); dWorldStep(aWorld, step); dJointGroupEmpty(aContactGroup); for (i = 0; i < NUMBODIES; i++) { const dReal *cvel = dBodyGetLinearVel(bodies[i]); dBodyAddForce(bodies[i], -cvel[0] * 0.5, -cvel[1] * 0.5, -cvel[2] * 0.5 ); } glutPostRedisplay(); } void myGlutDisplay(void) { int i; glClearColor(fade * 0.15, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (USE_WEIRD_MATRIX_OPS) glPushMatrix(); for (i = 0; i < NUMBODIES; i++) { if (!USE_WEIRD_MATRIX_OPS) glPushMatrix(); kglTransformByODEGeom(geoms[i]); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, colors[i]); glColor3f(fade * 1.5, 0, 0); #if USE_SPHERE glRotatef(90, 1, 0, 0); glutSolidSphere(0.5, 9, 6); glDisable(GL_LIGHTING); glutWireSphere(0.5, 9, 6); #else glutSolidCube(1); glDisable(GL_LIGHTING); glutWireCube(1); #endif glEnable(GL_LIGHTING); if (!USE_WEIRD_MATRIX_OPS) glPopMatrix(); } if (USE_WEIRD_MATRIX_OPS) glPopMatrix(); glutSwapBuffers(); } int main(int argc, char **argv) { printf("Initializing GLUT\n"); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(400, 300); glutInitWindowPosition(100, 100); glutCreateWindow("ODE Crash Test"); glutDisplayFunc(myGlutDisplay); glutReshapeFunc(myGlutResize); glutIdleFunc(myGlutIdle); glPolygonOffset(1, 1); glDepthFunc(GL_LEQUAL); glEnable(GL_POLYGON_OFFSET_FILL); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); myGlutResize(400, 300); printf("Creating ODE world\n"); aWorld = dWorldCreate(); aSpace = dHashSpaceCreate(); aContactGroup = dJointGroupCreate(0); dCreatePlane(aSpace, 0, 1, 0, 0); dWorldSetGravity(aWorld, 0, -9.81, 0); dWorldSetERP(aWorld, 0.4); dWorldSetCFM(aWorld, 1e-10); printf("Creating objects\n"); { int i; dMass mass; dMassSetBox(&mass, 1.0, 1, 1, 1); for (i = 0; i < NUMBODIES; i++) { float fraction = (float)i / NUMBODIES; bodies[i] = dBodyCreate(aWorld); dBodySetMass(bodies[i], &mass); #if USE_SPHERE geoms[i] = dCreateSphere(aSpace, 0.5); #else geoms[i] = dCreateBox(aSpace, 1, 1, 1); #endif dGeomSetBody(geoms[i], bodies[i]); if (USE_HELIX) { float r = (i % 3 - 1) * (1.5+4*(1 - fraction)), theta = (float)i / 4; dBodySetPosition(bodies[i], sin(theta) * r, (float)i + 1, cos(theta) * r ); } else { dBodySetPosition(bodies[i], 0, (float)i * 2 + 1, 0); } if (USE_TORQUE) dBodyAddTorque(bodies[i], fraction*10, fraction*20, fraction*30); colors[i][0] = fraction; colors[i][1] = 1 - fraction; colors[i][2] = 1 - fabs(fraction * 2 - 1); colors[i][3] = 1; } } printf("Starting simulation\n"); glutMainLoop(); return 0; }ode-0.14/contrib/Ode.NET/0000775000000000000000000000000012635012023013473 5ustar rootrootode-0.14/contrib/Ode.NET/Drawstuff/0000775000000000000000000000000012635012023015440 5ustar rootrootode-0.14/contrib/Ode.NET/Drawstuff/AssemblyInfo.cs0000644000000000000000000000117312635011627020373 0ustar rootrootusing System; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("Drawstuff.NET")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Ode.NET")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("b2a39dd4-dd67-4e8a-af70-d3b412da8850")] [assembly: AssemblyVersion("0.7.0.0")] [assembly: AssemblyFileVersion("0.7.0.0")] [assembly: CLSCompliantAttribute(true)] ode-0.14/contrib/Ode.NET/Drawstuff/Drawstuff.cs0000644000000000000000000000341512635011627017746 0ustar rootrootusing System; using System.Runtime.InteropServices; using Ode.NET; namespace Drawstuff.NET { #if dDOUBLE using dReal = System.Double; #else using dReal = System.Single; #endif public static class ds { public const int VERSION = 2; public enum Texture { None, Wood } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void CallbackFunction(int arg); [StructLayout(LayoutKind.Sequential)] public struct Functions { public int version; public CallbackFunction start; public CallbackFunction step; public CallbackFunction command; public CallbackFunction stop; public string path_to_textures; } [DllImport("drawstuff", EntryPoint="dsDrawBox")] public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides); [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")] public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius); [DllImport("drawstuff", EntryPoint = "dsDrawConvex")] public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); [DllImport("drawstuff", EntryPoint="dsSetColor")] public static extern void SetColor(float red, float green, float blue); [DllImport("drawstuff", EntryPoint="dsSetTexture")] public static extern void SetTexture(Texture texture); [DllImport("drawstuff", EntryPoint="dsSetViewpoint")] public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr); [DllImport("drawstuff", EntryPoint="dsSimulationLoop")] public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn); } } ode-0.14/contrib/Ode.NET/Drawstuff/premake.lua0000644000000000000000000000047012635011627017577 0ustar rootrootpackage.name = "Drawstuff.NET" package.kind = "dll" package.language = "c#" if (options["with-doubles"]) then package.defines = { "dDOUBLE" } else package.defines = { "dSINGLE " } end package.links = { "System", "Ode.NET" } package.files = { "AssemblyInfo.cs", "Drawstuff.cs" } ode-0.14/contrib/Ode.NET/Ode/0000775000000000000000000000000012635012023014202 5ustar rootrootode-0.14/contrib/Ode.NET/Ode/AssemblyInfo.cs0000644000000000000000000000114512635011627017134 0ustar rootrootusing System; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("Ode.NET")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Ode.NET")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("1347a35e-c32b-4ff6-8064-7d10b2cc113b")] [assembly: AssemblyVersion("0.10.1.0")] [assembly: AssemblyFileVersion("0.10.1.0")] [assembly: CLSCompliantAttribute(true)] ode-0.14/contrib/Ode.NET/Ode/Ode.cs0000644000000000000000000026103112635011627015252 0ustar rootrootusing System; using System.Runtime.InteropServices; using System.Security; namespace Ode.NET { #if dDOUBLE using dReal = System.Double; #else using dReal = System.Single; #endif public static class d { public static dReal Infinity = dReal.MaxValue; #region Flags and Enumerations #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [Flags] public enum AllocateODEDataFlags : uint { BasicData = 0, CollisionData = 0x00000001, All = ~0u } [CLSCompliant(false)] [Flags] public enum IniteODEFlags : uint { dInitFlagManualThreadCleanup = 0x00000001 } #endif [Flags] public enum ContactFlags : int { Mu2 = 0x001, FDir1 = 0x002, Bounce = 0x004, SoftERP = 0x008, SoftCFM = 0x010, Motion1 = 0x020, Motion2 = 0x040, MotionN = 0x080, Slip1 = 0x100, Slip2 = 0x200, Approx0 = 0x0000, Approx1_1 = 0x1000, Approx1_2 = 0x2000, Approx1 = 0x3000 } public enum GeomClassID : int { SphereClass, BoxClass, CapsuleClass, CylinderClass, PlaneClass, RayClass, ConvexClass, GeomTransformClass, TriMeshClass, HeightfieldClass, FirstSpaceClass, SimpleSpaceClass = FirstSpaceClass, HashSpaceClass, QuadTreeSpaceClass, LastSpaceClass = QuadTreeSpaceClass, FirstUserClass, LastUserClass = FirstUserClass + MaxUserClasses - 1, NumClasses, MaxUserClasses = 4 } public enum JointType : int { None, Ball, Hinge, Slider, Contact, Universal, Hinge2, Fixed, Null, AMotor, LMotor, Plane2D } public enum JointParam : int { LoStop, HiStop, Vel, FMax, FudgeFactor, Bounce, CFM, StopERP, StopCFM, SuspensionERP, SuspensionCFM, LoStop2 = 256, HiStop2, Vel2, FMax2, FudgeFactor2, Bounce2, CFM2, StopERP2, StopCFM2, SuspensionERP2, SuspensionCFM2, LoStop3 = 512, HiStop3, Vel3, FMax3, FudgeFactor3, Bounce3, CFM3, StopERP3, StopCFM3, SuspensionERP3, SuspensionCFM3 } public enum dSweepAndPruneAxis : int { XYZ = ((0)|(1<<2)|(2<<4)), XZY = ((0)|(2<<2)|(1<<4)), YXZ = ((1)|(0<<2)|(2<<4)), YZX = ((1)|(2<<2)|(0<<4)), ZXY = ((2)|(0<<2)|(1<<4)), ZYX = ((2)|(1<<2)|(0<<4)) } #endregion #region Callbacks [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int AABBTestFn(IntPtr o1, IntPtr o2, ref AABB aabb); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int ColliderFn(IntPtr o1, IntPtr o2, int flags, out ContactGeom contact, int skip); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void GetAABBFn(IntPtr geom, out AABB aabb); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate ColliderFn GetColliderFnFn(int num); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void GeomDtorFn(IntPtr o); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate dReal HeightfieldGetHeight(IntPtr p_user_data, int x, int z); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void NearCallback(IntPtr data, IntPtr geom1, IntPtr geom2); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int TriRayCallback(IntPtr trimesh, IntPtr ray, int triangleIndex, dReal u, dReal v); #endregion #region Structs [StructLayout(LayoutKind.Sequential)] public struct AABB { public dReal MinX, MaxX; public dReal MinY, MaxY; public dReal MinZ, MaxZ; } [StructLayout(LayoutKind.Sequential)] public struct Contact { public SurfaceParameters surface; public ContactGeom geom; public Vector3 fdir1; } [StructLayout(LayoutKind.Sequential)] public struct ContactGeom { public static readonly int SizeOf = Marshal.SizeOf(typeof(ContactGeom)); public Vector3 pos; public Vector3 normal; public dReal depth; public IntPtr g1; public IntPtr g2; public int side1; public int side2; } [StructLayout(LayoutKind.Sequential)] public struct GeomClass { public int bytes; public GetColliderFnFn collider; public GetAABBFn aabb; public AABBTestFn aabb_test; public GeomDtorFn dtor; } [StructLayout(LayoutKind.Sequential)] public struct JointFeedback { public Vector3 f1; public Vector3 t1; public Vector3 f2; public Vector3 t2; } [StructLayout(LayoutKind.Sequential)] public struct Mass { public dReal mass; public Vector4 c; public Matrix3 I; } [StructLayout(LayoutKind.Sequential)] public struct Matrix3 { public Matrix3(dReal m00, dReal m10, dReal m20, dReal m01, dReal m11, dReal m21, dReal m02, dReal m12, dReal m22) { M00 = m00; M10 = m10; M20 = m20; _m30 = 0.0f; M01 = m01; M11 = m11; M21 = m21; _m31 = 0.0f; M02 = m02; M12 = m12; M22 = m22; _m32 = 0.0f; } public dReal M00, M10, M20; private dReal _m30; public dReal M01, M11, M21; private dReal _m31; public dReal M02, M12, M22; private dReal _m32; } [StructLayout(LayoutKind.Sequential)] public struct Matrix4 { public Matrix4(dReal m00, dReal m10, dReal m20, dReal m30, dReal m01, dReal m11, dReal m21, dReal m31, dReal m02, dReal m12, dReal m22, dReal m32, dReal m03, dReal m13, dReal m23, dReal m33) { M00 = m00; M10 = m10; M20 = m20; M30 = m30; M01 = m01; M11 = m11; M21 = m21; M31 = m31; M02 = m02; M12 = m12; M22 = m22; M32 = m32; M03 = m03; M13 = m13; M23 = m23; M33 = m33; } public dReal M00, M10, M20, M30; public dReal M01, M11, M21, M31; public dReal M02, M12, M22, M32; public dReal M03, M13, M23, M33; } [StructLayout(LayoutKind.Sequential)] public struct Quaternion { public dReal W, X, Y, Z; } [StructLayout(LayoutKind.Sequential)] public struct SurfaceParameters { public ContactFlags mode; public dReal mu; public dReal mu2; public dReal bounce; public dReal bounce_vel; public dReal soft_erp; public dReal soft_cfm; public dReal motion1; public dReal motion2; public dReal motionN; public dReal slip1; public dReal slip2; } [StructLayout(LayoutKind.Sequential)] public struct Vector3 { public Vector3(dReal x, dReal y, dReal z) { X = x; Y = y; Z = z; _w = 0.0f; } public dReal X, Y, Z; private dReal _w; } [StructLayout(LayoutKind.Sequential)] public struct Vector4 { public Vector4(dReal x, dReal y, dReal z, dReal w) { X = x; Y = y; Z = z; W = w; } public dReal X, Y, Z, W; } #endregion #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dAllocateODEDataForThread"), SuppressUnmanagedCodeSecurity] public static extern int AllocateODEDataForThread(uint ODEInitFlags); #endif [DllImport("ode", EntryPoint = "dAreConnected"), SuppressUnmanagedCodeSecurity] public static extern bool AreConnected(IntPtr b1, IntPtr b2); [DllImport("ode", EntryPoint = "dAreConnectedExcluding"), SuppressUnmanagedCodeSecurity] public static extern bool AreConnectedExcluding(IntPtr b1, IntPtr b2, JointType joint_type); [DllImport("ode", EntryPoint = "dBodyAddForce"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddForce(IntPtr body, dReal fx, dReal fy, dReal fz); [DllImport("ode", EntryPoint = "dBodyAddForceAtPos"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddForceAtPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); [DllImport("ode", EntryPoint = "dBodyAddForceAtRelPos"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddForceAtRelPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); [DllImport("ode", EntryPoint = "dBodyAddRelForce"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddRelForce(IntPtr body, dReal fx, dReal fy, dReal fz); [DllImport("ode", EntryPoint = "dBodyAddRelForceAtPos"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddRelForceAtPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); [DllImport("ode", EntryPoint = "dBodyAddRelForceAtRelPos"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddRelForceAtRelPos(IntPtr body, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); [DllImport("ode", EntryPoint = "dBodyAddRelTorque"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddRelTorque(IntPtr body, dReal fx, dReal fy, dReal fz); [DllImport("ode", EntryPoint = "dBodyAddTorque"), SuppressUnmanagedCodeSecurity] public static extern void BodyAddTorque(IntPtr body, dReal fx, dReal fy, dReal fz); [DllImport("ode", EntryPoint = "dBodyCopyPosition"), SuppressUnmanagedCodeSecurity] public static extern void BodyCopyPosition(IntPtr body, out Vector3 pos); [DllImport("ode", EntryPoint = "dBodyCopyPosition"), SuppressUnmanagedCodeSecurity] public static extern void BodyCopyPosition(IntPtr body, out dReal X); [DllImport("ode", EntryPoint = "dBodyCopyQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void BodyCopyQuaternion(IntPtr body, out Quaternion quat); [DllImport("ode", EntryPoint = "dBodyCopyQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void BodyCopyQuaternion(IntPtr body, out dReal X); [DllImport("ode", EntryPoint = "dBodyCopyRotation"), SuppressUnmanagedCodeSecurity] public static extern void BodyCopyRotation(IntPtr body, out Matrix3 R); [DllImport("ode", EntryPoint = "dBodyCopyRotation"), SuppressUnmanagedCodeSecurity] public static extern void BodyCopyRotation(IntPtr body, out dReal M00); [DllImport("ode", EntryPoint = "dBodyCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr BodyCreate(IntPtr world); [DllImport("ode", EntryPoint = "dBodyDestroy"), SuppressUnmanagedCodeSecurity] public static extern void BodyDestroy(IntPtr body); [DllImport("ode", EntryPoint = "dBodyDisable"), SuppressUnmanagedCodeSecurity] public static extern void BodyDisable(IntPtr body); [DllImport("ode", EntryPoint = "dBodyEnable"), SuppressUnmanagedCodeSecurity] public static extern void BodyEnable(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal BodyGetAutoDisableAngularThreshold(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] public static extern bool BodyGetAutoDisableFlag(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAutoDisableDefaults"), SuppressUnmanagedCodeSecurity] public static extern void BodyGetAutoDisableDefaults(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal BodyGetAutoDisableLinearThreshold(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] public static extern int BodyGetAutoDisableSteps(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAutoDisableTime"), SuppressUnmanagedCodeSecurity] public static extern dReal BodyGetAutoDisableTime(IntPtr body); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dBodyGetAngularVel"), SuppressUnmanagedCodeSecurity] public extern unsafe static Vector3* BodyGetAngularVelUnsafe(IntPtr body); public static Vector3 BodyGetAngularVel(IntPtr body) { unsafe { return *(BodyGetAngularVelUnsafe(body)); } } #endif [DllImport("ode", EntryPoint = "dBodyGetData"), SuppressUnmanagedCodeSecurity] public static extern IntPtr BodyGetData(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetFiniteRotationMode"), SuppressUnmanagedCodeSecurity] public static extern int BodyGetFiniteRotationMode(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetFiniteRotationAxis"), SuppressUnmanagedCodeSecurity] public static extern void BodyGetFiniteRotationAxis(IntPtr body, out Vector3 result); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dBodyGetForce"), SuppressUnmanagedCodeSecurity] public extern unsafe static Vector3* BodyGetForceUnsafe(IntPtr body); public static Vector3 BodyGetForce(IntPtr body) { unsafe { return *(BodyGetForceUnsafe(body)); } } #endif [DllImport("ode", EntryPoint = "dBodyGetGravityMode"), SuppressUnmanagedCodeSecurity] public static extern bool BodyGetGravityMode(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetGyroscopicMode"), SuppressUnmanagedCodeSecurity] public static extern int BodyGetGyroscopicMode(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetJoint"), SuppressUnmanagedCodeSecurity] public static extern IntPtr BodyGetJoint(IntPtr body, int index); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dBodyGetLinearVel"), SuppressUnmanagedCodeSecurity] public extern unsafe static Vector3* BodyGetLinearVelUnsafe(IntPtr body); public static Vector3 BodyGetLinearVel(IntPtr body) { unsafe { return *(BodyGetLinearVelUnsafe(body)); } } #endif [DllImport("ode", EntryPoint = "dBodyGetMass"), SuppressUnmanagedCodeSecurity] public static extern void BodyGetMass(IntPtr body, out Mass mass); [DllImport("ode", EntryPoint = "dBodyGetNumJoints"), SuppressUnmanagedCodeSecurity] public static extern int BodyGetNumJoints(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetPointVel"), SuppressUnmanagedCodeSecurity] public static extern void BodyGetPointVel(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dBodyGetPosition"), SuppressUnmanagedCodeSecurity] public extern unsafe static Vector3* BodyGetPositionUnsafe(IntPtr body); public static Vector3 BodyGetPosition(IntPtr body) { unsafe { return *(BodyGetPositionUnsafe(body)); } } #endif [DllImport("ode", EntryPoint = "dBodyGetPosRelPoint"), SuppressUnmanagedCodeSecurity] public static extern void BodyGetPosRelPoint(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dBodyGetQuaternion"), SuppressUnmanagedCodeSecurity] public extern unsafe static Quaternion* BodyGetQuaternionUnsafe(IntPtr body); public static Quaternion BodyGetQuaternion(IntPtr body) { unsafe { return *(BodyGetQuaternionUnsafe(body)); } } #endif [DllImport("ode", EntryPoint = "dBodyGetRelPointPos"), SuppressUnmanagedCodeSecurity] public static extern void BodyGetRelPointPos(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); [DllImport("ode", EntryPoint = "dBodyGetRelPointVel"), SuppressUnmanagedCodeSecurity] public static extern void BodyGetRelPointVel(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dBodyGetRotation"), SuppressUnmanagedCodeSecurity] public extern unsafe static Matrix3* BodyGetRotationUnsafe(IntPtr body); public static Matrix3 BodyGetRotation(IntPtr body) { unsafe { return *(BodyGetRotationUnsafe(body)); } } #endif #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dBodyGetTorque"), SuppressUnmanagedCodeSecurity] public extern unsafe static Vector3* BodyGetTorqueUnsafe(IntPtr body); public static Vector3 BodyGetTorque(IntPtr body) { unsafe { return *(BodyGetTorqueUnsafe(body)); } } #endif [DllImport("ode", EntryPoint = "dBodyGetWorld"), SuppressUnmanagedCodeSecurity] public static extern IntPtr BodyGetWorld(IntPtr body); [DllImport("ode", EntryPoint = "dBodyIsEnabled"), SuppressUnmanagedCodeSecurity] public static extern bool BodyIsEnabled(IntPtr body); [DllImport("ode", EntryPoint = "dBodySetAngularVel"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAngularVel(IntPtr body, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dBodySetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAutoDisableAngularThreshold(IntPtr body, dReal angular_threshold); [DllImport("ode", EntryPoint = "dBodySetAutoDisableDefaults"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAutoDisableDefaults(IntPtr body); [DllImport("ode", EntryPoint = "dBodySetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAutoDisableFlag(IntPtr body, bool do_auto_disable); [DllImport("ode", EntryPoint = "dBodySetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAutoDisableLinearThreshold(IntPtr body, dReal linear_threshold); [DllImport("ode", EntryPoint = "dBodySetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAutoDisableSteps(IntPtr body, int steps); [DllImport("ode", EntryPoint = "dBodySetAutoDisableTime"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAutoDisableTime(IntPtr body, dReal time); [DllImport("ode", EntryPoint = "dBodySetData"), SuppressUnmanagedCodeSecurity] public static extern void BodySetData(IntPtr body, IntPtr data); [DllImport("ode", EntryPoint = "dBodySetFiniteRotationMode"), SuppressUnmanagedCodeSecurity] public static extern void BodySetFiniteRotationMode(IntPtr body, int mode); [DllImport("ode", EntryPoint = "dBodySetFiniteRotationAxis"), SuppressUnmanagedCodeSecurity] public static extern void BodySetFiniteRotationAxis(IntPtr body, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dBodySetLinearDamping"), SuppressUnmanagedCodeSecurity] public static extern void BodySetLinearDamping(IntPtr body, dReal scale); [DllImport("ode", EntryPoint = "dBodySetAngularDamping"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAngularDamping(IntPtr body, dReal scale); [DllImport("ode", EntryPoint = "dBodyGetLinearDamping"), SuppressUnmanagedCodeSecurity] public static extern dReal BodyGetLinearDamping(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAngularDamping"), SuppressUnmanagedCodeSecurity] public static extern dReal BodyGetAngularDamping(IntPtr body); [DllImport("ode", EntryPoint = "dBodySetAngularDamping"), SuppressUnmanagedCodeSecurity] public static extern void BodySetDamping(IntPtr body, dReal linear_scale, dReal angular_scale); [DllImport("ode", EntryPoint = "dBodySetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern void BodySetAngularDampingThreshold(IntPtr body, dReal threshold); [DllImport("ode", EntryPoint = "dBodySetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern void BodySetLinearDampingThreshold(IntPtr body, dReal threshold); [DllImport("ode", EntryPoint = "dBodyGetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal BodyGetLinearDampingThreshold(IntPtr body); [DllImport("ode", EntryPoint = "dBodyGetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal BodyGetAngularDampingThreshold(IntPtr body); [DllImport("ode", EntryPoint = "dBodySetForce"), SuppressUnmanagedCodeSecurity] public static extern void BodySetForce(IntPtr body, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dBodySetGravityMode"), SuppressUnmanagedCodeSecurity] public static extern void BodySetGravityMode(IntPtr body, bool mode); /// /// Sets the Gyroscopic term status on the body specified. /// /// Pointer to body /// NonZero enabled, Zero disabled [DllImport("ode", EntryPoint = "dBodySetGyroscopicMode"), SuppressUnmanagedCodeSecurity] public static extern void dBodySetGyroscopicMode(IntPtr body, int enabled); [DllImport("ode", EntryPoint = "dBodySetLinearVel"), SuppressUnmanagedCodeSecurity] public static extern void BodySetLinearVel(IntPtr body, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dBodySetMass"), SuppressUnmanagedCodeSecurity] public static extern void BodySetMass(IntPtr body, ref Mass mass); [DllImport("ode", EntryPoint = "dBodySetPosition"), SuppressUnmanagedCodeSecurity] public static extern void BodySetPosition(IntPtr body, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dBodySetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void BodySetQuaternion(IntPtr body, ref Quaternion q); [DllImport("ode", EntryPoint = "dBodySetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void BodySetQuaternion(IntPtr body, ref dReal w); [DllImport("ode", EntryPoint = "dBodySetRotation"), SuppressUnmanagedCodeSecurity] public static extern void BodySetRotation(IntPtr body, ref Matrix3 R); [DllImport("ode", EntryPoint = "dBodySetRotation"), SuppressUnmanagedCodeSecurity] public static extern void BodySetRotation(IntPtr body, ref dReal M00); [DllImport("ode", EntryPoint = "dBodySetTorque"), SuppressUnmanagedCodeSecurity] public static extern void BodySetTorque(IntPtr body, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dBodyVectorFromWorld"), SuppressUnmanagedCodeSecurity] public static extern void BodyVectorFromWorld(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); [DllImport("ode", EntryPoint = "dBodyVectorToWorld"), SuppressUnmanagedCodeSecurity] public static extern void BodyVectorToWorld(IntPtr body, dReal px, dReal py, dReal pz, out Vector3 result); [DllImport("ode", EntryPoint = "dBoxBox"), SuppressUnmanagedCodeSecurity] public static extern void BoxBox(ref Vector3 p1, ref Matrix3 R1, ref Vector3 side1, ref Vector3 p2, ref Matrix3 R2, ref Vector3 side2, ref Vector3 normal, out dReal depth, out int return_code, int maxc, out ContactGeom contact, int skip); [DllImport("ode", EntryPoint = "dBoxTouchesBox"), SuppressUnmanagedCodeSecurity] public static extern void BoxTouchesBox(ref Vector3 _p1, ref Matrix3 R1, ref Vector3 side1, ref Vector3 _p2, ref Matrix3 R2, ref Vector3 side2); [DllImport("ode", EntryPoint = "dCleanupODEAllDataForThread"), SuppressUnmanagedCodeSecurity] public static extern void CleanupODEAllDataForThread(); [DllImport("ode", EntryPoint = "dClosestLineSegmentPoints"), SuppressUnmanagedCodeSecurity] public static extern void ClosestLineSegmentPoints(ref Vector3 a1, ref Vector3 a2, ref Vector3 b1, ref Vector3 b2, ref Vector3 cp1, ref Vector3 cp2); [DllImport("ode", EntryPoint = "dCloseODE"), SuppressUnmanagedCodeSecurity] public static extern void CloseODE(); [DllImport("ode", EntryPoint = "dCollide"), SuppressUnmanagedCodeSecurity] public static extern int Collide(IntPtr o1, IntPtr o2, int flags, [In, Out] ContactGeom[] contact, int skip); [DllImport("ode", EntryPoint = "dConnectingJoint"), SuppressUnmanagedCodeSecurity] public static extern IntPtr ConnectingJoint(IntPtr j1, IntPtr j2); [DllImport("ode", EntryPoint = "dCreateBox"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateBox(IntPtr space, dReal lx, dReal ly, dReal lz); [DllImport("ode", EntryPoint = "dCreateCapsule"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateCapsule(IntPtr space, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dCreateConvex"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateConvex(IntPtr space, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); [DllImport("ode", EntryPoint = "dCreateCylinder"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateCylinder(IntPtr space, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dCreateHeightfield"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateHeightfield(IntPtr space, IntPtr data, int bPlaceable); [DllImport("ode", EntryPoint = "dCreateGeom"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateGeom(int classnum); [DllImport("ode", EntryPoint = "dCreateGeomClass"), SuppressUnmanagedCodeSecurity] public static extern int CreateGeomClass(ref GeomClass classptr); [DllImport("ode", EntryPoint = "dCreateGeomTransform"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateGeomTransform(IntPtr space); [DllImport("ode", EntryPoint = "dCreatePlane"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreatePlane(IntPtr space, dReal a, dReal b, dReal c, dReal d); [DllImport("ode", EntryPoint = "dCreateRay"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateRay(IntPtr space, dReal length); [DllImport("ode", EntryPoint = "dCreateSphere"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateSphere(IntPtr space, dReal radius); [DllImport("ode", EntryPoint = "dCreateTriMesh"), SuppressUnmanagedCodeSecurity] public static extern IntPtr CreateTriMesh(IntPtr space, IntPtr data, TriCallback callback, TriArrayCallback arrayCallback, TriRayCallback rayCallback); [DllImport("ode", EntryPoint = "dDot"), SuppressUnmanagedCodeSecurity] public static extern dReal Dot(ref dReal X0, ref dReal X1, int n); [DllImport("ode", EntryPoint = "dDQfromW"), SuppressUnmanagedCodeSecurity] public static extern void DQfromW(dReal[] dq, ref Vector3 w, ref Quaternion q); [DllImport("ode", EntryPoint = "dFactorCholesky"), SuppressUnmanagedCodeSecurity] public static extern int FactorCholesky(ref dReal A00, int n); [DllImport("ode", EntryPoint = "dFactorLDLT"), SuppressUnmanagedCodeSecurity] public static extern void FactorLDLT(ref dReal A, out dReal d, int n, int nskip); [DllImport("ode", EntryPoint = "dGeomBoxGetLengths"), SuppressUnmanagedCodeSecurity] public static extern void GeomBoxGetLengths(IntPtr geom, out Vector3 len); [DllImport("ode", EntryPoint = "dGeomBoxGetLengths"), SuppressUnmanagedCodeSecurity] public static extern void GeomBoxGetLengths(IntPtr geom, out dReal x); [DllImport("ode", EntryPoint = "dGeomBoxPointDepth"), SuppressUnmanagedCodeSecurity] public static extern dReal GeomBoxPointDepth(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomBoxSetLengths"), SuppressUnmanagedCodeSecurity] public static extern void GeomBoxSetLengths(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomCapsuleGetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomCapsuleGetParams(IntPtr geom, out dReal radius, out dReal length); [DllImport("ode", EntryPoint = "dGeomCapsulePointDepth"), SuppressUnmanagedCodeSecurity] public static extern dReal GeomCapsulePointDepth(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomCapsuleSetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomCapsuleSetParams(IntPtr geom, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dGeomClearOffset"), SuppressUnmanagedCodeSecurity] public static extern void GeomClearOffset(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomCopyOffsetPosition"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomCopyOffsetPosition(IntPtr geom, ref Vector3 pos); [DllImport("ode", EntryPoint = "dGeomCopyOffsetPosition"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomCopyOffsetPosition(IntPtr geom, ref dReal X); [DllImport("ode", EntryPoint = "dGeomGetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyOffsetQuaternion(IntPtr geom, ref Quaternion Q); [DllImport("ode", EntryPoint = "dGeomGetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyOffsetQuaternion(IntPtr geom, ref dReal X); [DllImport("ode", EntryPoint = "dGeomCopyOffsetRotation"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomCopyOffsetRotation(IntPtr geom, ref Matrix3 R); [DllImport("ode", EntryPoint = "dGeomCopyOffsetRotation"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomCopyOffsetRotation(IntPtr geom, ref dReal M00); [DllImport("ode", EntryPoint = "dGeomCopyPosition"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyPosition(IntPtr geom, out Vector3 pos); [DllImport("ode", EntryPoint = "dGeomCopyPosition"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyPosition(IntPtr geom, out dReal X); [DllImport("ode", EntryPoint = "dGeomCopyRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyRotation(IntPtr geom, out Matrix3 R); [DllImport("ode", EntryPoint = "dGeomCopyRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyRotation(IntPtr geom, out dReal M00); [DllImport("ode", EntryPoint = "dGeomCylinderGetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomCylinderGetParams(IntPtr geom, out dReal radius, out dReal length); [DllImport("ode", EntryPoint = "dGeomCylinderSetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomCylinderSetParams(IntPtr geom, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dGeomDestroy"), SuppressUnmanagedCodeSecurity] public static extern void GeomDestroy(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomDisable"), SuppressUnmanagedCodeSecurity] public static extern void GeomDisable(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomEnable"), SuppressUnmanagedCodeSecurity] public static extern void GeomEnable(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomGetAABB"), SuppressUnmanagedCodeSecurity] public static extern void GeomGetAABB(IntPtr geom, out AABB aabb); [DllImport("ode", EntryPoint = "dGeomGetAABB"), SuppressUnmanagedCodeSecurity] public static extern void GeomGetAABB(IntPtr geom, out dReal minX); [DllImport("ode", EntryPoint = "dGeomGetBody"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomGetBody(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomGetCategoryBits"), SuppressUnmanagedCodeSecurity] public static extern int GeomGetCategoryBits(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomGetClassData"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomGetClassData(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomGetCollideBits"), SuppressUnmanagedCodeSecurity] public static extern int GeomGetCollideBits(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomGetClass"), SuppressUnmanagedCodeSecurity] public static extern GeomClassID GeomGetClass(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomGetData"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomGetData(IntPtr geom); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dGeomGetOffsetPosition"), SuppressUnmanagedCodeSecurity] public extern unsafe static Vector3* GeomGetOffsetPositionUnsafe(IntPtr geom); public static Vector3 GeomGetOffsetPosition(IntPtr geom) { unsafe { return *(GeomGetOffsetPositionUnsafe(geom)); } } #endif #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dGeomGetOffsetRotation"), SuppressUnmanagedCodeSecurity] public extern unsafe static Matrix3* GeomGetOffsetRotationUnsafe(IntPtr geom); public static Matrix3 GeomGetOffsetRotation(IntPtr geom) { unsafe { return *(GeomGetOffsetRotationUnsafe(geom)); } } #endif #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dGeomGetPosition"), SuppressUnmanagedCodeSecurity] public extern unsafe static Vector3* GeomGetPositionUnsafe(IntPtr geom); public static Vector3 GeomGetPosition(IntPtr geom) { unsafe { return *(GeomGetPositionUnsafe(geom)); } } #endif [DllImport("ode", EntryPoint = "dGeomGetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyQuaternion(IntPtr geom, out Quaternion q); [DllImport("ode", EntryPoint = "dGeomGetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomCopyQuaternion(IntPtr geom, out dReal X); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dGeomGetRotation"), SuppressUnmanagedCodeSecurity] public extern unsafe static Matrix3* GeomGetRotationUnsafe(IntPtr geom); public static Matrix3 GeomGetRotation(IntPtr geom) { unsafe { return *(GeomGetRotationUnsafe(geom)); } } #endif [DllImport("ode", EntryPoint = "dGeomGetSpace"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomGetSpace(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildByte"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildByte(IntPtr d, byte[] pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildByte"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildByte(IntPtr d, IntPtr pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildCallback"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildCallback(IntPtr d, IntPtr pUserData, HeightfieldGetHeight pCallback, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildShort"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildShort(IntPtr d, ushort[] pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildShort"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildShort(IntPtr d, short[] pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildShort"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildShort(IntPtr d, IntPtr pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildSingle"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildSingle(IntPtr d, float[] pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildSingle"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildSingle(IntPtr d, IntPtr pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildDouble"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildDouble(IntPtr d, double[] pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataBuildDouble"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataBuildDouble(IntPtr d, IntPtr pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomHeightfieldDataCreate(); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataDestroy"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataDestroy(IntPtr d); [DllImport("ode", EntryPoint = "dGeomHeightfieldDataSetBounds"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldDataSetBounds(IntPtr d, dReal minHeight, dReal maxHeight); [DllImport("ode", EntryPoint = "dGeomHeightfieldGetHeightfieldData"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomHeightfieldGetHeightfieldData(IntPtr g); [DllImport("ode", EntryPoint = "dGeomHeightfieldSetHeightfieldData"), SuppressUnmanagedCodeSecurity] public static extern void GeomHeightfieldSetHeightfieldData(IntPtr g, IntPtr d); [DllImport("ode", EntryPoint = "dGeomIsEnabled"), SuppressUnmanagedCodeSecurity] public static extern bool GeomIsEnabled(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomIsOffset"), SuppressUnmanagedCodeSecurity] public static extern bool GeomIsOffset(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomIsSpace"), SuppressUnmanagedCodeSecurity] public static extern bool GeomIsSpace(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomPlaneGetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomPlaneGetParams(IntPtr geom, ref Vector4 result); [DllImport("ode", EntryPoint = "dGeomPlaneGetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomPlaneGetParams(IntPtr geom, ref dReal A); [DllImport("ode", EntryPoint = "dGeomPlanePointDepth"), SuppressUnmanagedCodeSecurity] public static extern dReal GeomPlanePointDepth(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomPlaneSetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomPlaneSetParams(IntPtr plane, dReal a, dReal b, dReal c, dReal d); [DllImport("ode", EntryPoint = "dGeomRayGet"), SuppressUnmanagedCodeSecurity] public static extern void GeomRayGet(IntPtr ray, ref Vector3 start, ref Vector3 dir); [DllImport("ode", EntryPoint = "dGeomRayGet"), SuppressUnmanagedCodeSecurity] public static extern void GeomRayGet(IntPtr ray, ref dReal startX, ref dReal dirX); [DllImport("ode", EntryPoint = "dGeomRayGetClosestHit"), SuppressUnmanagedCodeSecurity] public static extern int GeomRayGetClosestHit(IntPtr ray); [DllImport("ode", EntryPoint = "dGeomRayGetLength"), SuppressUnmanagedCodeSecurity] public static extern dReal GeomRayGetLength(IntPtr ray); [DllImport("ode", EntryPoint = "dGeomRayGetParams"), SuppressUnmanagedCodeSecurity] public static extern dReal GeomRayGetParams(IntPtr g, out int firstContact, out int backfaceCull); [DllImport("ode", EntryPoint = "dGeomRaySet"), SuppressUnmanagedCodeSecurity] public static extern void GeomRaySet(IntPtr ray, dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz); [DllImport("ode", EntryPoint = "dGeomRaySetClosestHit"), SuppressUnmanagedCodeSecurity] public static extern void GeomRaySetClosestHit(IntPtr ray, int closestHit); [DllImport("ode", EntryPoint = "dGeomRaySetLength"), SuppressUnmanagedCodeSecurity] public static extern void GeomRaySetLength(IntPtr ray, dReal length); [DllImport("ode", EntryPoint = "dGeomRaySetParams"), SuppressUnmanagedCodeSecurity] public static extern void GeomRaySetParams(IntPtr ray, int firstContact, int backfaceCull); [DllImport("ode", EntryPoint = "dGeomSetBody"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetBody(IntPtr geom, IntPtr body); [DllImport("ode", EntryPoint = "dGeomSetCategoryBits"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetCategoryBits(IntPtr geom, int bits); [DllImport("ode", EntryPoint = "dGeomSetCollideBits"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetCollideBits(IntPtr geom, int bits); [DllImport("ode", EntryPoint = "dGeomSetConvex"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomSetConvex(IntPtr geom, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons); [DllImport("ode", EntryPoint = "dGeomSetData"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetData(IntPtr geom, IntPtr data); [DllImport("ode", EntryPoint = "dGeomSetOffsetPosition"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetPosition(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomSetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetQuaternion(IntPtr geom, ref Quaternion Q); [DllImport("ode", EntryPoint = "dGeomSetOffsetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetQuaternion(IntPtr geom, ref dReal X); [DllImport("ode", EntryPoint = "dGeomSetOffsetRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetRotation(IntPtr geom, ref Matrix3 R); [DllImport("ode", EntryPoint = "dGeomSetOffsetRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetRotation(IntPtr geom, ref dReal M00); [DllImport("ode", EntryPoint = "dGeomSetOffsetWorldPosition"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetWorldPosition(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomSetOffsetWorldQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetWorldQuaternion(IntPtr geom, ref Quaternion Q); [DllImport("ode", EntryPoint = "dGeomSetOffsetWorldQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetWorldQuaternion(IntPtr geom, ref dReal X); [DllImport("ode", EntryPoint = "dGeomSetOffsetWorldRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetWorldRotation(IntPtr geom, ref Matrix3 R); [DllImport("ode", EntryPoint = "dGeomSetOffsetWorldRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetOffsetWorldRotation(IntPtr geom, ref dReal M00); [DllImport("ode", EntryPoint = "dGeomSetPosition"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetPosition(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomSetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetQuaternion(IntPtr geom, ref Quaternion quat); [DllImport("ode", EntryPoint = "dGeomSetQuaternion"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetQuaternion(IntPtr geom, ref dReal w); [DllImport("ode", EntryPoint = "dGeomSetRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetRotation(IntPtr geom, ref Matrix3 R); [DllImport("ode", EntryPoint = "dGeomSetRotation"), SuppressUnmanagedCodeSecurity] public static extern void GeomSetRotation(IntPtr geom, ref dReal M00); [DllImport("ode", EntryPoint = "dGeomSphereGetRadius"), SuppressUnmanagedCodeSecurity] public static extern dReal GeomSphereGetRadius(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomSpherePointDepth"), SuppressUnmanagedCodeSecurity] public static extern dReal GeomSpherePointDepth(IntPtr geom, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dGeomSphereSetRadius"), SuppressUnmanagedCodeSecurity] public static extern void GeomSphereSetRadius(IntPtr geom, dReal radius); [DllImport("ode", EntryPoint = "dGeomTransformGetCleanup"), SuppressUnmanagedCodeSecurity] public static extern int GeomTransformGetCleanup(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomTransformGetGeom"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomTransformGetGeom(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomTransformGetInfo"), SuppressUnmanagedCodeSecurity] public static extern int GeomTransformGetInfo(IntPtr geom); [DllImport("ode", EntryPoint = "dGeomTransformSetCleanup"), SuppressUnmanagedCodeSecurity] public static extern void GeomTransformSetCleanup(IntPtr geom, int mode); [DllImport("ode", EntryPoint = "dGeomTransformSetGeom"), SuppressUnmanagedCodeSecurity] public static extern void GeomTransformSetGeom(IntPtr geom, IntPtr obj); [DllImport("ode", EntryPoint = "dGeomTransformSetInfo"), SuppressUnmanagedCodeSecurity] public static extern void GeomTransformSetInfo(IntPtr geom, int info); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildDouble"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildDouble(IntPtr d, double[] vertices, int vertexStride, int vertexCount, int[] indices, int indexCount, int triStride); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildDouble"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildDouble(IntPtr d, IntPtr vertices, int vertexStride, int vertexCount, IntPtr indices, int indexCount, int triStride); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildDouble1"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildDouble1(IntPtr d, double[] vertices, int vertexStride, int vertexCount, int[] indices, int indexCount, int triStride, double[] normals); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildDouble1"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildDouble(IntPtr d, IntPtr vertices, int vertexStride, int vertexCount, IntPtr indices, int indexCount, int triStride, IntPtr normals); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSimple"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSingle(IntPtr d, dReal[] vertices, int vertexStride, int vertexCount, int[] indices, int indexCount, int triStride); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSimple"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSingle(IntPtr d, IntPtr vertices, int vertexStride, int vertexCount, IntPtr indices, int indexCount, int triStride); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSimple1"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSingle1(IntPtr d, dReal[] vertices, int vertexStride, int vertexCount, int[] indices, int indexCount, int triStride, dReal[] normals); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSimple1"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSingle1(IntPtr d, IntPtr vertices, int vertexStride, int vertexCount, IntPtr indices, int indexCount, int triStride, IntPtr normals); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSingle"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSimple(IntPtr d, float[] vertices, int vertexStride, int vertexCount, int[] indices, int indexCount, int triStride); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSingle"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSimple(IntPtr d, IntPtr vertices, int vertexStride, int vertexCount, IntPtr indices, int indexCount, int triStride); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSingle1"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSimple1(IntPtr d, float[] vertices, int vertexStride, int vertexCount, int[] indices, int indexCount, int triStride, float[] normals); [DllImport("ode", EntryPoint = "dGeomTriMeshDataBuildSingle1"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataBuildSimple1(IntPtr d, IntPtr vertices, int vertexStride, int vertexCount, IntPtr indices, int indexCount, int triStride, IntPtr normals); [DllImport("ode", EntryPoint = "dGeomTriMeshClearTCCache"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshClearTCCache(IntPtr g); [DllImport("ode", EntryPoint = "dGeomTriMeshDataCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomTriMeshDataCreate(); [DllImport("ode", EntryPoint = "dGeomTriMeshDataDestroy"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataDestroy(IntPtr d); [DllImport("ode", EntryPoint = "dGeomTriMeshDataGet"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomTriMeshDataGet(IntPtr d, int data_id); [DllImport("ode", EntryPoint = "dGeomTriMeshDataPreprocess"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataPreprocess(IntPtr d); [DllImport("ode", EntryPoint = "dGeomTriMeshDataSet"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataSet(IntPtr d, int data_id, IntPtr in_data); [DllImport("ode", EntryPoint = "dGeomTriMeshDataUpdate"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshDataUpdate(IntPtr d); [DllImport("ode", EntryPoint = "dGeomTriMeshEnableTC"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshEnableTC(IntPtr g, int geomClass, bool enable); [DllImport("ode", EntryPoint = "dGeomTriMeshGetArrayCallback"), SuppressUnmanagedCodeSecurity] public static extern TriArrayCallback GeomTriMeshGetArrayCallback(IntPtr g); [DllImport("ode", EntryPoint = "dGeomTriMeshGetCallback"), SuppressUnmanagedCodeSecurity] public static extern TriCallback GeomTriMeshGetCallback(IntPtr g); [DllImport("ode", EntryPoint = "dGeomTriMeshGetData"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomTriMeshGetData(IntPtr g); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dGeomTriMeshGetLastTransform"), SuppressUnmanagedCodeSecurity] public extern unsafe static Matrix4* GeomTriMeshGetLastTransformUnsafe(IntPtr geom); public static Matrix4 GeomTriMeshGetLastTransform(IntPtr geom) { unsafe { return *(GeomTriMeshGetLastTransformUnsafe(geom)); } } #endif [DllImport("ode", EntryPoint = "dGeomTriMeshGetPoint"), SuppressUnmanagedCodeSecurity] public extern static void GeomTriMeshGetPoint(IntPtr g, int index, dReal u, dReal v, ref Vector3 outVec); [DllImport("ode", EntryPoint = "dGeomTriMeshGetRayCallback"), SuppressUnmanagedCodeSecurity] public static extern TriRayCallback GeomTriMeshGetRayCallback(IntPtr g); [DllImport("ode", EntryPoint = "dGeomTriMeshGetTriangle"), SuppressUnmanagedCodeSecurity] public extern static void GeomTriMeshGetTriangle(IntPtr g, int index, ref Vector3 v0, ref Vector3 v1, ref Vector3 v2); [DllImport("ode", EntryPoint = "dGeomTriMeshGetTriangleCount"), SuppressUnmanagedCodeSecurity] public extern static int GeomTriMeshGetTriangleCount(IntPtr g); [DllImport("ode", EntryPoint = "dGeomTriMeshGetTriMeshDataID"), SuppressUnmanagedCodeSecurity] public static extern IntPtr GeomTriMeshGetTriMeshDataID(IntPtr g); [DllImport("ode", EntryPoint = "dGeomTriMeshIsTCEnabled"), SuppressUnmanagedCodeSecurity] public static extern bool GeomTriMeshIsTCEnabled(IntPtr g, int geomClass); [DllImport("ode", EntryPoint = "dGeomTriMeshSetArrayCallback"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshSetArrayCallback(IntPtr g, TriArrayCallback arrayCallback); [DllImport("ode", EntryPoint = "dGeomTriMeshSetCallback"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshSetCallback(IntPtr g, TriCallback callback); [DllImport("ode", EntryPoint = "dGeomTriMeshSetData"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshSetData(IntPtr g, IntPtr data); [DllImport("ode", EntryPoint = "dGeomTriMeshSetLastTransform"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshSetLastTransform(IntPtr g, ref Matrix4 last_trans); [DllImport("ode", EntryPoint = "dGeomTriMeshSetLastTransform"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshSetLastTransform(IntPtr g, ref dReal M00); [DllImport("ode", EntryPoint = "dGeomTriMeshSetRayCallback"), SuppressUnmanagedCodeSecurity] public static extern void GeomTriMeshSetRayCallback(IntPtr g, TriRayCallback callback); [DllImport("ode", EntryPoint = "dHashSpaceCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr HashSpaceCreate(IntPtr space); [DllImport("ode", EntryPoint = "dHashSpaceGetLevels"), SuppressUnmanagedCodeSecurity] public static extern void HashSpaceGetLevels(IntPtr space, out int minlevel, out int maxlevel); [DllImport("ode", EntryPoint = "dHashSpaceSetLevels"), SuppressUnmanagedCodeSecurity] public static extern void HashSpaceSetLevels(IntPtr space, int minlevel, int maxlevel); [DllImport("ode", EntryPoint = "dInfiniteAABB"), SuppressUnmanagedCodeSecurity] public static extern void InfiniteAABB(IntPtr geom, out AABB aabb); [DllImport("ode", EntryPoint = "dInitODE"), SuppressUnmanagedCodeSecurity] public static extern void InitODE(); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dInitODE2"), SuppressUnmanagedCodeSecurity] public static extern int InitODE2(uint ODEInitFlags); #endif [DllImport("ode", EntryPoint = "dIsPositiveDefinite"), SuppressUnmanagedCodeSecurity] public static extern int IsPositiveDefinite(ref dReal A, int n); [DllImport("ode", EntryPoint = "dInvertPDMatrix"), SuppressUnmanagedCodeSecurity] public static extern int InvertPDMatrix(ref dReal A, out dReal Ainv, int n); [DllImport("ode", EntryPoint = "dJointAddAMotorTorques"), SuppressUnmanagedCodeSecurity] public static extern void JointAddAMotorTorques(IntPtr joint, dReal torque1, dReal torque2, dReal torque3); [DllImport("ode", EntryPoint = "dJointAddHingeTorque"), SuppressUnmanagedCodeSecurity] public static extern void JointAddHingeTorque(IntPtr joint, dReal torque); [DllImport("ode", EntryPoint = "dJointAddHinge2Torque"), SuppressUnmanagedCodeSecurity] public static extern void JointAddHinge2Torques(IntPtr joint, dReal torque1, dReal torque2); [DllImport("ode", EntryPoint = "dJointAddPRTorque"), SuppressUnmanagedCodeSecurity] public static extern void JointAddPRTorque(IntPtr joint, dReal torque); [DllImport("ode", EntryPoint = "dJointAddUniversalTorque"), SuppressUnmanagedCodeSecurity] public static extern void JointAddUniversalTorques(IntPtr joint, dReal torque1, dReal torque2); [DllImport("ode", EntryPoint = "dJointAddSliderForce"), SuppressUnmanagedCodeSecurity] public static extern void JointAddSliderForce(IntPtr joint, dReal force); [DllImport("ode", EntryPoint = "dJointAttach"), SuppressUnmanagedCodeSecurity] public static extern void JointAttach(IntPtr joint, IntPtr body1, IntPtr body2); [DllImport("ode", EntryPoint = "dJointCreateAMotor"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateAMotor(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateBall"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateBall(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateContact"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateContact(IntPtr world, IntPtr group, ref Contact contact); [DllImport("ode", EntryPoint = "dJointCreateFixed"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateFixed(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateHinge"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateHinge(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateHinge2"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateHinge2(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateLMotor"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateLMotor(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateNull"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateNull(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreatePR"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreatePR(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreatePlane2D"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreatePlane2D(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateSlider"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateSlider(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointCreateUniversal"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointCreateUniversal(IntPtr world, IntPtr group); [DllImport("ode", EntryPoint = "dJointDestroy"), SuppressUnmanagedCodeSecurity] public static extern void JointDestroy(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetAMotorAngle"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetAMotorAngle(IntPtr j, int anum); [DllImport("ode", EntryPoint = "dJointGetAMotorAngleRate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetAMotorAngleRate(IntPtr j, int anum); [DllImport("ode", EntryPoint = "dJointGetAMotorAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointGetAMotorAxis(IntPtr j, int anum, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetAMotorAxisRel"), SuppressUnmanagedCodeSecurity] public static extern int JointGetAMotorAxisRel(IntPtr j, int anum); [DllImport("ode", EntryPoint = "dJointGetAMotorMode"), SuppressUnmanagedCodeSecurity] public static extern int JointGetAMotorMode(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetAMotorNumAxes"), SuppressUnmanagedCodeSecurity] public static extern int JointGetAMotorNumAxes(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetAMotorParam"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetAMotorParam(IntPtr j, int parameter); [DllImport("ode", EntryPoint = "dJointGetBallAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointGetBallAnchor(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetBallAnchor2"), SuppressUnmanagedCodeSecurity] public static extern void JointGetBallAnchor2(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetBody"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointGetBody(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetData"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointGetData(IntPtr j); #if !dNO_UNSAFE_CODE [CLSCompliant(false)] [DllImport("ode", EntryPoint = "dJointGetFeedback"), SuppressUnmanagedCodeSecurity] public extern unsafe static JointFeedback* JointGetFeedbackUnsafe(IntPtr j); public static JointFeedback JointGetFeedback(IntPtr j) { unsafe { return *(JointGetFeedbackUnsafe(j)); } } #endif [DllImport("ode", EntryPoint = "dJointGetHingeAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointGetHingeAnchor(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetHingeAngle"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetHingeAngle(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetHingeAngleRate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetHingeAngleRate(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetHingeAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointGetHingeAxis(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetHingeParam"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetHingeParam(IntPtr j, int parameter); [DllImport("ode", EntryPoint = "dJointGetHinge2Angle1"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetHinge2Angle1(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetHinge2Angle1Rate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetHinge2Angle1Rate(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetHinge2Angle2Rate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetHinge2Angle2Rate(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetHingeAnchor2"), SuppressUnmanagedCodeSecurity] public static extern void JointGetHingeAnchor2(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetHinge2Anchor"), SuppressUnmanagedCodeSecurity] public static extern void JointGetHinge2Anchor(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetHinge2Anchor2"), SuppressUnmanagedCodeSecurity] public static extern void JointGetHinge2Anchor2(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetHinge2Axis1"), SuppressUnmanagedCodeSecurity] public static extern void JointGetHinge2Axis1(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetHinge2Axis2"), SuppressUnmanagedCodeSecurity] public static extern void JointGetHinge2Axis2(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetHinge2Param"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetHinge2Param(IntPtr j, int parameter); [DllImport("ode", EntryPoint = "dJointGetLMotorAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointGetLMotorAxis(IntPtr j, int anum, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetLMotorNumAxes"), SuppressUnmanagedCodeSecurity] public static extern int JointGetLMotorNumAxes(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetLMotorParam"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetLMotorParam(IntPtr j, int parameter); [DllImport("ode", EntryPoint = "dJointGetPRAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointGetPRAnchor(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetPRAxis1"), SuppressUnmanagedCodeSecurity] public static extern void JointGetPRAxis1(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetPRAxis2"), SuppressUnmanagedCodeSecurity] public static extern void JointGetPRAxis2(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetPRParam"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetPRParam(IntPtr j, int parameter); [DllImport("ode", EntryPoint = "dJointGetPRPosition"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetPRPosition(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetPRPositionRate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetPRPositionRate(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetSliderAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointGetSliderAxis(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetSliderParam"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetSliderParam(IntPtr j, int parameter); [DllImport("ode", EntryPoint = "dJointGetSliderPosition"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetSliderPosition(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetSliderPositionRate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetSliderPositionRate(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetType"), SuppressUnmanagedCodeSecurity] public static extern JointType JointGetType(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetUniversalAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointGetUniversalAnchor(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetUniversalAnchor2"), SuppressUnmanagedCodeSecurity] public static extern void JointGetUniversalAnchor2(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetUniversalAngle1"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetUniversalAngle1(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetUniversalAngle1Rate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetUniversalAngle1Rate(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetUniversalAngle2"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetUniversalAngle2(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetUniversalAngle2Rate"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetUniversalAngle2Rate(IntPtr j); [DllImport("ode", EntryPoint = "dJointGetUniversalAngles"), SuppressUnmanagedCodeSecurity] public static extern void JointGetUniversalAngles(IntPtr j, out dReal angle1, out dReal angle2); [DllImport("ode", EntryPoint = "dJointGetUniversalAxis1"), SuppressUnmanagedCodeSecurity] public static extern void JointGetUniversalAxis1(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetUniversalAxis2"), SuppressUnmanagedCodeSecurity] public static extern void JointGetUniversalAxis2(IntPtr j, out Vector3 result); [DllImport("ode", EntryPoint = "dJointGetUniversalParam"), SuppressUnmanagedCodeSecurity] public static extern dReal JointGetUniversalParam(IntPtr j, int parameter); [DllImport("ode", EntryPoint = "dJointGroupCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr JointGroupCreate(int max_size); [DllImport("ode", EntryPoint = "dJointGroupDestroy"), SuppressUnmanagedCodeSecurity] public static extern void JointGroupDestroy(IntPtr group); [DllImport("ode", EntryPoint = "dJointGroupEmpty"), SuppressUnmanagedCodeSecurity] public static extern void JointGroupEmpty(IntPtr group); [DllImport("ode", EntryPoint = "dJointSetAMotorAngle"), SuppressUnmanagedCodeSecurity] public static extern void JointSetAMotorAngle(IntPtr j, int anum, dReal angle); [DllImport("ode", EntryPoint = "dJointSetAMotorAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointSetAMotorAxis(IntPtr j, int anum, int rel, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetAMotorMode"), SuppressUnmanagedCodeSecurity] public static extern void JointSetAMotorMode(IntPtr j, int mode); [DllImport("ode", EntryPoint = "dJointSetAMotorNumAxes"), SuppressUnmanagedCodeSecurity] public static extern void JointSetAMotorNumAxes(IntPtr group, int num); [DllImport("ode", EntryPoint = "dJointSetAMotorParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetAMotorParam(IntPtr group, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetBallAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointSetBallAnchor(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetBallAnchor2"), SuppressUnmanagedCodeSecurity] public static extern void JointSetBallAnchor2(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetData"), SuppressUnmanagedCodeSecurity] public static extern void JointSetData(IntPtr j, IntPtr data); [DllImport("ode", EntryPoint = "dJointSetFeedback"), SuppressUnmanagedCodeSecurity] public static extern void JointSetFeedback(IntPtr j, out JointFeedback feedback); [DllImport("ode", EntryPoint = "dJointSetFixed"), SuppressUnmanagedCodeSecurity] public static extern void JointSetFixed(IntPtr j); [DllImport("ode", EntryPoint = "dJointSetHingeAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHingeAnchor(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetHingeAnchorDelta"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHingeAnchorDelta(IntPtr j, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); [DllImport("ode", EntryPoint = "dJointSetHingeAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHingeAxis(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetHingeParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHingeParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetHinge2Anchor"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHinge2Anchor(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetHinge2Axis1"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHinge2Axis1(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetHinge2Axis2"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHinge2Axis2(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetHinge2Param"), SuppressUnmanagedCodeSecurity] public static extern void JointSetHinge2Param(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetLMotorAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointSetLMotorAxis(IntPtr j, int anum, int rel, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetLMotorNumAxes"), SuppressUnmanagedCodeSecurity] public static extern void JointSetLMotorNumAxes(IntPtr j, int num); [DllImport("ode", EntryPoint = "dJointSetLMotorParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetLMotorParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetPlane2DAngleParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetPlane2DAngleParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetPlane2DXParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetPlane2DXParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetPlane2DYParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetPlane2DYParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetPRAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointSetPRAnchor(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetPRAxis1"), SuppressUnmanagedCodeSecurity] public static extern void JointSetPRAxis1(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetPRAxis2"), SuppressUnmanagedCodeSecurity] public static extern void JointSetPRAxis2(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetPRParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetPRParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetSliderAxis"), SuppressUnmanagedCodeSecurity] public static extern void JointSetSliderAxis(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetSliderAxisDelta"), SuppressUnmanagedCodeSecurity] public static extern void JointSetSliderAxisDelta(IntPtr j, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); [DllImport("ode", EntryPoint = "dJointSetSliderParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetSliderParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dJointSetUniversalAnchor"), SuppressUnmanagedCodeSecurity] public static extern void JointSetUniversalAnchor(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetUniversalAxis1"), SuppressUnmanagedCodeSecurity] public static extern void JointSetUniversalAxis1(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetUniversalAxis2"), SuppressUnmanagedCodeSecurity] public static extern void JointSetUniversalAxis2(IntPtr j, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dJointSetUniversalParam"), SuppressUnmanagedCodeSecurity] public static extern void JointSetUniversalParam(IntPtr j, int parameter, dReal value); [DllImport("ode", EntryPoint = "dLDLTAddTL"), SuppressUnmanagedCodeSecurity] public static extern void LDLTAddTL(ref dReal L, ref dReal d, ref dReal a, int n, int nskip); [DllImport("ode", EntryPoint = "dMassAdd"), SuppressUnmanagedCodeSecurity] public static extern void MassAdd(ref Mass a, ref Mass b); [DllImport("ode", EntryPoint = "dMassAdjust"), SuppressUnmanagedCodeSecurity] public static extern void MassAdjust(ref Mass m, dReal newmass); [DllImport("ode", EntryPoint = "dMassCheck"), SuppressUnmanagedCodeSecurity] public static extern bool MassCheck(ref Mass m); [DllImport("ode", EntryPoint = "dMassRotate"), SuppressUnmanagedCodeSecurity] public static extern void MassRotate(out Mass mass, ref Matrix3 R); [DllImport("ode", EntryPoint = "dMassRotate"), SuppressUnmanagedCodeSecurity] public static extern void MassRotate(out Mass mass, ref dReal M00); [DllImport("ode", EntryPoint = "dMassSetBox"), SuppressUnmanagedCodeSecurity] public static extern void MassSetBox(out Mass mass, dReal density, dReal lx, dReal ly, dReal lz); [DllImport("ode", EntryPoint = "dMassSetBoxTotal"), SuppressUnmanagedCodeSecurity] public static extern void MassSetBoxTotal(out Mass mass, dReal total_mass, dReal lx, dReal ly, dReal lz); [DllImport("ode", EntryPoint = "dMassSetCapsule"), SuppressUnmanagedCodeSecurity] public static extern void MassSetCapsule(out Mass mass, dReal density, int direction, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dMassSetCapsuleTotal"), SuppressUnmanagedCodeSecurity] public static extern void MassSetCapsuleTotal(out Mass mass, dReal total_mass, int direction, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dMassSetCylinder"), SuppressUnmanagedCodeSecurity] public static extern void MassSetCylinder(out Mass mass, dReal density, int direction, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dMassSetCylinderTotal"), SuppressUnmanagedCodeSecurity] public static extern void MassSetCylinderTotal(out Mass mass, dReal total_mass, int direction, dReal radius, dReal length); [DllImport("ode", EntryPoint = "dMassSetParameters"), SuppressUnmanagedCodeSecurity] public static extern void MassSetParameters(out Mass mass, dReal themass, dReal cgx, dReal cgy, dReal cgz, dReal i11, dReal i22, dReal i33, dReal i12, dReal i13, dReal i23); [DllImport("ode", EntryPoint = "dMassSetSphere"), SuppressUnmanagedCodeSecurity] public static extern void MassSetSphere(out Mass mass, dReal density, dReal radius); [DllImport("ode", EntryPoint = "dMassSetSphereTotal"), SuppressUnmanagedCodeSecurity] public static extern void dMassSetSphereTotal(out Mass mass, dReal total_mass, dReal radius); [DllImport("ode", EntryPoint = "dMassSetTrimesh"), SuppressUnmanagedCodeSecurity] public static extern void MassSetTrimesh(out Mass mass, dReal density, IntPtr g); [DllImport("ode", EntryPoint = "dMassSetZero"), SuppressUnmanagedCodeSecurity] public static extern void MassSetZero(out Mass mass); [DllImport("ode", EntryPoint = "dMassTranslate"), SuppressUnmanagedCodeSecurity] public static extern void MassTranslate(out Mass mass, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dMultiply0"), SuppressUnmanagedCodeSecurity] public static extern void Multiply0(out dReal A00, ref dReal B00, ref dReal C00, int p, int q, int r); [DllImport("ode", EntryPoint = "dMultiply1"), SuppressUnmanagedCodeSecurity] public static extern void Multiply1(out dReal A00, ref dReal B00, ref dReal C00, int p, int q, int r); [DllImport("ode", EntryPoint = "dMultiply2"), SuppressUnmanagedCodeSecurity] public static extern void Multiply2(out dReal A00, ref dReal B00, ref dReal C00, int p, int q, int r); [DllImport("ode", EntryPoint = "dQFromAxisAndAngle"), SuppressUnmanagedCodeSecurity] public static extern void QFromAxisAndAngle(out Quaternion q, dReal ax, dReal ay, dReal az, dReal angle); [DllImport("ode", EntryPoint = "dQfromR"), SuppressUnmanagedCodeSecurity] public static extern void QfromR(out Quaternion q, ref Matrix3 R); [DllImport("ode", EntryPoint = "dQMultiply0"), SuppressUnmanagedCodeSecurity] public static extern void QMultiply0(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); [DllImport("ode", EntryPoint = "dQMultiply1"), SuppressUnmanagedCodeSecurity] public static extern void QMultiply1(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); [DllImport("ode", EntryPoint = "dQMultiply2"), SuppressUnmanagedCodeSecurity] public static extern void QMultiply2(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); [DllImport("ode", EntryPoint = "dQMultiply3"), SuppressUnmanagedCodeSecurity] public static extern void QMultiply3(out Quaternion qa, ref Quaternion qb, ref Quaternion qc); [DllImport("ode", EntryPoint = "dQSetIdentity"), SuppressUnmanagedCodeSecurity] public static extern void QSetIdentity(out Quaternion q); [DllImport("ode", EntryPoint = "dQuadTreeSpaceCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr QuadTreeSpaceCreate(IntPtr space, ref Vector3 center, ref Vector3 extents, int depth); [DllImport("ode", EntryPoint = "dQuadTreeSpaceCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr QuadTreeSpaceCreate(IntPtr space, ref dReal centerX, ref dReal extentsX, int depth); [DllImport("ode", EntryPoint = "dRandReal"), SuppressUnmanagedCodeSecurity] public static extern dReal RandReal(); [DllImport("ode", EntryPoint = "dRFrom2Axes"), SuppressUnmanagedCodeSecurity] public static extern void RFrom2Axes(out Matrix3 R, dReal ax, dReal ay, dReal az, dReal bx, dReal by, dReal bz); [DllImport("ode", EntryPoint = "dRFromAxisAndAngle"), SuppressUnmanagedCodeSecurity] public static extern void RFromAxisAndAngle(out Matrix3 R, dReal x, dReal y, dReal z, dReal angle); [DllImport("ode", EntryPoint = "dRFromEulerAngles"), SuppressUnmanagedCodeSecurity] public static extern void RFromEulerAngles(out Matrix3 R, dReal phi, dReal theta, dReal psi); [DllImport("ode", EntryPoint = "dRfromQ"), SuppressUnmanagedCodeSecurity] public static extern void RfromQ(out Matrix3 R, ref Quaternion q); [DllImport("ode", EntryPoint = "dRFromZAxis"), SuppressUnmanagedCodeSecurity] public static extern void RFromZAxis(out Matrix3 R, dReal ax, dReal ay, dReal az); [DllImport("ode", EntryPoint = "dRSetIdentity"), SuppressUnmanagedCodeSecurity] public static extern void RSetIdentity(out Matrix3 R); [DllImport("ode", EntryPoint = "dSetValue"), SuppressUnmanagedCodeSecurity] public static extern void SetValue(out dReal a, int n); [DllImport("ode", EntryPoint = "dSetZero"), SuppressUnmanagedCodeSecurity] public static extern void SetZero(out dReal a, int n); [DllImport("ode", EntryPoint = "dSimpleSpaceCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr SimpleSpaceCreate(IntPtr space); [DllImport("ode", EntryPoint = "dSolveCholesky"), SuppressUnmanagedCodeSecurity] public static extern void SolveCholesky(ref dReal L, out dReal b, int n); [DllImport("ode", EntryPoint = "dSolveL1"), SuppressUnmanagedCodeSecurity] public static extern void SolveL1(ref dReal L, out dReal b, int n, int nskip); [DllImport("ode", EntryPoint = "dSolveL1T"), SuppressUnmanagedCodeSecurity] public static extern void SolveL1T(ref dReal L, out dReal b, int n, int nskip); [DllImport("ode", EntryPoint = "dSolveLDLT"), SuppressUnmanagedCodeSecurity] public static extern void SolveLDLT(ref dReal L, ref dReal d, out dReal b, int n, int nskip); [DllImport("ode", EntryPoint = "dSpaceAdd"), SuppressUnmanagedCodeSecurity] public static extern void SpaceAdd(IntPtr space, IntPtr geom); [DllImport("ode", EntryPoint = "dSpaceClean"), SuppressUnmanagedCodeSecurity] public static extern void SpaceClean(IntPtr space); [DllImport("ode", EntryPoint = "dSpaceCollide"), SuppressUnmanagedCodeSecurity] public static extern void SpaceCollide(IntPtr space, IntPtr data, NearCallback callback); [DllImport("ode", EntryPoint = "dSpaceCollide2"), SuppressUnmanagedCodeSecurity] public static extern void SpaceCollide2(IntPtr space1, IntPtr space2, IntPtr data, NearCallback callback); [DllImport("ode", EntryPoint = "dSpaceDestroy"), SuppressUnmanagedCodeSecurity] public static extern void SpaceDestroy(IntPtr space); [DllImport("ode", EntryPoint = "dSpaceGetCleanup"), SuppressUnmanagedCodeSecurity] public static extern bool SpaceGetCleanup(IntPtr space); [DllImport("ode", EntryPoint = "dSpaceGetNumGeoms"), SuppressUnmanagedCodeSecurity] public static extern int SpaceGetNumGeoms(IntPtr space); [DllImport("ode", EntryPoint = "dSpaceGetGeom"), SuppressUnmanagedCodeSecurity] public static extern IntPtr SpaceGetGeom(IntPtr space, int i); [DllImport("ode", EntryPoint = "dSpaceGetSublevel"), SuppressUnmanagedCodeSecurity] public static extern int SpaceGetSublevel(IntPtr space); [DllImport("ode", EntryPoint = "dSpaceQuery"), SuppressUnmanagedCodeSecurity] public static extern bool SpaceQuery(IntPtr space, IntPtr geom); [DllImport("ode", EntryPoint = "dSpaceRemove"), SuppressUnmanagedCodeSecurity] public static extern void SpaceRemove(IntPtr space, IntPtr geom); [DllImport("ode", EntryPoint = "dSpaceSetCleanup"), SuppressUnmanagedCodeSecurity] public static extern void SpaceSetCleanup(IntPtr space, bool mode); [DllImport("ode", EntryPoint = "dSpaceSetSublevel"), SuppressUnmanagedCodeSecurity] public static extern void SpaceSetSublevel(IntPtr space, int sublevel); [DllImport("ode", EntryPoint = "dSweepAndPruneSpaceCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr SweepAndPruneSpaceCreate(IntPtr space, int AxisOrder); [DllImport("ode", EntryPoint = "dVectorScale"), SuppressUnmanagedCodeSecurity] public static extern void VectorScale(out dReal a, ref dReal d, int n); [DllImport("ode", EntryPoint = "dWorldCreate"), SuppressUnmanagedCodeSecurity] public static extern IntPtr WorldCreate(); [DllImport("ode", EntryPoint = "dWorldDestroy"), SuppressUnmanagedCodeSecurity] public static extern void WorldDestroy(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAutoDisableAverageSamplesCount"), SuppressUnmanagedCodeSecurity] public static extern int WorldGetAutoDisableAverageSamplesCount(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetAutoDisableAngularThreshold(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] public static extern bool WorldGetAutoDisableFlag(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetAutoDisableLinearThreshold(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] public static extern int WorldGetAutoDisableSteps(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAutoDisableTime"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetAutoDisableTime(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAutoEnableDepthSF1"), SuppressUnmanagedCodeSecurity] public static extern int WorldGetAutoEnableDepthSF1(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetCFM"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetCFM(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetERP"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetERP(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetGravity"), SuppressUnmanagedCodeSecurity] public static extern void WorldGetGravity(IntPtr world, out Vector3 gravity); [DllImport("ode", EntryPoint = "dWorldGetGravity"), SuppressUnmanagedCodeSecurity] public static extern void WorldGetGravity(IntPtr world, out dReal X); [DllImport("ode", EntryPoint = "dWorldGetContactMaxCorrectingVel"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetContactMaxCorrectingVel(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetContactSurfaceLayer"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetContactSurfaceLayer(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAngularDamping"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetAngularDamping(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetAngularDampingThreshold(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetLinearDamping"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetLinearDamping(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetLinearDampingThreshold(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetQuickStepNumIterations"), SuppressUnmanagedCodeSecurity] public static extern int WorldGetQuickStepNumIterations(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetQuickStepW"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetQuickStepW(IntPtr world); [DllImport("ode", EntryPoint = "dWorldGetMaxAngularSpeed"), SuppressUnmanagedCodeSecurity] public static extern dReal WorldGetMaxAngularSpeed(IntPtr world); [DllImport("ode", EntryPoint = "dWorldImpulseToForce"), SuppressUnmanagedCodeSecurity] public static extern void WorldImpulseToForce(IntPtr world, dReal stepsize, dReal ix, dReal iy, dReal iz, out Vector3 force); [DllImport("ode", EntryPoint = "dWorldImpulseToForce"), SuppressUnmanagedCodeSecurity] public static extern void WorldImpulseToForce(IntPtr world, dReal stepsize, dReal ix, dReal iy, dReal iz, out dReal forceX); [DllImport("ode", EntryPoint = "dWorldQuickStep"), SuppressUnmanagedCodeSecurity] public static extern void WorldQuickStep(IntPtr world, dReal stepsize); [DllImport("ode", EntryPoint = "dWorldSetAngularDamping"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAngularDamping(IntPtr world, dReal scale); [DllImport("ode", EntryPoint = "dWorldSetAngularDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAngularDampingThreshold(IntPtr world, dReal threshold); [DllImport("ode", EntryPoint = "dWorldSetAutoDisableAngularThreshold"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAutoDisableAngularThreshold(IntPtr world, dReal angular_threshold); [DllImport("ode", EntryPoint = "dWorldSetAutoDisableAverageSamplesCount"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAutoDisableAverageSamplesCount(IntPtr world, int average_samples_count); [DllImport("ode", EntryPoint = "dWorldSetAutoDisableFlag"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAutoDisableFlag(IntPtr world, bool do_auto_disable); [DllImport("ode", EntryPoint = "dWorldSetAutoDisableLinearThreshold"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAutoDisableLinearThreshold(IntPtr world, dReal linear_threshold); [DllImport("ode", EntryPoint = "dWorldSetAutoDisableSteps"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAutoDisableSteps(IntPtr world, int steps); [DllImport("ode", EntryPoint = "dWorldSetAutoDisableTime"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAutoDisableTime(IntPtr world, dReal time); [DllImport("ode", EntryPoint = "dWorldSetAutoEnableDepthSF1"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetAutoEnableDepthSF1(IntPtr world, int autoEnableDepth); [DllImport("ode", EntryPoint = "dWorldSetCFM"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetCFM(IntPtr world, dReal cfm); [DllImport("ode", EntryPoint = "dWorldSetContactMaxCorrectingVel"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetContactMaxCorrectingVel(IntPtr world, dReal vel); [DllImport("ode", EntryPoint = "dWorldSetContactSurfaceLayer"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetContactSurfaceLayer(IntPtr world, dReal depth); [DllImport("ode", EntryPoint = "dWorldSetDamping"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetDamping(IntPtr world, dReal linear_scale, dReal angular_scale); [DllImport("ode", EntryPoint = "dWorldSetERP"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetERP(IntPtr world, dReal erp); [DllImport("ode", EntryPoint = "dWorldSetGravity"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetGravity(IntPtr world, dReal x, dReal y, dReal z); [DllImport("ode", EntryPoint = "dWorldSetLinearDamping"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetLinearDamping(IntPtr world, dReal scale); [DllImport("ode", EntryPoint = "dWorldSetLinearDampingThreshold"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetLinearDampingThreshold(IntPtr world, dReal threshold); [DllImport("ode", EntryPoint = "dWorldSetQuickStepNumIterations"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetQuickStepNumIterations(IntPtr world, int num); [DllImport("ode", EntryPoint = "dWorldSetQuickStepW"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetQuickStepW(IntPtr world, dReal over_relaxation); [DllImport("ode", EntryPoint = "dWorldSetMaxAngularSpeed"), SuppressUnmanagedCodeSecurity] public static extern void WorldSetMaxAngularSpeed(IntPtr world, dReal max_speed); [DllImport("ode", EntryPoint = "dWorldStep"), SuppressUnmanagedCodeSecurity] public static extern void WorldStep(IntPtr world, dReal stepsize); [DllImport("ode", EntryPoint = "dWorldStepFast1"), SuppressUnmanagedCodeSecurity] public static extern void WorldStepFast1(IntPtr world, dReal stepsize, int maxiterations); } } ode-0.14/contrib/Ode.NET/Ode/premake.lua0000644000000000000000000000104212635011627016335 0ustar rootrootpackage.name = "Ode.NET" package.kind = "dll" package.language = "c#" -- Build options package.defines = { } if (options["with-doubles"]) then table.insert(package.defines, "dDOUBLE") else table.insert(package.defines, "dSINGLE") end if (options["no-unsafe"]) then table.insert(package.defines, "dNO_UNSAFE_CODE") else package.buildflags = { "unsafe" } end -- Files & Libraries package.files = { "AssemblyInfo.cs", "Ode.cs" } package.links = { "System" } ode-0.14/contrib/Ode.NET/README.TXT0000644000000000000000000000476012635011627015047 0ustar rootrootOde.NET - .NET bindings for ODE Jason Perkins (starkos@industriousone.com) --------------------------------------------------------------------- INSTALLATION --------------------------------------------------------------------- This binding uses a C# 2.0 feature (the UnmanagedFunctionPointer attribute). You will need to use Visual Studio 2005 (C# Express is fine) or Mono's gmcs compiler. Start by getting or building ODE as a shared library (DLL). The simplest way to build the bindings is probably to create a new library assembly in your tool of choice and drop in the files Ode/Ode.cs and Ode/AssemblyInfo.cs (optional). Define the symbol `dDOUBLE` if you used double-precision math in your ode.dll. Build, done. For testing purposes, I have also created bindings for the Drawstuff library and a C# version of the BoxStack demo. You can throw all of these files into a console executable and run it to see the demo. If you happen to have Premake installed (http://premake.sf.net/), you can generate build scripts for the library with: premake --target (toolset) # for single precision premake --with-doubles --target (toolset) # for double precision To build the test application too, use: premake --with-tests --target (toolset) To build with Mono, you must add the --dotnet parameter to enable support .NET 2.0: premake --dotnet mono2 --target gnu --------------------------------------------------------------------- USAGE --------------------------------------------------------------------- I have tried to keep things as close to the original C API as I can, rather than forcing a class structure on everyone. Everything is contained within the `Ode.NET` namespace inside a static class named `d`. All ODE IDs are replaced with IntPtrs. A quick example: using Ode.NET; IntPtr world = d.WorldCreate(); IntPtr body = d.BodyCreate(world); Take a look at Tests/BoxStack.cs for a more complete example. --------------------------------------------------------------------- KNOWN ISSUES --------------------------------------------------------------------- While I managed to map most of the API, there may still be some bits missing. If you find something, please submit a bug report or patch the Tracker on SourceForge. Collision response (contact joints) do not work when built under Mono as double-precision. I have not tried to track down why. ode-0.14/contrib/Ode.NET/Tests/0000775000000000000000000000000012635012023014575 5ustar rootrootode-0.14/contrib/Ode.NET/Tests/BoxStack.cs0000644000000000000000000001622312635011627016655 0ustar rootrootusing System; using System.Collections.Generic; using Drawstuff.NET; namespace Ode.NET { #if dDOUBLE using dReal = System.Double; #else using dReal = System.Single; #endif public class TestBoxStack { #region Description of convex shape static dReal[] planes = { 1.0f, 0.0f, 0.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f, 0.25f, 0.0f, 0.0f, -1.0f, 0.25f, 0.0f, -1.0f, 0.0f, 0.25f, -1.0f, 0.0f , 0.0f, 0.25f }; static dReal[] points = { 0.25f, 0.25f, 0.25f, -0.25f, 0.25f, 0.25f, 0.25f, -0.25f, 0.25f, -0.25f, -0.25f, 0.25f, 0.25f, 0.25f, -0.25f, -0.25f,0.25f,-0.25f, 0.25f,-0.25f,-0.25f, -0.25f,-0.25f,-0.25f, }; static int[] polygons = { 4, 0, 2, 6, 4, 4, 1, 0, 4, 5, 4, 0, 1, 3, 2, 4, 3, 1, 5, 7, 4, 2, 3, 7, 6, 4, 5, 4, 6, 7, }; #endregion const int NUM = 100; const float DENSITY = 5.0f; const int MAX_CONTACTS = 8; static IntPtr world; static IntPtr space; static IntPtr contactgroup; static Queue obj = new Queue(); static d.Vector3 xyz = new d.Vector3(2.1640f, -1.3079f, 1.7600f); static d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f); static d.NearCallback nearCallback = near; static d.ContactGeom[] contacts = new d.ContactGeom[MAX_CONTACTS]; static d.Contact contact; // Called when window is opened - sets up viewpoint and prints usage static void start(int unused) { ds.SetViewpoint(ref xyz, ref hpr); Console.WriteLine("To drop another object, press:"); Console.WriteLine(" b for box."); Console.WriteLine(" s for sphere."); Console.WriteLine(" c for capsule."); Console.WriteLine(" y for cylinder."); Console.WriteLine(" v for a convex object."); Console.WriteLine(" x for a composite object."); Console.WriteLine("To select an object, press space."); Console.WriteLine("To disable the selected object, press d."); Console.WriteLine("To enable the selected object, press e."); Console.WriteLine("To toggle showing the geom AABBs, press a."); Console.WriteLine("To toggle showing the contact points, press t."); Console.WriteLine("To toggle dropping from random position/orientation, press r."); Console.WriteLine("To save the current state to 'state.dif', press 1."); } // Near callback - creates contact joints static void near(IntPtr space, IntPtr g1, IntPtr g2) { IntPtr b1 = d.GeomGetBody(g1); IntPtr b2 = d.GeomGetBody(g2); if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) return; int count = d.Collide(g1, g2, MAX_CONTACTS, contacts, d.ContactGeom.SizeOf); for (int i = 0; i < count; ++i) { contact.geom = contacts[i]; IntPtr joint = d.JointCreateContact(world, contactgroup, ref contact); d.JointAttach(joint, b1, b2); } } // Adds a new object to the scene - attaches a body to the geom and // sets the initial position and orientation static void addObject(IntPtr geom, d.Mass mass) { // Create a body for this object IntPtr body = d.BodyCreate(world); d.GeomSetBody(geom, body); d.BodySetMass(body, ref mass); obj.Enqueue(geom); // Set the position of the new object d.Matrix3 R; d.BodySetPosition(body, d.RandReal() * 2 - 1, d.RandReal() * 2 - 1, d.RandReal() + 2); d.RFromAxisAndAngle(out R, d.RandReal() * 2 - 1, d.RandReal() * 2 - 1, d.RandReal() * 2 - 1, d.RandReal() * 10 - 5); d.BodySetRotation(body, ref R); // Cap the total number of objects if (obj.Count > NUM) { geom = obj.Dequeue(); body = d.GeomGetBody(geom); d.BodyDestroy(body); d.GeomDestroy(geom); } } // Keyboard callback static void command(int cmd) { IntPtr geom; d.Mass mass; d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f); Char ch = Char.ToLower((Char)cmd); switch ((Char)ch) { case 'b': d.MassSetBox(out mass, DENSITY, sides.X, sides.Y, sides.Z); geom = d.CreateBox(space, sides.X, sides.Y, sides.Z); addObject(geom, mass); break; case 'c': sides.X *= 0.5f; d.MassSetCapsule(out mass, DENSITY, 3, sides.X, sides.Y); geom = d.CreateCapsule(space, sides.X, sides.Y); addObject(geom, mass); break; case 'v': d.MassSetBox(out mass, DENSITY, 0.25f, 0.25f, 0.25f); geom = d.CreateConvex(space, planes, planes.Length / 4, points, points.Length / 3, polygons); addObject(geom, mass); break; } } // Draw an object in the scene static void drawGeom(IntPtr geom) { IntPtr body = d.GeomGetBody(geom); d.Vector3 pos; d.BodyCopyPosition(body, out pos); d.Matrix3 R; d.BodyCopyRotation(body, out R); d.GeomClassID type = d.GeomGetClass(geom); switch (type) { case d.GeomClassID.BoxClass: d.Vector3 sides; d.GeomBoxGetLengths(geom, out sides); ds.DrawBox(ref pos, ref R, ref sides); break; case d.GeomClassID.CapsuleClass: dReal radius, length; d.GeomCapsuleGetParams(geom, out radius, out length); ds.DrawCapsule(ref pos, ref R, length, radius); break; case d.GeomClassID.ConvexClass: ds.DrawConvex(ref pos, ref R, planes, planes.Length / 4, points, points.Length / 3, polygons); break; } } // Called once per frame; updates the scene static void step(int pause) { d.SpaceCollide(space, IntPtr.Zero, nearCallback); if (pause == 0) d.WorldQuickStep(world, 0.02f); d.JointGroupEmpty(contactgroup); ds.SetColor(1.0f, 1.0f, 0.0f); ds.SetTexture(ds.Texture.Wood); foreach (IntPtr geom in obj) { drawGeom(geom); } } static void Main(string[] args) { dInitODE(); // Setup pointers to drawstuff callback functions ds.Functions fn; fn.version = ds.VERSION; fn.start = new ds.CallbackFunction(start); fn.step = new ds.CallbackFunction(step); fn.command = new ds.CallbackFunction(command); fn.stop = null; fn.path_to_textures = "../../../../drawstuff/textures"; if (args.Length > 0) { fn.path_to_textures = args[0]; } // Set up contact response parameters contact.surface.mode = d.ContactFlags.Bounce | d.ContactFlags.SoftCFM; contact.surface.mu = d.Infinity; contact.surface.mu2 = 0.0f; contact.surface.bounce = 0.1f; contact.surface.bounce_vel = 0.1f; contact.surface.soft_cfm = 0.01f; // Initialize the scene world = d.WorldCreate(); space = d.HashSpaceCreate(IntPtr.Zero); contactgroup = d.JointGroupCreate(0); d.WorldSetGravity(world, 0.0f, 0.0f, -0.5f); d.WorldSetCFM(world, 1e-5f); d.WorldSetAutoDisableFlag(world, true); d.WorldSetContactMaxCorrectingVel(world, 0.1f); d.WorldSetContactSurfaceLayer(world, 0.001f); d.CreatePlane(space, 0, 0, 1, 0); // Run the scene ds.SimulationLoop(args.Length, args, 352, 288, ref fn); // Clean up d.JointGroupDestroy(contactgroup); d.SpaceDestroy(space); d.WorldDestroy(world); d.CloseODE(); } } } ode-0.14/contrib/Ode.NET/Tests/premake.lua0000644000000000000000000000071612635011627016737 0ustar rootroot-- This function creates the test packages function maketest(name) package = newpackage() package.name = name package.kind = "exe" package.language = "c#" if (options["with-doubles"]) then package.defines = { "dDOUBLE" } else package.defines = { "dSINGLE " } end package.links = { "System", "Ode.NET", "Drawstuff.NET" } package.files = { name .. ".cs" } end maketest("BoxStack") ode-0.14/contrib/Ode.NET/premake.lua0000644000000000000000000000132312635011627015630 0ustar rootrootproject.name = "Ode.NET" -- Target checking if (target and target ~= "vs2005" and target ~= "gnu") then error("Ode.NET requires a .NET 2.0 compiler") end -- Project options addoption("with-doubles", "Use double instead of float as base numeric type") addoption("with-tests", "Builds the test applications and DrawStuff library") addoption("no-unsafe", "Exclude functions using unsafe code (dBodyGetPosition, etc.)") -- Build settings project.config["Debug"].bindir = "bin/Debug" project.config["Release"].bindir = "bin/Release" -- Packages if (options["with-tests"]) then dopackage("Tests") dopackage("Drawstuff") end dopackage("Ode") ode-0.14/contrib/OdeModelProcessor/0000775000000000000000000000000012635012023015727 5ustar rootrootode-0.14/contrib/OdeModelProcessor/LICENSE-BSD.TXT0000644000000000000000000000336112635011627020032 0ustar rootroot This is the BSD-style license for The ODE Model Processor ---------------------------------------------------------- The ODE Model Processor Copyright (c) 2007, Department Of Information Science, University of Otago, Dunedin, New Zealand. All rights reserved. Author: Richard Barrington Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ode-0.14/contrib/OdeModelProcessor/LICENSE.TXT0000644000000000000000000006347412635011627017437 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ode-0.14/contrib/OdeModelProcessor/OdeModelProcessor.sln0000644000000000000000000000166012635011627022047 0ustar rootroot Microsoft Visual Studio Solution File, Format Version 9.00 # Visual C# Express 2005 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OdeModelProcessor", "OdeModelProcessor\OdeModelProcessor.csproj", "{246F3075-FEE3-45F9-8CB6-47DADBFFD1F2}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {246F3075-FEE3-45F9-8CB6-47DADBFFD1F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {246F3075-FEE3-45F9-8CB6-47DADBFFD1F2}.Debug|Any CPU.Build.0 = Debug|Any CPU {246F3075-FEE3-45F9-8CB6-47DADBFFD1F2}.Release|Any CPU.ActiveCfg = Release|Any CPU {246F3075-FEE3-45F9-8CB6-47DADBFFD1F2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ode-0.14/contrib/OdeModelProcessor/OdeModelProcessor/0000775000000000000000000000000012635012023021317 5ustar rootrootode-0.14/contrib/OdeModelProcessor/OdeModelProcessor/OdeModelProcessor.cs0000644000000000000000000002774512635011627025264 0ustar rootroot/* * The ODE Model Processor * ----------------------- * * Copyright 2007, Department of Information Science, * University of Otago, Dunedin, New Zealand. * * Author: Richard Barrington * * This is a Content Processor and Tag library written for use with * Microsoft Visual C# 2005 Express Edition and Microsoft XNA Game * Studio Express 1.0. * * It can be used to read .x model vertex and index data before * insertion into the content pipeline. This is used to build ODE * Triangle Meshes which are then used for collision detection that * is more accurate than the default XNA bounding boxes or spheres. * * Usage is simple: * Build the library and reference the DLL in your project. * Add the DLL to the Content Pipeline * Set the content processor for you .x models to OdeModelProcessor. * * Create triangle meshes as follows: * 1) Create a space, but only one for all of models. * 2) Create a triangle data. * 3) Load the model. * 4) Retreive the tag from the model. * 6) Build the triangle mesh by calling d.GeomTriMeshDataBuildSimple. * * Eg: * IntPtr space = d.SimpleSpaceCreate(IntPtr.Zero); * IntPtr triangleData = d.GeomTriMeshDataCreate(); * Model obj = content.Load("Content\\mycube"); * OdeTag tag = (OdeTag)obj.Tag; * IntPtr vertexArray = tag.getVertices(); * IntPtr indexArray = tag.getIndices(); * d.GeomTriMeshDataBuildSimple * ( * triangleData, * vertexArray, tag.getVertexStride(), tag.getVertexCount(), * indexArray, tag.getIndexCount(), tag.getIndexStride() * ); * IntPtr triangleMesh = d.CreateTriMesh(space, triangleData, null, null, null); * * You can load multiple models and test for collisions with something * like this in the update method: * * d.GeomSetPosition(odeTri1, obj1Position.X, obj1Position.Y, obj1Position.Z); * d.GeomSetPosition(odeTri2, obj2Position.X, obj2Position.Y, obj2Position.Z); * int numberOfContacts = d.Collide(odeTri1, odeTri2, ODE_CONTACTS, * contactGeom, d.ContactGeom.SizeOf); * * Where odeTri1 and odeTri2 are triangle meshes you've created, obj1Position * and obj2Position are the positions of your rendered models in the scene, * ODE_CONTACTS is a constant defining the maximum number of contacts * to test for, contactGeom is a d.ContactGeom[] of length ODE_CONTACTS. * * If numberOfContacts is greater than 0, you have a collision. * * Other ODE functions such as d.SpaceCollide() also work; see ODE.NET BoxTest.cs. * * This library is free software; you can redistribute it and/or * modify it under the same terms as the ODE and ODE.Net libraries. * Specifically, the terms are one of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at * your option) any later version. The text of the GNU Lesser * General Public License is included with this library in the * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * the file LICENSE-BSD.TXT. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * LICENSE.TXT and LICENSE-BSD.TXT for more details. * */ using System; using System.Collections.Generic; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Design; using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Content.Pipeline.Graphics; using Microsoft.Xna.Framework.Content.Pipeline.Processors; using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; using Ode.NET; using System.Runtime.InteropServices; namespace OdeModelProcessor { /* * Container for vertex and index data in a format * that ODE.Net can use */ public class OdeTag { private float[] vertexData; private int[] indexData; private const int indexStride = (sizeof(int)); private const int vertexStride = (3 * sizeof(float)); /* Constructors */ public OdeTag() { vertexData = new float[0]; indexData = new int[0]; } public OdeTag(float[] vertexData, int[] indexData) { this.vertexData = vertexData; this.indexData = indexData; } /* Data setter */ public void setData(float[] vertexData, int[] indexData) { this.vertexData = vertexData; this.indexData = indexData; } /* Data appenders */ public void appendVertexData(float[] vertexData) { int newVertexDataLength = vertexData.Length; float[] tempVertexArray = new float[newVertexDataLength + this.vertexData.Length]; this.vertexData.CopyTo(tempVertexArray, 0); vertexData.CopyTo(tempVertexArray, this.vertexData.Length); this.vertexData = tempVertexArray; } public void appendIndexData(int[] indexData) { int newIndexDataLength = indexData.Length; int[] tempIndexArray = new int[newIndexDataLength + this.indexData.Length]; this.indexData.CopyTo(tempIndexArray, 0); indexData.CopyTo(tempIndexArray, this.indexData.Length); this.indexData = tempIndexArray; } /* Data getters */ public float[] getVertexData() { return this.vertexData; } public int[] getIndexData() { return this.indexData; } /* Native data getters */ public IntPtr getVertices() { int count = getVertexData().Length; int memsize = count * Marshal.SizeOf(getVertexData()[0].GetType()); IntPtr pointer = Marshal.AllocCoTaskMem(memsize); Marshal.Copy(getVertexData(), 0, pointer, count); return pointer; } public IntPtr getIndices() { int count = getIndexData().Length; int memsize = count * Marshal.SizeOf(getIndexData()[0].GetType()); IntPtr pointer = Marshal.AllocCoTaskMem(memsize); Marshal.Copy(getIndexData(), 0, pointer, count); return pointer; } /* Count getters */ public int getVertexCount() { return vertexData.Length/3; } public int getIndexCount() { return indexData.Length; } /* Stride getters */ public int getVertexStride() { return vertexStride; } public int getIndexStride() { return indexStride; } /* * Convienience method to build the mesh and return it. The triangleData * is passed in to allow the calling application to delete it afterwards. * * Be sure to destroy the returned TriangleMesh in the client application. * * Can't destroy the index and vertex arrays here though, so best to handle * this manually - only use this method if nothing else makes sense. */ public IntPtr getTriangleMesh(IntPtr space, IntPtr triangleData) { d.GeomTriMeshDataBuildSimple( triangleData, getVertices(), getVertexStride(), getVertexCount(), getIndices(), getIndexCount(), getIndexStride() ); return d.CreateTriMesh(space, triangleData, null, null, null); } } /* * Subclass of the XNA .x model processor, which creates and appends a tag * containing vertex and index data for ODE.Net to use. */ [ContentProcessor] public class OdeModelProcessor : ModelProcessor { private OdeTag tag; private int indexOffset = 0; public override ModelContent Process(NodeContent input, ContentProcessorContext context) { tag = new OdeTag(); GenerateVerticesRecursive( input ); ModelContent model = base.Process(input, context); model.Tag = tag; indexOffset = 0; return model; } public void GenerateVerticesRecursive(NodeContent input) { MeshContent mesh = input as MeshContent; if (mesh != null) { GeometryContentCollection gc = mesh.Geometry; foreach (GeometryContent g in gc) { VertexContent vc = g.Vertices; IndirectPositionCollection ipc = vc.Positions; IndexCollection ic = g.Indices; float[] vertexData = new float[ipc.Count * 3]; for (int i = 0; i < ipc.Count; i++) { Vector3 v0 = ipc[i]; vertexData[(i * 3) + 0] = v0.X; vertexData[(i * 3) + 1] = v0.Y; vertexData[(i * 3) + 2] = v0.Z; } int[] indexData = new int[ic.Count]; for (int j = 0; j < ic.Count; j ++) { indexData[j] = ic[j] + indexOffset; } tag.appendVertexData(vertexData); tag.appendIndexData(indexData); indexOffset += ipc.Count; } } foreach (NodeContent child in input.Children) { GenerateVerticesRecursive(child); } } } /* Writer for the OdeTag class */ [ContentTypeWriter] public class OdeTagWriter : ContentTypeWriter { protected override void Write(ContentWriter output, OdeTag value) { float[] vertexData = value.getVertexData(); int[] indexData = value.getIndexData(); output.Write(vertexData.Length); output.Write(indexData.Length); for (int j = 0; j < vertexData.Length; j++) { output.Write(vertexData[j]); } for (int i = 0; i < indexData.Length; i++) { output.Write(indexData[i]); } } public override string GetRuntimeType(TargetPlatform targetPlatform) { return typeof(OdeTag).AssemblyQualifiedName; } public override string GetRuntimeReader(TargetPlatform targetPlatform) { return "OdeModelProcessor.OdeTagReader, OdeModelProcessor, Version=1.0.0.0, Culture=neutral"; } } /* Reader for the OdeTag class */ public class OdeTagReader : ContentTypeReader { protected override OdeTag Read(ContentReader input, OdeTag existingInstance) { float[] vertexData = new float[input.ReadInt32()]; int[] indexData = new int[input.ReadInt32()]; for (int j = 0; j < vertexData.Length; j++) { vertexData[j] = input.ReadSingle(); } for (int i = 0; i < indexData.Length; i++) { indexData[i] = input.ReadInt32(); } OdeTag tag = null; if (existingInstance == null) { tag = new OdeTag(vertexData, indexData); } else { tag = existingInstance; tag.setData(vertexData, indexData); } return tag; } } } ode-0.14/contrib/OdeModelProcessor/OdeModelProcessor/OdeModelProcessor.csproj0000644000000000000000000000613412635011627026144 0ustar rootroot Debug AnyCPU 8.0.50727 2.0 {246F3075-FEE3-45F9-8CB6-47DADBFFD1F2} Library Properties OdeModelProcessor OdeModelProcessor true full false bin\Debug\ DEBUG prompt 4 false false pdbonly true bin\Release\ prompt 4 false false False ..\..\ODE\Ode.NET-0.8\bin\Release\Ode.NET.dll True True Settings.settings SettingsSingleFileGenerator Settings.Designer.cs ode-0.14/contrib/OdeModelProcessor/OdeModelProcessor/Properties/0000775000000000000000000000000012635012023023453 5ustar rootrootode-0.14/contrib/OdeModelProcessor/OdeModelProcessor/Properties/AssemblyInfo.cs0000644000000000000000000000257512635011627026415 0ustar rootrootusing System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("OdeModelProcessor")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("OdeModelProcessor")] [assembly: AssemblyCopyright("Copyright © 2007")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("29c5609a-cd5f-480b-b4ef-5c11de022268")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ode-0.14/contrib/OdeModelProcessor/OdeModelProcessor/Properties/Settings.Designer.cs0000755000000000000000000000211112635011627027346 0ustar rootroot//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:2.0.50727.832 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace OdeModelProcessor.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { get { return defaultInstance; } } } } ode-0.14/contrib/OdeModelProcessor/OdeModelProcessor/Properties/Settings.settings0000755000000000000000000000035112635011627027046 0ustar rootroot ode-0.14/contrib/OdeModelProcessor/README.TXT0000644000000000000000000000624112635011627017277 0ustar rootrootThe ODE Model Processor ----------------------- Copyright 2007, Department of Information Science, University of Otago, Dunedin, New Zealand. Author: Richard Barrington This is a Content Processor and Tag library written for use with Microsoft Visual C# 2005 Express Edition and Microsoft XNA Game Studio Express 1.0. It can be used to read .x model vertex and index data before insertion into the content pipeline. This is used to build ODE Triangle Meshes which are then used for collision detection that is more accurate than the default XNA bounding boxes or spheres. Usage is fairly simple: Build the library and reference the DLL in your project. Add the DLL to the Content Pipeline Set the content processor for you .x models to OdeModelProcessor. Create triangle meshes as follows: 1) Create a space, but only one for all of models. 2) Create a triangle data. 3) Load the model. 4) Retreive the tag from the model. 6) Build the triangle mesh by calling d.GeomTriMeshDataBuildSimple. Eg: IntPtr space = d.SimpleSpaceCreate(IntPtr.Zero); IntPtr triangleData = d.GeomTriMeshDataCreate(); Model obj = content.Load("Content\\mycube"); OdeTag tag = (OdeTag)obj.Tag; IntPtr vertexArray = tag.getVertices(); IntPtr indexArray = tag.getIndices(); d.GeomTriMeshDataBuildSimple ( triangleData, vertexArray, tag.getVertexStride(), tag.getVertexCount(), indexArray, tag.getIndexCount(), tag.getIndexStride() ); IntPtr triangleMesh = d.CreateTriMesh(space, triangleData, null, null, null); You can load multiple models and test for collisions with something like this in the update method: d.GeomSetPosition(odeTri1, obj1Position.X, obj1Position.Y, obj1Position.Z); d.GeomSetPosition(odeTri2, obj2Position.X, obj2Position.Y, obj2Position.Z); int numberOfContacts = d.Collide(odeTri1, odeTri2, ODE_CONTACTS, contactGeom, d.ContactGeom.SizeOf); Where odeTri1 and odeTri2 are triangle meshes you've created, obj1Position and obj2Position are the positions of your rendered models in the scene, ODE_CONTACTS is a constant defining the maximum number of contacts to test for, contactGeom is a d.ContactGeom[] of length ODE_CONTACTS. If numberOfContacts is greater than 0, you have a collision. Other ODE functions such as d.SpaceCollide() also work; see ODE.NET BoxTest.cs. This library is free software; you can redistribute it and/or modify it under the same terms as the ODE and ODE.Net libraries. Specifically, the terms are one of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file LICENSE.TXT. (2) The BSD-style license that is included with this library in the file LICENSE-BSD.TXT. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files LICENSE.TXT and LICENSE-BSD.TXT for more details. ode-0.14/contrib/README0000644000000000000000000000124312635011627013226 0ustar rootrootThis directory contains ODE-related things that have been generously contributed by ODE's users. Why is this stuff here and not integrated into the main ODE source tree? There may be several reasons: * The author(s) and ODE maintainers(s) may not have had time to do the job. * It may not be finished. * It may contribute functionality that is useful but not considered to be part of ODE's core. No guarantees are made about the code in this directory - it may not be documented, it may not have been tested, and it may not even compile for you. Each package has its own subdirectory, with a README file in that directory explaining what the package is. ode-0.14/contrib/TerrainAndCone/0000775000000000000000000000000012635012023015173 5ustar rootrootode-0.14/contrib/TerrainAndCone/collision_std_internal.h0000644000000000000000000000507512635011627022123 0ustar rootroot//Benoit CHAPEROT 2003-2004 www.jstarlab.com #ifndef _ODE_COLLISION_STD_INTERNAL_H_ #define _ODE_COLLISION_STD_INTERNAL_H_ #include #include "collision_kernel.h" struct dxSphere : public dxGeom { dReal radius; // sphere radius dxSphere (dSpaceID space, dReal _radius); void computeAABB(); }; struct dxBox : public dxGeom { dVector3 side; // side lengths (x,y,z) dxBox (dSpaceID space, dReal lx, dReal ly, dReal lz); void computeAABB(); }; struct dxCCylinder : public dxGeom { dReal radius,lz; // radius, length along z axis dxCCylinder (dSpaceID space, dReal _radius, dReal _length); void computeAABB(); }; struct dxPlane : public dxGeom { dReal p[4]; dxPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d); void computeAABB(); }; struct dxCylinder : public dxGeom { dReal radius,lz; // radius, length along z axis dxCylinder (dSpaceID space, dReal _radius, dReal _length); void computeAABB(); }; struct dxCone : public dxGeom { dReal radius,lz; dxCone(dSpaceID space, dReal _radius,dReal _length); ~dxCone(); void computeAABB(); }; struct dxRay : public dxGeom { dReal length; dxRay (dSpaceID space, dReal _length); void computeAABB(); }; struct dxTerrainY : public dxGeom { dReal m_vLength; dReal *m_pHeights; dReal m_vMinHeight; dReal m_vMaxHeight; dReal m_vNodeLength; int m_nNumNodesPerSide; int m_nNumNodesPerSideShift; int m_nNumNodesPerSideMask; int m_bFinite; dxTerrainY(dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable); ~dxTerrainY(); void computeAABB(); dReal GetHeight(dReal x,dReal z); dReal GetHeight(int x,int z); int dCollideTerrainUnit(int x,int z,dxGeom *o2,int numMaxContacts,int flags,dContactGeom *contact, int skip); bool IsOnTerrain(int nx,int nz,int w,dReal *pos); }; struct dxTerrainZ : public dxGeom { dReal m_vLength; dReal *m_pHeights; dReal m_vMinHeight; dReal m_vMaxHeight; dReal m_vNodeLength; int m_nNumNodesPerSide; int m_nNumNodesPerSideShift; int m_nNumNodesPerSideMask; int m_bFinite; dxTerrainZ(dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable); ~dxTerrainZ(); void computeAABB(); dReal GetHeight(dReal x,dReal y); dReal GetHeight(int x,int y); int dCollideTerrainUnit(int x,int y,dxGeom *o2,int numMaxContacts,int flags,dContactGeom *contact, int skip); bool IsOnTerrain(int nx,int ny,int w,dReal *pos); }; #ifndef MIN #define MIN(a,b) ((ab)?a:b) #endif #endif //_ODE_COLLISION_STD_INTERNAL_H_ode-0.14/contrib/TerrainAndCone/dCone.cpp0000644000000000000000000003136212635011627016743 0ustar rootroot//Benoit CHAPEROT 2003-2004 www.jstarlab.com //some code inspired by Magic Software #include #include #include #include #include #include "collision_kernel.h" #include "collision_std.h" #include "collision_std_internal.h" #include "collision_util.h" #include #include "windows.h" #include "ode\ode.h" #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) const dReal fEPSILON = 1e-9f; dxCone::dxCone (dSpaceID space, dReal _radius,dReal _length) : dxGeom (space,1) { dAASSERT(_radius > 0.f); dAASSERT(_length > 0.f); type = dConeClass; radius = _radius; lz = _length; } dxCone::~dxCone() { } void dxCone::computeAABB() { const dMatrix3& R = final_posr->R; const dVector3& pos = final_posr->pos; dReal xrange = dFabs(R[2] * lz) + radius; dReal yrange = dFabs(R[6] * lz) + radius; dReal zrange = dFabs(R[10] * lz) + radius; aabb[0] = pos[0] - xrange; aabb[1] = pos[0] + xrange; aabb[2] = pos[1] - yrange; aabb[3] = pos[1] + yrange; aabb[4] = pos[2] - zrange; aabb[5] = pos[2] + zrange; } dGeomID dCreateCone(dSpaceID space, dReal _radius,dReal _length) { return new dxCone(space,_radius,_length); } void dGeomConeSetParams (dGeomID g, dReal _radius, dReal _length) { dUASSERT (g && g->type == dConeClass,"argument not a cone"); dAASSERT (_radius > 0.f); dAASSERT (_length > 0.f); g->recomputePosr(); dxCone *c = (dxCone*) g; c->radius = _radius; c->lz = _length; dGeomMoved (g); } void dGeomConeGetParams (dGeomID g, dReal *_radius, dReal *_length) { dUASSERT (g && g->type == dConeClass,"argument not a cone"); g->recomputePosr(); dxCone *c = (dxCone*) g; *_radius = c->radius; *_length = c->lz; } //positive inside dReal dGeomConePointDepth(dGeomID g, dReal x, dReal y, dReal z) { dUASSERT (g && g->type == dConeClass,"argument not a cone"); g->recomputePosr(); dxCone *cone = (dxCone*) g; dVector3 tmp,q; tmp[0] = x - cone->final_posr->pos[0]; tmp[1] = y - cone->final_posr->pos[1]; tmp[2] = z - cone->final_posr->pos[2]; dMULTIPLY1_331 (q,cone->final_posr->R,tmp); dReal r = cone->radius; dReal h = cone->lz; dReal d0 = (r - r*q[2]/h) - dSqrt(q[0]*q[0]+q[1]*q[1]); dReal d1 = q[2]; dReal d2 = h-q[2]; if (d0 < d1) { if (d0 < d2) return d0; else return d2; } else { if (d1 < d2) return d1; else return d2; } } //plane plane bool FindIntersectionPlanePlane(const dReal Plane0[4], const dReal Plane1[4], dVector3 LinePos,dVector3 LineDir) { // If Cross(N0,N1) is zero, then either planes are parallel and separated // or the same plane. In both cases, 'false' is returned. Otherwise, // the intersection line is // // L(t) = t*Cross(N0,N1) + c0*N0 + c1*N1 // // for some coefficients c0 and c1 and for t any real number (the line // parameter). Taking dot products with the normals, // // d0 = Dot(N0,L) = c0*Dot(N0,N0) + c1*Dot(N0,N1) // d1 = Dot(N1,L) = c0*Dot(N0,N1) + c1*Dot(N1,N1) // // which are two equations in two unknowns. The solution is // // c0 = (Dot(N1,N1)*d0 - Dot(N0,N1)*d1)/det // c1 = (Dot(N0,N0)*d1 - Dot(N0,N1)*d0)/det // // where det = Dot(N0,N0)*Dot(N1,N1)-Dot(N0,N1)^2. /* Real fN00 = rkPlane0.Normal().SquaredLength(); Real fN01 = rkPlane0.Normal().Dot(rkPlane1.Normal()); Real fN11 = rkPlane1.Normal().SquaredLength(); Real fDet = fN00*fN11 - fN01*fN01; if ( Math::FAbs(fDet) < gs_fEpsilon ) return false; Real fInvDet = 1.0f/fDet; Real fC0 = (fN11*rkPlane0.Constant() - fN01*rkPlane1.Constant())*fInvDet; Real fC1 = (fN00*rkPlane1.Constant() - fN01*rkPlane0.Constant())*fInvDet; rkLine.Direction() = rkPlane0.Normal().Cross(rkPlane1.Normal()); rkLine.Origin() = fC0*rkPlane0.Normal() + fC1*rkPlane1.Normal(); return true; */ dReal fN00 = dLENGTHSQUARED(Plane0); dReal fN01 = dDOT(Plane0,Plane1); dReal fN11 = dLENGTHSQUARED(Plane1); dReal fDet = fN00*fN11 - fN01*fN01; if ( fabs(fDet) < fEPSILON) return false; dReal fInvDet = 1.0f/fDet; dReal fC0 = (fN11*Plane0[3] - fN01*Plane1[3])*fInvDet; dReal fC1 = (fN00*Plane1[3] - fN01*Plane0[3])*fInvDet; dCROSS(LineDir,=,Plane0,Plane1); dNormalize3(LineDir); dVector3 Temp0,Temp1; dOPC(Temp0,*,Plane0,fC0); dOPC(Temp1,*,Plane1,fC1); dOP(LinePos,+,Temp0,Temp1); return true; } //plane ray bool FindIntersectionPlaneRay(const dReal Plane[4], const dVector3 &LinePos,const dVector3 &LineDir, dReal &u,dVector3 &Pos) { /* u = (A*X1 + B*Y1 + C*Z1 + D) / (A*(X1-X2) + B*(Y1-Y2)+C*(Z1-Z2)) */ dReal fDet = -dDot(Plane,LineDir,3); if ( fabs(fDet) < fEPSILON) return false; u = (dDot(Plane,LinePos,3) - Plane[3]) / fDet; dOPC(Pos,*,LineDir,u); dOPE(Pos,+=,LinePos); return true; } int SolveQuadraticPolynomial(dReal a,dReal b,dReal c,dReal &x0,dReal &x1) { dReal d = b*b - 4*a*c; int NumRoots = 0; dReal dr; if (d < 0.f) return NumRoots; if (d == 0.f) { NumRoots = 1; dr = 0.f; } else { NumRoots = 2; dr = sqrtf(d); } x0 = (-b -dr) / (2.f * a); x1 = (-b +dr) / (2.f * a); return NumRoots; } /* const int VALID_INTERSECTION = 1<<0; const int POS_TEST_FAILEDT0 = 1<<0; const int POS_TEST_FAILEDT1 = 1<<1; */ int ProcessConeRayIntersectionPoint( dReal r,dReal h, const dVector3 &q,const dVector3 &v,dReal t, dVector3 &p, dVector3 &n, int &f) { dOPC(p,*,v,t); dOPE(p,+=,q); n[0] = 2*p[0]; n[1] = 2*p[1]; n[2] = -2*p[2]*r*r/(h*h); f = 0; if (p[2] > h) return 0; if (p[2] < 0) return 0; if (t > 1) return 0; if (t < 0) return 0; return 1; } //cone ray //line in cone space (position,direction) //distance from line position (direction normalized)(if any) //return the number of intersection int FindIntersectionConeRay(dReal r,dReal h, const dVector3 &q,const dVector3 &v,dContactGeom *pContact) { dVector3 qp,vp; dOPE(qp,=,q); dOPE(vp,=,v); qp[2] = h-q[2]; vp[2] = -v[2]; dReal ts = (r/h); ts *= ts; dReal a = vp[0]*vp[0] + vp[1]*vp[1] - ts*vp[2]*vp[2]; dReal b = 2.f*qp[0]*vp[0] + 2.f*qp[1]*vp[1] - 2.f*ts*qp[2]*vp[2]; dReal c = qp[0]*qp[0] + qp[1]*qp[1] - ts*qp[2]*qp[2]; /* dReal a = v[0]*v[0] + v[1]*v[1] - (v[2]*v[2]*r*r) / (h*h); dReal b = 2.f*q[0]*v[0] + 2.f*q[1]*v[1] + 2.f*r*r*v[2]/h - 2*r*r*q[0]*v[0]/(h*h); dReal c = q[0]*q[0] + q[1]*q[1] + 2*r*r*q[2]/h - r*r*q[2]/(h*h) - r*r; */ int nNumRoots=SolveQuadraticPolynomial(a,b,c,pContact[0].depth,pContact[1].depth); int flag = 0; dContactGeom ValidContact[2]; int nNumValidContacts = 0; for (int i=0;i=0) && (d<=1)) { dOPC(vp,*,v,d); dOP(qp,+,q,vp); if (qp[0]*qp[0]+qp[1]*qp[1] < r*r) { dOPE(ValidContact[nNumValidContacts].pos,=,qp); ValidContact[nNumValidContacts].normal[0] = 0.f; ValidContact[nNumValidContacts].normal[1] = 0.f; ValidContact[nNumValidContacts].normal[2] = -1.f; ValidContact[nNumValidContacts].depth = d; nNumValidContacts++; } } } if (nNumValidContacts == 2) { if (ValidContact[0].depth > ValidContact[1].depth) { pContact[0] = ValidContact[1]; pContact[1] = ValidContact[0]; } else { pContact[0] = ValidContact[0]; pContact[1] = ValidContact[1]; } } else if (nNumValidContacts == 1) { pContact[0] = ValidContact[0]; } return nNumValidContacts; } int dCollideConePlane (dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dConeClass); dIASSERT (o2->type == dPlaneClass); dxCone *cone = (dxCone*) o1; dxPlane *plane = (dxPlane*) o2; contact->g1 = o1; contact->g2 = o2; dVector3 p0,p1,pp0,pp1; dOPE(p0,=,cone->final_posr->pos); p1[0] = cone->final_posr->R[0*4+2] * cone->lz + p0[0]; p1[1] = cone->final_posr->R[1*4+2] * cone->lz + p0[1]; p1[2] = cone->final_posr->R[2*4+2] * cone->lz + p0[2]; dReal u; FindIntersectionPlaneRay(plane->p,p0,plane->p,u,pp0); FindIntersectionPlaneRay(plane->p,p1,plane->p,u,pp1); if (dDISTANCE(pp0,pp1) < fEPSILON) { p1[0] = cone->final_posr->R[0*4+0] * cone->lz + p0[0]; p1[1] = cone->final_posr->R[1*4+0] * cone->lz + p0[1]; p1[2] = cone->final_posr->R[2*4+0] * cone->lz + p0[2]; FindIntersectionPlaneRay(plane->p,p1,plane->p,u,pp1); dIASSERT(dDISTANCE(pp0,pp1) >= fEPSILON); } dVector3 h,r0,r1; h[0] = cone->final_posr->R[0*4+2]; h[1] = cone->final_posr->R[1*4+2]; h[2] = cone->final_posr->R[2*4+2]; dOP(r0,-,pp0,pp1); dCROSS(r1,=,h,r0); dCROSS(r0,=,r1,h); dNormalize3(r0); dOPEC(h,*=,cone->lz); dOPEC(r0,*=,cone->radius); dVector3 p[3]; dOP(p[0],+,cone->final_posr->pos,h); dOP(p[1],+,cone->final_posr->pos,r0); dOP(p[2],-,cone->final_posr->pos,r0); int numMaxContacts = flags & 0xffff; if (numMaxContacts == 0) numMaxContacts = 1; int n=0; for (int i=0;i<3;i++) { dReal d = dGeomPlanePointDepth(o2, p[i][0], p[i][1], p[i][2]); if (d>0.f) { CONTACT(contact,n*skip)->g1 = o1; CONTACT(contact,n*skip)->g2 = o2; dOPE(CONTACT(contact,n*skip)->normal,=,plane->p); dOPE(CONTACT(contact,n*skip)->pos,=,p[i]); CONTACT(contact,n*skip)->depth = d; n++; if (n == numMaxContacts) return n; } } return n; } int dCollideRayCone (dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dRayClass); dIASSERT (o2->type == dConeClass); dxRay *ray = (dxRay*) o1; dxCone *cone = (dxCone*) o2; contact->g1 = o1; contact->g2 = o2; dVector3 tmp,q,v; tmp[0] = ray->final_posr->pos[0] - cone->final_posr->pos[0]; tmp[1] = ray->final_posr->pos[1] - cone->final_posr->pos[1]; tmp[2] = ray->final_posr->pos[2] - cone->final_posr->pos[2]; dMULTIPLY1_331 (q,cone->final_posr->R,tmp); tmp[0] = ray->final_posr->R[0*4+2] * ray->length; tmp[1] = ray->final_posr->R[1*4+2] * ray->length; tmp[2] = ray->final_posr->R[2*4+2] * ray->length; dMULTIPLY1_331 (v,cone->final_posr->R,tmp); dReal r = cone->radius; dReal h = cone->lz; dContactGeom Contact[2]; if (FindIntersectionConeRay(r,h,q,v,Contact)) { dMULTIPLY0_331(contact->normal,cone->final_posr->R,Contact[0].normal); dMULTIPLY0_331(contact->pos,cone->final_posr->R,Contact[0].pos); dOPE(contact->pos,+=,cone->final_posr->pos); contact->depth = Contact[0].depth * dLENGTH(v); /* dMatrix3 RI; dRSetIdentity (RI); dVector3 ss; ss[0] = 0.01f; ss[1] = 0.01f; ss[2] = 0.01f; dsSetColorAlpha (1,0,0,0.8f); dsDrawBox(contact->pos,RI,ss); */ return 1; } return 0; } int dCollideConeSphere(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dConeClass); dIASSERT (o2->type == dSphereClass); dxCone *cone = (dxCone*) o1; dxSphere ASphere(0,cone->radius); dGeomSetRotation(&ASphere,cone->final_posr->R); dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]); return dCollideSphereSphere(&ASphere, o2, flags, contact, skip); } int dCollideConeBox(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dConeClass); dIASSERT (o2->type == dBoxClass); dxCone *cone = (dxCone*) o1; dxSphere ASphere(0,cone->radius); dGeomSetRotation(&ASphere,cone->final_posr->R); dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]); return dCollideSphereBox(&ASphere, o2, flags, contact, skip); } int dCollideCCylinderCone(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dCCylinderClass); dIASSERT (o2->type == dConeClass); dxCone *cone = (dxCone*) o2; dxSphere ASphere(0,cone->radius); dGeomSetRotation(&ASphere,cone->final_posr->R); dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]); return dCollideCCylinderSphere(o1, &ASphere, flags, contact, skip); } extern int dCollideSTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); int dCollideTriMeshCone(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dTriMeshClass); dIASSERT (o2->type == dConeClass); dxCone *cone = (dxCone*) o2; dxSphere ASphere(0,cone->radius); dGeomSetRotation(&ASphere,cone->final_posr->R); dGeomSetPosition(&ASphere,cone->final_posr->pos[0],cone->final_posr->pos[1],cone->final_posr->pos[2]); return dCollideSTL(o1, &ASphere, flags, contact, skip); } ode-0.14/contrib/TerrainAndCone/dTerrainY.cpp0000644000000000000000000004125212635011627017613 0ustar rootroot//Benoit CHAPEROT 2003-2004 www.jstarlab.com //some code inspired by Magic Software #include #include #include #include #include #include "collision_kernel.h" #include "collision_std.h" #include "collision_std_internal.h" #include "collision_util.h" //#include #include "windows.h" #include "ode\ode.h" #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) #define MAXCONTACT 10 #define TERRAINTOL 0.0f static bool IsAPowerOfTwo(int f) { dAASSERT(f!=0); while ((f&1) != 1) f >>= 1; return (f == 1); } static int GetPowerOfTwo(int f) { dAASSERT(f!=0); int n = 0; while ((f&1) != 1) { n++; f >>= 1; } return n; } dxTerrainY::dxTerrainY (dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable) : dxGeom (space,bPlaceable) { dIASSERT(IsAPowerOfTwo(nNumNodesPerSide)); dIASSERT(pHeights); dIASSERT(vLength > 0.f); dIASSERT(nNumNodesPerSide > 0); type = dTerrainYClass; m_vLength = vLength; m_pHeights = new dReal[nNumNodesPerSide * nNumNodesPerSide]; dIASSERT(m_pHeights); m_nNumNodesPerSide = nNumNodesPerSide; m_vNodeLength = m_vLength / m_nNumNodesPerSide; m_nNumNodesPerSideShift = GetPowerOfTwo(m_nNumNodesPerSide); m_nNumNodesPerSideMask = m_nNumNodesPerSide - 1; m_vMinHeight = dInfinity; m_vMaxHeight = -dInfinity; m_bFinite = bFinite; for (int i=0;i m_vMaxHeight) m_vMaxHeight = m_pHeights[i]; } } dxTerrainY::~dxTerrainY() { dIASSERT(m_pHeights); delete [] m_pHeights; } void dxTerrainY::computeAABB() { if (m_bFinite) { if (gflags & GEOM_PLACEABLE) { dReal dx[6],dy[6],dz[6]; dx[0] = 0; dx[1] = final_posr->R[0] * m_vLength; dx[2] = final_posr->R[1] * m_vMinHeight; dx[3] = final_posr->R[1] * m_vMaxHeight; dx[4] = 0; dx[5] = final_posr->R[2] * m_vLength; dy[0] = 0; dy[1] = final_posr->R[4] * m_vLength; dy[2] = final_posr->R[5] * m_vMinHeight; dy[3] = final_posr->R[5] * m_vMaxHeight; dy[4] = 0; dy[5] = final_posr->R[6] * m_vLength; dz[0] = 0; dz[1] = final_posr->R[8] * m_vLength; dz[2] = final_posr->R[9] * m_vMinHeight; dz[3] = final_posr->R[9] * m_vMaxHeight; dz[4] = 0; dz[5] = final_posr->R[10] * m_vLength; aabb[0] = final_posr->pos[0] + MIN(dx[0],dx[1]) + MIN(dx[2],dx[3]) + MIN(dx[4],dx[5]); aabb[1] = final_posr->pos[0] + MAX(dx[0],dx[1]) + MAX(dx[2],dx[3]) + MAX(dx[4],dx[5]); aabb[2] = final_posr->pos[1] + MIN(dy[0],dy[1]) + MIN(dy[2],dy[3]) + MIN(dy[4],dy[5]); aabb[3] = final_posr->pos[1] + MAX(dy[0],dy[1]) + MAX(dy[2],dy[3]) + MAX(dy[4],dy[5]); aabb[4] = final_posr->pos[2] + MIN(dz[0],dz[1]) + MIN(dz[2],dz[3]) + MIN(dz[4],dz[5]); aabb[5] = final_posr->pos[2] + MAX(dz[0],dz[1]) + MAX(dz[2],dz[3]) + MAX(dz[4],dz[5]); } else { aabb[0] = 0; aabb[1] = m_vLength; aabb[2] = m_vMinHeight; aabb[3] = m_vMaxHeight; aabb[4] = 0; aabb[5] = m_vLength; } } else { if (gflags & GEOM_PLACEABLE) { aabb[0] = -dInfinity; aabb[1] = dInfinity; aabb[2] = -dInfinity; aabb[3] = dInfinity; aabb[4] = -dInfinity; aabb[5] = dInfinity; } else { aabb[0] = -dInfinity; aabb[1] = dInfinity; aabb[2] = m_vMinHeight; aabb[3] = m_vMaxHeight; aabb[4] = -dInfinity; aabb[5] = dInfinity; } } } dReal dxTerrainY::GetHeight(int x,int z) { return m_pHeights[ (((unsigned int)(z) & m_nNumNodesPerSideMask) << m_nNumNodesPerSideShift) + ((unsigned int)(x) & m_nNumNodesPerSideMask)]; } dReal dxTerrainY::GetHeight(dReal x,dReal z) { int nX = int(floor(x / m_vNodeLength)); int nZ = int(floor(z / m_vNodeLength)); dReal dx = (x - (dReal(nX) * m_vNodeLength)) / m_vNodeLength; dReal dz = (z - (dReal(nZ) * m_vNodeLength)) / m_vNodeLength; dIASSERT((dx >= 0.f) && (dx <= 1.f)); dIASSERT((dz >= 0.f) && (dz <= 1.f)); dReal y,y0; if (dx + dz < 1.f) { y0 = GetHeight(nX,nZ); y = y0 + (GetHeight(nX+1,nZ) - y0) * dx + (GetHeight(nX,nZ+1) - y0) * dz; } else { y0 = GetHeight(nX+1,nZ+1); y = y0 + (GetHeight(nX+1,nZ) - y0) * (1.f - dz) + (GetHeight(nX,nZ+1) - y0) * (1.f - dx); } return y; } bool dxTerrainY::IsOnTerrain(int nx,int nz,int w,dReal *pos) { dVector3 Min,Max; Min[0] = nx * m_vNodeLength; Min[2] = nz * m_vNodeLength; Max[0] = (nx+1) * m_vNodeLength; Max[2] = (nz+1) * m_vNodeLength; dReal Tol = m_vNodeLength * TERRAINTOL; if ((pos[0]Max[0]+Tol)) return false; if ((pos[2]Max[2]+Tol)) return false; dReal dx = (pos[0] - (dReal(nx) * m_vNodeLength)) / m_vNodeLength; dReal dz = (pos[2] - (dReal(nz) * m_vNodeLength)) / m_vNodeLength; if ((w == 0) && (dx + dz > 1.f+TERRAINTOL)) return false; if ((w == 1) && (dx + dz < 1.f-TERRAINTOL)) return false; return true; } dGeomID dCreateTerrainY(dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable) { return new dxTerrainY(space, pHeights,vLength,nNumNodesPerSide,bFinite,bPlaceable); } dReal dGeomTerrainYPointDepth (dGeomID g, dReal x, dReal y, dReal z) { dUASSERT (g && g->type == dTerrainYClass,"argument not a terrain"); g->recomputePosr(); dxTerrainY *t = (dxTerrainY*) g; return t->GetHeight(x,z) - y; } typedef dReal dGetDepthFn(dGeomID g, dReal x, dReal y, dReal z); #define RECOMPUTE_RAYNORMAL //#define DO_RAYDEPTH #define DMESS(A) \ dMessage(0,"Contact Plane (%d %d %d) %.5e %.5e (%.5e %.5e %.5e)(%.5e %.5e %.5e)).", \ x,z,A, \ pContact->depth, \ dGeomSphereGetRadius(o2), \ pContact->pos[0], \ pContact->pos[1], \ pContact->pos[2], \ pContact->normal[0], \ pContact->normal[1], \ pContact->normal[2]); /* (y is up) A-B-E.x |/| C-D | F . z */ int dxTerrainY::dCollideTerrainUnit( int x,int z,dxGeom *o2,int numMaxContacts, int flags,dContactGeom *contact, int skip) { dColliderFn *CollideRayN; dColliderFn *CollideNPlane; dGetDepthFn *GetDepth; int numContacts = 0; int numPlaneContacts = 0; int i; if (numContacts == numMaxContacts) return numContacts; dContactGeom PlaneContact[MAXCONTACT]; flags = (flags & 0xffff0000) | MAXCONTACT; switch (o2->type) { case dSphereClass: CollideRayN = dCollideRaySphere; CollideNPlane = dCollideSpherePlane; GetDepth = dGeomSpherePointDepth; break; case dBoxClass: CollideRayN = dCollideRayBox; CollideNPlane = dCollideBoxPlane; GetDepth = dGeomBoxPointDepth; break; case dCCylinderClass: CollideRayN = dCollideRayCCylinder; CollideNPlane = dCollideCCylinderPlane; GetDepth = dGeomCCylinderPointDepth; break; case dRayClass: CollideRayN = NULL; CollideNPlane = dCollideRayPlane; GetDepth = NULL; break; case dConeClass: CollideRayN = dCollideRayCone; CollideNPlane = dCollideConePlane; GetDepth = dGeomConePointDepth; break; default: dIASSERT(0); } dReal Plane[4],lBD,lCD,lBC; dVector3 A,B,C,D,BD,CD,BC,AB,AC; A[0] = x * m_vNodeLength; A[2] = z* m_vNodeLength; A[1] = GetHeight(x,z); B[0] = (x+1) * m_vNodeLength; B[2] = z * m_vNodeLength; B[1] = GetHeight(x+1,z); C[0] = x * m_vNodeLength; C[2] = (z+1) * m_vNodeLength; C[1] = GetHeight(x,z+1); D[0] = (x+1) * m_vNodeLength; D[2] = (z+1) * m_vNodeLength; D[1] = GetHeight(x+1,z+1); dOP(BC,-,C,B); lBC = dLENGTH(BC); dOPEC(BC,/=,lBC); dOP(BD,-,D,B); lBD = dLENGTH(BD); dOPEC(BD,/=,lBD); dOP(CD,-,D,C); lCD = dLENGTH(CD); dOPEC(CD,/=,lCD); dOP(AB,-,B,A); dNormalize3(AB); dOP(AC,-,C,A); dNormalize3(AC); if (CollideRayN) { #ifdef RECOMPUTE_RAYNORMAL dVector3 E,F; dVector3 CE,FB,AD; dVector3 Normal[3]; E[0] = (x+2) * m_vNodeLength; E[2] = z * m_vNodeLength; E[1] = GetHeight(x+2,z); F[0] = x * m_vNodeLength; F[2] = (z+2) * m_vNodeLength; F[1] = GetHeight(x,z+2); dOP(AD,-,D,A); dNormalize3(AD); dOP(CE,-,E,C); dNormalize3(CE); dOP(FB,-,B,F); dNormalize3(FB); //BC dCROSS(Normal[0],=,BC,AD); dNormalize3(Normal[0]); //BD dCROSS(Normal[1],=,BD,CE); dNormalize3(Normal[1]); //CD dCROSS(Normal[2],=,CD,FB); dNormalize3(Normal[2]); #endif int nA[3],nB[3]; dContactGeom ContactA[3],ContactB[3]; dxRay rayBC(0,lBC); dGeomRaySet(&rayBC, B[0], B[1], B[2], BC[0], BC[1], BC[2]); nA[0] = CollideRayN(&rayBC,o2,flags,&ContactA[0],sizeof(dContactGeom)); dGeomRaySet(&rayBC, C[0], C[1], C[2], -BC[0], -BC[1], -BC[2]); nB[0] = CollideRayN(&rayBC,o2,flags,&ContactB[0],sizeof(dContactGeom)); dxRay rayBD(0,lBD); dGeomRaySet(&rayBD, B[0], B[1], B[2], BD[0], BD[1], BD[2]); nA[1] = CollideRayN(&rayBD,o2,flags,&ContactA[1],sizeof(dContactGeom)); dGeomRaySet(&rayBD, D[0], D[1], D[2], -BD[0], -BD[1], -BD[2]); nB[1] = CollideRayN(&rayBD,o2,flags,&ContactB[1],sizeof(dContactGeom)); dxRay rayCD(0,lCD); dGeomRaySet(&rayCD, C[0], C[1], C[2], CD[0], CD[1], CD[2]); nA[2] = CollideRayN(&rayCD,o2,flags,&ContactA[2],sizeof(dContactGeom)); dGeomRaySet(&rayCD, D[0], D[1], D[2], -CD[0], -CD[1], -CD[2]); nB[2] = CollideRayN(&rayCD,o2,flags,&ContactB[2],sizeof(dContactGeom)); for (i=0;i<3;i++) { if (nA[i] & nB[i]) { dContactGeom *pContact = CONTACT(contact,numContacts*skip); pContact->pos[0] = (ContactA[i].pos[0] + ContactB[i].pos[0])/2; pContact->pos[1] = (ContactA[i].pos[1] + ContactB[i].pos[1])/2; pContact->pos[2] = (ContactA[i].pos[2] + ContactB[i].pos[2])/2; #ifdef RECOMPUTE_RAYNORMAL pContact->normal[0] = -Normal[i][0]; pContact->normal[1] = -Normal[i][1]; pContact->normal[2] = -Normal[i][2]; #else pContact->normal[0] = (ContactA[i].normal[0] + ContactB[i].normal[0])/2; //0.f; pContact->normal[1] = (ContactA[i].normal[1] + ContactB[i].normal[1])/2; //0.f; pContact->normal[2] = (ContactA[i].normal[2] + ContactB[i].normal[2])/2; //-1.f; dNormalize3(pContact->normal); #endif #ifdef DO_RAYDEPTH dxRay rayV(0,1000.f); dGeomRaySet(&rayV, pContact->pos[0], pContact->pos[1], pContact->pos[2], -pContact->normal[0], -pContact->normal[1], -pContact->normal[2]); dContactGeom ContactV; if (CollideRayN(&rayV,o2,flags,&ContactV,sizeof(dContactGeom))) { pContact->depth = ContactV.depth; numContacts++; } #else if (GetDepth == NULL) { dxRay rayV(0,1000.f); dGeomRaySet(&rayV, pContact->pos[0], pContact->pos[1], pContact->pos[2], -pContact->normal[0], -pContact->normal[1], -pContact->normal[2]); dContactGeom ContactV; if (CollideRayN(&rayV,o2,flags,&ContactV,sizeof(dContactGeom))) { pContact->depth = ContactV.depth; numContacts++; } } else { pContact->depth = GetDepth(o2, pContact->pos[0], pContact->pos[1], pContact->pos[2]); numContacts++; } #endif if (numContacts == numMaxContacts) return numContacts; } } } dCROSS(Plane,=,AC,AB); dNormalize3(Plane); Plane[3] = Plane[0] * A[0] + Plane[1] * A[1] + Plane[2] * A[2]; dxPlane planeABC(0,Plane[0],Plane[1],Plane[2],Plane[3]); numPlaneContacts = CollideNPlane(o2,&planeABC,flags,PlaneContact,sizeof(dContactGeom)); for (i=0;ipos[0] = PlaneContact[i].pos[0]; pContact->pos[1] = PlaneContact[i].pos[1]; pContact->pos[2] = PlaneContact[i].pos[2]; pContact->normal[0] = -PlaneContact[i].normal[0]; pContact->normal[1] = -PlaneContact[i].normal[1]; pContact->normal[2] = -PlaneContact[i].normal[2]; pContact->depth = PlaneContact[i].depth; //DMESS(0); numContacts++; if (numContacts == numMaxContacts) return numContacts; } } dCROSS(Plane,=,BD,CD); dNormalize3(Plane); Plane[3] = Plane[0] * D[0] + Plane[1] * D[1] + Plane[2] * D[2]; dxPlane planeDCB(0,Plane[0],Plane[1],Plane[2],Plane[3]); numPlaneContacts = CollideNPlane(o2,&planeDCB,flags,PlaneContact,sizeof(dContactGeom)); for (i=0;ipos[0] = PlaneContact[i].pos[0]; pContact->pos[1] = PlaneContact[i].pos[1]; pContact->pos[2] = PlaneContact[i].pos[2]; pContact->normal[0] = -PlaneContact[i].normal[0]; pContact->normal[1] = -PlaneContact[i].normal[1]; pContact->normal[2] = -PlaneContact[i].normal[2]; pContact->depth = PlaneContact[i].depth; //DMESS(1); numContacts++; if (numContacts == numMaxContacts) return numContacts; } } return numContacts; } int dCollideTerrainY(dxGeom *o1, dxGeom *o2, int flags,dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dTerrainYClass); int i,j; if ((flags & 0xffff) == 0) flags = (flags & 0xffff0000) | 1; int numMaxTerrainContacts = (flags & 0xffff); dxTerrainY *terrain = (dxTerrainY*) o1; dReal aabbbak[6]; int gflagsbak; dVector3 pos0; int numTerrainContacts = 0; dxPosR *bak; dxPosR X1; if (terrain->gflags & GEOM_PLACEABLE) { dOP(pos0,-,o2->final_posr->pos,terrain->final_posr->pos); dMULTIPLY1_331(X1.pos,terrain->final_posr->R,pos0); dMULTIPLY1_333(X1.R,terrain->final_posr->R,o2->final_posr->R); bak = o2->final_posr; o2->final_posr = &X1; memcpy(aabbbak,o2->aabb,sizeof(dReal)*6); gflagsbak = o2->gflags; o2->computeAABB(); } int nMinX = int(floor(o2->aabb[0] / terrain->m_vNodeLength)); int nMaxX = int(floor(o2->aabb[1] / terrain->m_vNodeLength)) + 1; int nMinZ = int(floor(o2->aabb[4] / terrain->m_vNodeLength)); int nMaxZ = int(floor(o2->aabb[5] / terrain->m_vNodeLength)) + 1; if (terrain->m_bFinite) { nMinX = MAX(nMinX,0); nMaxX = MIN(nMaxX,terrain->m_nNumNodesPerSide); nMinZ = MAX(nMinZ,0); nMaxZ = MIN(nMaxZ,terrain->m_nNumNodesPerSide); if ((nMinX >= nMaxX) || (nMinZ >= nMaxZ)) goto dCollideTerrainYExit; } dVector3 AabbTop; AabbTop[0] = (o2->aabb[0]+o2->aabb[1]) / 2; AabbTop[2] = (o2->aabb[4]+o2->aabb[5]) / 2; AabbTop[1] = o2->aabb[3]; if (o2->type != dRayClass) { dReal AabbTopDepth = terrain->GetHeight(AabbTop[0],AabbTop[2]) - AabbTop[1]; if (AabbTopDepth > 0.f) { contact->depth = AabbTopDepth; dReal MaxDepth = (o2->aabb[3]-o2->aabb[2]) / 2; if (contact->depth > MaxDepth) contact->depth = MaxDepth; contact->g1 = o1; contact->g2 = o2; dOPE(contact->pos,=,AabbTop); contact->normal[0] = 0.f; contact->normal[1] = -1.f; contact->normal[2] = 0.f; numTerrainContacts = 1; goto dCollideTerrainYExit; } } for (i=nMinX;idCollideTerrainUnit( i,j,o2,numMaxTerrainContacts - numTerrainContacts, flags,CONTACT(contact,numTerrainContacts*skip),skip ); } } dIASSERT(numTerrainContacts <= numMaxTerrainContacts); for (i=0; ig1 = o1; CONTACT(contact,i*skip)->g2 = o2; } dCollideTerrainYExit: if (terrain->gflags & GEOM_PLACEABLE) { o2->final_posr = bak; memcpy(o2->aabb,aabbbak,sizeof(dReal)*6); o2->gflags = gflagsbak; for (i=0; ipos); dMULTIPLY0_331(CONTACT(contact,i*skip)->pos,terrain->final_posr->R,pos0); dOP(CONTACT(contact,i*skip)->pos,+,CONTACT(contact,i*skip)->pos,terrain->final_posr->pos); dOPE(pos0,=,CONTACT(contact,i*skip)->normal); dMULTIPLY0_331(CONTACT(contact,i*skip)->normal,terrain->final_posr->R,pos0); } } return numTerrainContacts; } /* void dsDrawTerrainY(int x,int z,float vLength,float vNodeLength,int nNumNodesPerSide,float *pHeights,const float *pR,const float *ppos) { float A[3],B[3],C[3],D[3]; float R[12]; float pos[3]; if (pR) memcpy(R,pR,sizeof(R)); else { memset(R,0,sizeof(R)); R[0] = 1.f; R[5] = 1.f; R[10] = 1.f; } if (ppos) memcpy(pos,ppos,sizeof(pos)); else memset(pos,0,sizeof(pos)); float vx,vz; vx = vLength * x; vz = vLength * z; int i; for (i=0;i #include #include #include #include #include "collision_kernel.h" #include "collision_std.h" #include "collision_std_internal.h" #include "collision_util.h" //#include #include "windows.h" #include "ode\ode.h" #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) #define MAXCONTACT 10 #define TERRAINTOL 0.0f static bool IsAPowerOfTwo(int f) { dAASSERT(f!=0); while ((f&1) != 1) f >>= 1; return (f == 1); } static int GetPowerOfTwo(int f) { dAASSERT(f!=0); int n = 0; while ((f&1) != 1) { n++; f >>= 1; } return n; } dxTerrainZ::dxTerrainZ (dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable) : dxGeom (space,bPlaceable) { dIASSERT(IsAPowerOfTwo(nNumNodesPerSide)); dIASSERT(pHeights); dIASSERT(vLength > 0.f); dIASSERT(nNumNodesPerSide > 0); type = dTerrainZClass; m_vLength = vLength; m_pHeights = new dReal[nNumNodesPerSide * nNumNodesPerSide]; dIASSERT(m_pHeights); m_nNumNodesPerSide = nNumNodesPerSide; m_vNodeLength = m_vLength / m_nNumNodesPerSide; m_nNumNodesPerSideShift = GetPowerOfTwo(m_nNumNodesPerSide); m_nNumNodesPerSideMask = m_nNumNodesPerSide - 1; m_vMinHeight = dInfinity; m_vMaxHeight = -dInfinity; m_bFinite = bFinite; for (int i=0;i m_vMaxHeight) m_vMaxHeight = m_pHeights[i]; } } dxTerrainZ::~dxTerrainZ() { dIASSERT(m_pHeights); delete [] m_pHeights; } void dxTerrainZ::computeAABB() { if (m_bFinite) { if (gflags & GEOM_PLACEABLE) { dReal dx[6],dy[6],dz[6]; dx[0] = 0; dx[1] = final_posr->R[0] * m_vLength; dx[2] = 0; dx[3] = final_posr->R[1] * m_vLength; dx[4] = final_posr->R[2] * m_vMinHeight; dx[5] = final_posr->R[2] * m_vMaxHeight; dy[0] = 0; dy[1] = final_posr->R[4] * m_vLength; dy[2] = 0; dy[3] = final_posr->R[5] * m_vLength; dy[4] = final_posr->R[6] * m_vMinHeight; dy[5] = final_posr->R[6] * m_vMaxHeight; dz[0] = 0; dz[1] = final_posr->R[8] * m_vLength; dz[2] = 0; dz[3] = final_posr->R[9] * m_vLength; dz[4] = final_posr->R[10] * m_vMinHeight; dz[5] = final_posr->R[10] * m_vMaxHeight; aabb[0] = final_posr->pos[0] + MIN(dx[0],dx[1]) + MIN(dx[2],dx[3]) + MIN(dx[4],dx[5]); aabb[1] = final_posr->pos[0] + MAX(dx[0],dx[1]) + MAX(dx[2],dx[3]) + MAX(dx[4],dx[5]); aabb[2] = final_posr->pos[1] + MIN(dy[0],dy[1]) + MIN(dy[2],dy[3]) + MIN(dy[4],dy[5]); aabb[3] = final_posr->pos[1] + MAX(dy[0],dy[1]) + MAX(dy[2],dy[3]) + MAX(dy[4],dy[5]); aabb[4] = final_posr->pos[2] + MIN(dz[0],dz[1]) + MIN(dz[2],dz[3]) + MIN(dz[4],dz[5]); aabb[5] = final_posr->pos[2] + MAX(dz[0],dz[1]) + MAX(dz[2],dz[3]) + MAX(dz[4],dz[5]); } else { aabb[0] = 0; aabb[1] = m_vLength; aabb[2] = 0; aabb[3] = m_vLength; aabb[4] = m_vMinHeight; aabb[5] = m_vMaxHeight; } } else { if (gflags & GEOM_PLACEABLE) { aabb[0] = -dInfinity; aabb[1] = dInfinity; aabb[2] = -dInfinity; aabb[3] = dInfinity; aabb[4] = -dInfinity; aabb[5] = dInfinity; } else { aabb[0] = -dInfinity; aabb[1] = dInfinity; aabb[2] = -dInfinity; aabb[3] = dInfinity; aabb[4] = m_vMinHeight; aabb[5] = m_vMaxHeight; } } } dReal dxTerrainZ::GetHeight(int x,int y) { return m_pHeights[ (((unsigned int)(y) & m_nNumNodesPerSideMask) << m_nNumNodesPerSideShift) + ((unsigned int)(x) & m_nNumNodesPerSideMask)]; } dReal dxTerrainZ::GetHeight(dReal x,dReal y) { int nX = int(floor(x / m_vNodeLength)); int nY = int(floor(y / m_vNodeLength)); dReal dx = (x - (dReal(nX) * m_vNodeLength)) / m_vNodeLength; dReal dy = (y - (dReal(nY) * m_vNodeLength)) / m_vNodeLength; dIASSERT((dx >= 0.f) && (dx <= 1.f)); dIASSERT((dy >= 0.f) && (dy <= 1.f)); dReal z,z0; if (dx + dy < 1.f) { z0 = GetHeight(nX,nY); z = z0 + (GetHeight(nX+1,nY) - z0) * dx + (GetHeight(nX,nY+1) - z0) * dy; } else { z0 = GetHeight(nX+1,nY+1); z = z0 + (GetHeight(nX+1,nY) - z0) * (1.f - dy) + (GetHeight(nX,nY+1) - z0) * (1.f - dx); } return z; } bool dxTerrainZ::IsOnTerrain(int nx,int ny,int w,dReal *pos) { dVector3 Min,Max; Min[0] = nx * m_vNodeLength; Min[1] = ny * m_vNodeLength; Max[0] = (nx+1) * m_vNodeLength; Max[1] = (ny+1) * m_vNodeLength; dReal Tol = m_vNodeLength * TERRAINTOL; if ((pos[0]Max[0]+Tol)) return false; if ((pos[1]Max[1]+Tol)) return false; dReal dx = (pos[0] - (dReal(nx) * m_vNodeLength)) / m_vNodeLength; dReal dy = (pos[1] - (dReal(ny) * m_vNodeLength)) / m_vNodeLength; if ((w == 0) && (dx + dy > 1.f+TERRAINTOL)) return false; if ((w == 1) && (dx + dy < 1.f-TERRAINTOL)) return false; return true; } dGeomID dCreateTerrainZ(dSpaceID space, dReal *pHeights,dReal vLength,int nNumNodesPerSide, int bFinite, int bPlaceable) { return new dxTerrainZ(space, pHeights,vLength,nNumNodesPerSide, bFinite, bPlaceable); } dReal dGeomTerrainZPointDepth (dGeomID g, dReal x, dReal y, dReal z) { dUASSERT (g && g->type == dTerrainZClass,"argument not a terrain"); g->recomputePosr(); dxTerrainZ *t = (dxTerrainZ*) g; return t->GetHeight(x,y) - z; } typedef dReal dGetDepthFn(dGeomID g, dReal x, dReal y, dReal z); #define RECOMPUTE_RAYNORMAL //#define DO_RAYDEPTH #define DMESS(A) \ dMessage(0,"Contact Plane (%d %d %d) %.5e %.5e (%.5e %.5e %.5e)(%.5e %.5e %.5e)).", \ x,y,A, \ pContact->depth, \ dGeomSphereGetRadius(o2), \ pContact->pos[0], \ pContact->pos[1], \ pContact->pos[2], \ pContact->normal[0], \ pContact->normal[1], \ pContact->normal[2]); /* (z is up) y . F | C-D |\| A-B-E.x */ int dxTerrainZ::dCollideTerrainUnit( int x,int y,dxGeom *o2,int numMaxContacts, int flags,dContactGeom *contact, int skip) { dColliderFn *CollideRayN; dColliderFn *CollideNPlane; dGetDepthFn *GetDepth; int numContacts = 0; int numPlaneContacts = 0; int i; if (numContacts == numMaxContacts) return numContacts; dContactGeom PlaneContact[MAXCONTACT]; flags = (flags & 0xffff0000) | MAXCONTACT; switch (o2->type) { case dSphereClass: CollideRayN = dCollideRaySphere; CollideNPlane = dCollideSpherePlane; GetDepth = dGeomSpherePointDepth; break; case dBoxClass: CollideRayN = dCollideRayBox; CollideNPlane = dCollideBoxPlane; GetDepth = dGeomBoxPointDepth; break; case dCCylinderClass: CollideRayN = dCollideRayCCylinder; CollideNPlane = dCollideCCylinderPlane; GetDepth = dGeomCCylinderPointDepth; break; case dRayClass: CollideRayN = NULL; CollideNPlane = dCollideRayPlane; GetDepth = NULL; break; case dConeClass: CollideRayN = dCollideRayCone; CollideNPlane = dCollideConePlane; GetDepth = dGeomConePointDepth; break; default: dIASSERT(0); } dReal Plane[4],lBD,lCD,lBC; dVector3 A,B,C,D,BD,CD,BC,AB,AC; A[0] = x * m_vNodeLength; A[1] = y * m_vNodeLength; A[2] = GetHeight(x,y); B[0] = (x+1) * m_vNodeLength; B[1] = y * m_vNodeLength; B[2] = GetHeight(x+1,y); C[0] = x * m_vNodeLength; C[1] = (y+1) * m_vNodeLength; C[2] = GetHeight(x,y+1); D[0] = (x+1) * m_vNodeLength; D[1] = (y+1) * m_vNodeLength; D[2] = GetHeight(x+1,y+1); dOP(BC,-,C,B); lBC = dLENGTH(BC); dOPEC(BC,/=,lBC); dOP(BD,-,D,B); lBD = dLENGTH(BD); dOPEC(BD,/=,lBD); dOP(CD,-,D,C); lCD = dLENGTH(CD); dOPEC(CD,/=,lCD); dOP(AB,-,B,A); dNormalize3(AB); dOP(AC,-,C,A); dNormalize3(AC); if (CollideRayN) { #ifdef RECOMPUTE_RAYNORMAL dVector3 E,F; dVector3 CE,FB,AD; dVector3 Normal[3]; E[0] = (x+2) * m_vNodeLength; E[1] = y * m_vNodeLength; E[2] = GetHeight(x+2,y); F[0] = x * m_vNodeLength; F[1] = (y+2) * m_vNodeLength; F[2] = GetHeight(x,y+2); dOP(AD,-,D,A); dNormalize3(AD); dOP(CE,-,E,C); dNormalize3(CE); dOP(FB,-,B,F); dNormalize3(FB); //BC dCROSS(Normal[0],=,AD,BC); dNormalize3(Normal[0]); //BD dCROSS(Normal[1],=,CE,BD); dNormalize3(Normal[1]); //CD dCROSS(Normal[2],=,FB,CD); dNormalize3(Normal[2]); #endif int nA[3],nB[3]; dContactGeom ContactA[3],ContactB[3]; dxRay rayBC(0,lBC); dGeomRaySet(&rayBC, B[0], B[1], B[2], BC[0], BC[1], BC[2]); nA[0] = CollideRayN(&rayBC,o2,flags,&ContactA[0],sizeof(dContactGeom)); dGeomRaySet(&rayBC, C[0], C[1], C[2], -BC[0], -BC[1], -BC[2]); nB[0] = CollideRayN(&rayBC,o2,flags,&ContactB[0],sizeof(dContactGeom)); dxRay rayBD(0,lBD); dGeomRaySet(&rayBD, B[0], B[1], B[2], BD[0], BD[1], BD[2]); nA[1] = CollideRayN(&rayBD,o2,flags,&ContactA[1],sizeof(dContactGeom)); dGeomRaySet(&rayBD, D[0], D[1], D[2], -BD[0], -BD[1], -BD[2]); nB[1] = CollideRayN(&rayBD,o2,flags,&ContactB[1],sizeof(dContactGeom)); dxRay rayCD(0,lCD); dGeomRaySet(&rayCD, C[0], C[1], C[2], CD[0], CD[1], CD[2]); nA[2] = CollideRayN(&rayCD,o2,flags,&ContactA[2],sizeof(dContactGeom)); dGeomRaySet(&rayCD, D[0], D[1], D[2], -CD[0], -CD[1], -CD[2]); nB[2] = CollideRayN(&rayCD,o2,flags,&ContactB[2],sizeof(dContactGeom)); for (i=0;i<3;i++) { if (nA[i] & nB[i]) { dContactGeom *pContact = CONTACT(contact,numContacts*skip); pContact->pos[0] = (ContactA[i].pos[0] + ContactB[i].pos[0])/2; pContact->pos[1] = (ContactA[i].pos[1] + ContactB[i].pos[1])/2; pContact->pos[2] = (ContactA[i].pos[2] + ContactB[i].pos[2])/2; #ifdef RECOMPUTE_RAYNORMAL pContact->normal[0] = -Normal[i][0]; pContact->normal[1] = -Normal[i][1]; pContact->normal[2] = -Normal[i][2]; #else pContact->normal[0] = (ContactA[i].normal[0] + ContactB[i].normal[0])/2; //0.f; pContact->normal[1] = (ContactA[i].normal[1] + ContactB[i].normal[1])/2; //0.f; pContact->normal[2] = (ContactA[i].normal[2] + ContactB[i].normal[2])/2; //-1.f; dNormalize3(pContact->normal); #endif #ifdef DO_RAYDEPTH dxRay rayV(0,1000.f); dGeomRaySet(&rayV, pContact->pos[0], pContact->pos[1], pContact->pos[2], -pContact->normal[0], -pContact->normal[1], -pContact->normal[2]); dContactGeom ContactV; if (CollideRayN(&rayV,o2,flags,&ContactV,sizeof(dContactGeom))) { pContact->depth = ContactV.depth; numContacts++; } #else if (GetDepth == NULL) { dxRay rayV(0,1000.f); dGeomRaySet(&rayV, pContact->pos[0], pContact->pos[1], pContact->pos[2], -pContact->normal[0], -pContact->normal[1], -pContact->normal[2]); dContactGeom ContactV; if (CollideRayN(&rayV,o2,flags,&ContactV,sizeof(dContactGeom))) { pContact->depth = ContactV.depth; numContacts++; } } else { pContact->depth = GetDepth(o2, pContact->pos[0], pContact->pos[1], pContact->pos[2]); numContacts++; } #endif if (numContacts == numMaxContacts) return numContacts; } } } dCROSS(Plane,=,AB,AC); dNormalize3(Plane); Plane[3] = Plane[0] * A[0] + Plane[1] * A[1] + Plane[2] * A[2]; dxPlane planeABC(0,Plane[0],Plane[1],Plane[2],Plane[3]); numPlaneContacts = CollideNPlane(o2,&planeABC,flags,PlaneContact,sizeof(dContactGeom)); for (i=0;ipos[0] = PlaneContact[i].pos[0]; pContact->pos[1] = PlaneContact[i].pos[1]; pContact->pos[2] = PlaneContact[i].pos[2]; pContact->normal[0] = -PlaneContact[i].normal[0]; pContact->normal[1] = -PlaneContact[i].normal[1]; pContact->normal[2] = -PlaneContact[i].normal[2]; pContact->depth = PlaneContact[i].depth; //DMESS(0); numContacts++; if (numContacts == numMaxContacts) return numContacts; } } dCROSS(Plane,=,CD,BD); dNormalize3(Plane); Plane[3] = Plane[0] * D[0] + Plane[1] * D[1] + Plane[2] * D[2]; dxPlane planeDCB(0,Plane[0],Plane[1],Plane[2],Plane[3]); numPlaneContacts = CollideNPlane(o2,&planeDCB,flags,PlaneContact,sizeof(dContactGeom)); for (i=0;ipos[0] = PlaneContact[i].pos[0]; pContact->pos[1] = PlaneContact[i].pos[1]; pContact->pos[2] = PlaneContact[i].pos[2]; pContact->normal[0] = -PlaneContact[i].normal[0]; pContact->normal[1] = -PlaneContact[i].normal[1]; pContact->normal[2] = -PlaneContact[i].normal[2]; pContact->depth = PlaneContact[i].depth; //DMESS(1); numContacts++; if (numContacts == numMaxContacts) return numContacts; } } return numContacts; } int dCollideTerrainZ(dxGeom *o1, dxGeom *o2, int flags,dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (o1->type == dTerrainZClass); int i,j; if ((flags & 0xffff) == 0) flags = (flags & 0xffff0000) | 1; int numMaxTerrainContacts = (flags & 0xffff); dxTerrainZ *terrain = (dxTerrainZ*) o1; dReal aabbbak[6]; int gflagsbak; dVector3 pos0; int numTerrainContacts = 0; dxPosR *bak; dxPosR X1; if (terrain->gflags & GEOM_PLACEABLE) { dOP(pos0,-,o2->final_posr->pos,terrain->final_posr->pos); dMULTIPLY1_331(X1.pos,terrain->final_posr->R,pos0); dMULTIPLY1_333(X1.R,terrain->final_posr->R,o2->final_posr->R); bak = o2->final_posr; o2->final_posr = &X1; memcpy(aabbbak,o2->aabb,sizeof(dReal)*6); gflagsbak = o2->gflags; o2->computeAABB(); } int nMinX = int(floor(o2->aabb[0] / terrain->m_vNodeLength)); int nMaxX = int(floor(o2->aabb[1] / terrain->m_vNodeLength)) + 1; int nMinY = int(floor(o2->aabb[2] / terrain->m_vNodeLength)); int nMaxY = int(floor(o2->aabb[3] / terrain->m_vNodeLength)) + 1; if (terrain->m_bFinite) { nMinX = MAX(nMinX,0); nMaxX = MIN(nMaxX,terrain->m_nNumNodesPerSide); nMinY = MAX(nMinY,0); nMaxY = MIN(nMaxY,terrain->m_nNumNodesPerSide); if ((nMinX >= nMaxX) || (nMinY >= nMaxY)) goto dCollideTerrainZExit; } dVector3 AabbTop; AabbTop[0] = (o2->aabb[0]+o2->aabb[1]) / 2; AabbTop[1] = (o2->aabb[2]+o2->aabb[3]) / 2; AabbTop[2] = o2->aabb[5]; if (o2->type != dRayClass) { dReal AabbTopDepth = terrain->GetHeight(AabbTop[0],AabbTop[1]) - AabbTop[2]; if (AabbTopDepth > 0.f) { contact->depth = AabbTopDepth; dReal MaxDepth = (o2->aabb[5]-o2->aabb[4]) / 2; if (contact->depth > MaxDepth) contact->depth = MaxDepth; contact->g1 = o1; contact->g2 = o2; dOPE(contact->pos,=,AabbTop); contact->normal[0] = 0.f; contact->normal[1] = 0.f; contact->normal[2] = -1.f; numTerrainContacts = 1; goto dCollideTerrainZExit; } } for (i=nMinX;idCollideTerrainUnit( i,j,o2,numMaxTerrainContacts - numTerrainContacts, flags,CONTACT(contact,numTerrainContacts*skip),skip ); } } dIASSERT(numTerrainContacts <= numMaxTerrainContacts); for (i=0; ig1 = o1; CONTACT(contact,i*skip)->g2 = o2; } dCollideTerrainZExit: if (terrain->gflags & GEOM_PLACEABLE) { o2->final_posr = bak; memcpy(o2->aabb,aabbbak,sizeof(dReal)*6); o2->gflags = gflagsbak; for (i=0; ipos); dMULTIPLY0_331(CONTACT(contact,i*skip)->pos,terrain->final_posr->R,pos0); dOP(CONTACT(contact,i*skip)->pos,+,CONTACT(contact,i*skip)->pos,terrain->final_posr->pos); dOPE(pos0,=,CONTACT(contact,i*skip)->normal); dMULTIPLY0_331(CONTACT(contact,i*skip)->normal,terrain->final_posr->R,pos0); } } return numTerrainContacts; } /* void dsDrawTerrainZ(int x,int z,float vLength,float vNodeLength,int nNumNodesPerSide,float *pHeights,const float *pR,const float *ppos) { float A[3],B[3],C[3],D[3]; float R[12]; float pos[3]; if (pR) memcpy(R,pR,sizeof(R)); else { memset(R,0,sizeof(R)); R[0] = 1.f; R[5] = 1.f; R[10] = 1.f; } if (ppos) memcpy(pos,ppos,sizeof(pos)); else memset(pos,0,sizeof(pos)); float vx,vz; vx = vLength * x; vz = vLength * z; int i; for (i=0;i edit each .cpp file and comment out #include "windows.h" & #include "ode\ode.h" *** add to drawstuff\src\drawstuff.cpp: static void drawCone(float l, float r) { int i; float tmp,ny,nz,a,ca,sa; const int n = 24; // number of sides to the cone (divisible by 4) a = float(M_PI*2.0)/float(n); sa = (float) sin(a); ca = (float) cos(a); // draw top glShadeModel (GL_FLAT); ny=1; nz=0; // normal vector = (0,ny,nz) glBegin (GL_TRIANGLE_FAN); glNormal3d (0,0,1); glVertex3d (0,0,l); for (i=0; i<=n; i++) { if (i==1 || i==n/2+1) setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]); glNormal3d (ny*r,nz*r,0); glVertex3d (ny*r,nz*r,0); if (i==1 || i==n/2+1) setColor (color[0],color[1],color[2],color[3]); // rotate ny,nz tmp = ca*ny - sa*nz; nz = sa*ny + ca*nz; ny = tmp; } glEnd(); // draw bottom ny=1; nz=0; // normal vector = (0,ny,nz) glBegin (GL_TRIANGLE_FAN); glNormal3d (0,0,-1); glVertex3d (0,0,0); for (i=0; i<=n; i++) { if (i==1 || i==n/2+1) setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]); glNormal3d (0,0,-1); glVertex3d (ny*r,nz*r,0); if (i==1 || i==n/2+1) setColor (color[0],color[1],color[2],color[3]); // rotate ny,nz tmp = ca*ny + sa*nz; nz = -sa*ny + ca*nz; ny = tmp; } glEnd(); } void dsDrawCone (const float pos[3], const float R[12], float length, float radius) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glShadeModel (GL_SMOOTH); setTransform (pos,R); drawCone (length,radius); glPopMatrix(); if (use_shadows) { setShadowDrawingMode(); setShadowTransform(); setTransform (pos,R); drawCone (length,radius); glPopMatrix(); glPopMatrix(); glDepthRange (0,1); } } void dsDrawConeD (const double pos[3], const double R[12], float length, float radius) { int i; float pos2[3],R2[12]; for (i=0; i<3; i++) pos2[i]=(float)pos[i]; for (i=0; i<12; i++) R2[i]=(float)R[i]; dsDrawCone(pos2,R2,length,radius); } static float GetHeight(int x,int y,int nNumNodesPerSide,float *pHeights) { int nNumNodesPerSideMask = nNumNodesPerSide - 1; return pHeights[ (((unsigned int)(y) & nNumNodesPerSideMask) * nNumNodesPerSide) + ((unsigned int)(x) & nNumNodesPerSideMask)]; } void dsDrawTerrainY(int x,int z,float vLength,float vNodeLength,int nNumNodesPerSide,float *pHeights,const float *pR,const float *ppos) { float A[3],B[3],C[3],D[3]; float R[12]; float pos[3]; if (pR) memcpy(R,pR,sizeof(R)); else { memset(R,0,sizeof(R)); R[0] = 1.f; R[5] = 1.f; R[10] = 1.f; } if (ppos) memcpy(pos,ppos,sizeof(pos)); else memset(pos,0,sizeof(pos)); float vx,vz; vx = vLength * x; vz = vLength * z; int i; for (i=0;i add dCone.cpp, dTerrainY.cpp and dTerrainZ.cpp to the the libode_a_SOURCES variable in the ode/src/Makefile.am file. *** now you can now test using file test_boxstackb.cpp (to add in folder ode\test). ode-0.14/contrib/TerrainAndCone/test_boxstackb.cpp0000644000000000000000000003321312635011627020727 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCappedCylinder dsDrawCappedCylinderD #endif // some constants const dReal vTerrainLength = 4.f; const dReal vTerrainHeight = 0.5f; const int TERRAINNODES = 4; dReal pTerrainHeights[TERRAINNODES*TERRAINNODES]; dGeomID terrainZ = NULL; dGeomID terrainY = NULL; #define NUM 20 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 4 // maximum number of contact points per body // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command (int cmd) { int i,j,k; dReal sides[3]; dMass m; cmd = locase (cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' /* || cmd == 'l' */) { if (num < NUM) { i = num; num++; } else { i = nextobj; nextobj++; if (nextobj >= num) nextobj = 0; // destroy the body and geoms for slot i dBodyDestroy (obj[i].body); for (k=0; k < GPB; k++) { if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]); } memset (&obj[i],0,sizeof(obj[i])); } obj[i].body = dBodyCreate (world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition (obj[i].body, dRandReal()*2-1,dRandReal()*2+1,dRandReal()+3); dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { dReal maxheight = 0; for (k=0; k maxheight) maxheight = pos[2]; } dBodySetPosition (obj[i].body, 0,maxheight+1,maxheight+3); dRFromAxisAndAngle (R,0,0,1,dRandReal()*10.0-5.0); } dBodySetRotation (obj[i].body,R); dBodySetData (obj[i].body,(void*) i); if (cmd == 'b') { dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCappedCylinder (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCCylinder (space,sides[0],sides[1]); } /* // cylinder option not yet implemented else if (cmd == 'l') { sides[1] *= 0.5; dMassSetCappedCylinder (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]); } */ else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere (space,sides[0]); } else if (cmd == 'x') { dGeomID g2[GPB]; // encapsulated geometries dReal dpos[GPB][3]; // delta-positions for encapsulated geometries // start accumulating masses for the encapsulated geometries dMass m2; dMassSetZero (&m); // set random delta positions for (j=0; j= num) selected = 0; if (selected < 0) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable (obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable (obj[selected].body); } else if (cmd == 'a') { show_aabb ^= 1; } else if (cmd == 't') { show_contacts ^= 1; } else if (cmd == 'r') { random_pos ^= 1; } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { int i; if (!g) return; if (!pos) pos = dGeomGetPosition (g); if (!R) R = dGeomGetRotation (g); int type = dGeomGetClass (g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths (g,sides); dsDrawBox (pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere (pos,R,dGeomSphereGetRadius (g)); } else if (type == dCCylinderClass) { dReal radius,length; dGeomCCylinderGetParams (g,&radius,&length); dsDrawCappedCylinder (pos,R,length,radius); } /* // cylinder option not yet implemented else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams (g,&radius,&length); dsDrawCylinder (pos,R,length,radius); } */ else if (type == dGeomTransformClass) { dGeomID g2 = dGeomTransformGetGeom (g); const dReal *pos2 = dGeomGetPosition (g2); const dReal *R2 = dGeomGetRotation (g2); dVector3 actual_pos; dMatrix3 actual_R; dMULTIPLY0_331 (actual_pos,R,pos2); actual_pos[0] += pos[0]; actual_pos[1] += pos[1]; actual_pos[2] += pos[2]; dMULTIPLY0_333 (actual_R,R,R2); drawGeom (g2,actual_pos,actual_R,0); } if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB (g,aabb); dVector3 bbpos; for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2]; dMatrix3 RI; dRSetIdentity (RI); dsSetColorAlpha (1,0,0,0.5); dsDrawBox (bbpos,RI,bbsides); } } // simulation loop static void simLoop (int pause) { dsSetColor (0,0,2); dSpaceCollide (space,0,&nearCallback); if (!pause) dWorldStep (world,0.05); dAASSERT(terrainY); dAASSERT(terrainZ); dsSetColor (0,1,0); dsDrawTerrainY(0,0,vTerrainLength,vTerrainLength/TERRAINNODES,TERRAINNODES,pTerrainHeights,dGeomGetRotation(terrainY),dGeomGetPosition(terrainY)); dsDrawTerrainZ(0,0,vTerrainLength,vTerrainLength/TERRAINNODES,TERRAINNODES,pTerrainHeights,dGeomGetRotation(terrainZ),dGeomGetPosition(terrainZ)); if (show_aabb) { dReal aabb[6]; dGeomGetAABB (terrainY,aabb); dVector3 bbpos; int i; for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2]; dMatrix3 RI; dRSetIdentity (RI); dsSetColorAlpha (1,0,0,0.5); dsDrawBox (bbpos,RI,bbsides); dGeomGetAABB (terrainZ,aabb); for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2]; dsDrawBox (bbpos,RI,bbsides); } dsSetColor (1,1,0); // remove all contact joints dJointGroupEmpty (contactgroup); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (int i=0; i #include "dCylinder.h" // given a pointer `p' to a dContactGeom, return the dContactGeom at // p + skip bytes. struct dxCylinder { // cylinder dReal radius,lz; // radius, length along y axis // }; int dCylinderClassUser = -1; #define NUMC_MASK (0xffff) #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) ///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////circleIntersection////////////////////////////////////////////////// //this does following: //takes two circles as normals to planes n1,n2, center points cp1,cp2,and radiuses r1,r2 //finds line on which circles' planes intersect //finds four points O1,O2 - intersection between the line and sphere with center cp1 radius r1 // O3,O4 - intersection between the line and sphere with center cp2 radius r2 //returns false if there is no intersection //computes distances O1-O3, O1-O4, O2-O3, O2-O4 //in "point" returns mean point between intersection points with smallest distance ///////////////////////////////////////////////////////////////////////////////////////////////// inline bool circleIntersection(const dReal* n1,const dReal* cp1,dReal r1,const dReal* n2,const dReal* cp2,dReal r2,dVector3 point){ dReal c1=dDOT14(cp1,n1); dReal c2=dDOT14(cp2,n2); dReal cos=dDOT44(n1,n2); dReal cos_2=cos*cos; dReal sin_2=1-cos_2; dReal p1=(c1-c2*cos)/sin_2; dReal p2=(c2-c1*cos)/sin_2; dVector3 lp={p1*n1[0]+p2*n2[0],p1*n1[4]+p2*n2[4],p1*n1[8]+p2*n2[8]}; dVector3 n; dCROSS144(n,=,n1,n2); dVector3 LC1={lp[0]-cp1[0],lp[1]-cp1[1],lp[2]-cp1[2]}; dVector3 LC2={lp[0]-cp2[0],lp[1]-cp2[1],lp[2]-cp2[2]}; dReal A,B,C,B_A,B_A_2,D; dReal t1,t2,t3,t4; A=dDOT(n,n); B=dDOT(LC1,n); C=dDOT(LC1,LC1)-r1*r1; B_A=B/A; B_A_2=B_A*B_A; D=B_A_2-C; if(D<0.f){ //somewhat strange solution //- it is needed to set some //axis to sepparate cylinders //when their edges approach t1=-B_A+sqrtf(-D); t2=-B_A-sqrtf(-D); // return false; } else{ t1=-B_A-sqrtf(D); t2=-B_A+sqrtf(D); } B=dDOT(LC2,n); C=dDOT(LC2,LC2)-r2*r2; B_A=B/A; B_A_2=B_A*B_A; D=B_A_2-C; if(D<0.f) { t3=-B_A+sqrtf(-D); t4=-B_A-sqrtf(-D); // return false; } else{ t3=-B_A-sqrtf(D); t4=-B_A+sqrtf(D); } dVector3 O1={lp[0]+n[0]*t1,lp[1]+n[1]*t1,lp[2]+n[2]*t1}; dVector3 O2={lp[0]+n[0]*t2,lp[1]+n[1]*t2,lp[2]+n[2]*t2}; dVector3 O3={lp[0]+n[0]*t3,lp[1]+n[1]*t3,lp[2]+n[2]*t3}; dVector3 O4={lp[0]+n[0]*t4,lp[1]+n[1]*t4,lp[2]+n[2]*t4}; dVector3 L1_3={O3[0]-O1[0],O3[1]-O1[1],O3[2]-O1[2]}; dVector3 L1_4={O4[0]-O1[0],O4[1]-O1[1],O4[2]-O1[2]}; dVector3 L2_3={O3[0]-O2[0],O3[1]-O2[1],O3[2]-O2[2]}; dVector3 L2_4={O4[0]-O2[0],O4[1]-O2[1],O4[2]-O2[2]}; dReal l1_3=dDOT(L1_3,L1_3); dReal l1_4=dDOT(L1_4,L1_4); dReal l2_3=dDOT(L2_3,L2_3); dReal l2_4=dDOT(L2_4,L2_4); if (l1_3 0) return 0; \ if (s2 > s) { \ s = s2; \ normalR = norm; \ invert_normal = ((expr1) < 0); \ *code = (cc); \ } s = -dInfinity; invert_normal = 0; *code = 0; // separating axis = cylinder ax u2 //used when a box vertex touches a flat face of the cylinder TEST (pp[1],(hlz + B1*Q21 + B2*Q22 + B3*Q23),R1+1,0); // separating axis = box axis v1,v2,v3 //used when cylinder edge touches box face //there is two ways to compute sQ: sQ21=sqrtf(1.f-Q21*Q21); or sQ21=sqrtf(Q23*Q23+Q22*Q22); //if we did not need Q23 and Q22 the first way might be used to quiken the routine but then it need to //check if Q21<=1.f, becouse it may slightly exeed 1.f. sQ21=sqrtf(Q23*Q23+Q22*Q22); TEST (dDOT41(R2+0,p),(radius*sQ21 + hlz*Q21 + B1),R2+0,1); sQ22=sqrtf(Q23*Q23+Q21*Q21); TEST (dDOT41(R2+1,p),(radius*sQ22 + hlz*Q22 + B2),R2+1,2); sQ23=sqrtf(Q22*Q22+Q21*Q21); TEST (dDOT41(R2+2,p),(radius*sQ23 + hlz*Q23 + B3),R2+2,3); #undef TEST #define TEST(expr1,expr2,n1,n2,n3,cc) \ s2 = dFabs(expr1) - (expr2); \ if (s2 > 0) return 0; \ if (s2 > s) { \ s = s2; \ normalR = 0; \ normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ invert_normal = ((expr1) < 0); \ *code = (cc); \ } // separating axis is a normal to the cylinder axis passing across the nearest box vertex //used when a box vertex touches the lateral surface of the cylinder dReal proj,boxProj,cos,sin,cos1,cos3; dVector3 tAx,Ax,pb; { //making Ax which is perpendicular to cyl ax to box position// proj=dDOT14(p2,R1+1)-dDOT14(p1,R1+1); Ax[0]=p2[0]-p1[0]-R1[1]*proj; Ax[1]=p2[1]-p1[1]-R1[5]*proj; Ax[2]=p2[2]-p1[2]-R1[9]*proj; dNormalize3(Ax); //using Ax find box vertex which is nearest to the cylinder axis dReal sign; for (i=0; i<3; i++) pb[i] = p2[i]; sign = (dDOT14(Ax,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) pb[i] += sign * B1 * R2[i*4]; sign = (dDOT14(Ax,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) pb[i] += sign * B2 * R2[i*4+1]; sign = (dDOT14(Ax,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) pb[i] += sign * B3 * R2[i*4+2]; //building axis which is normal to cylinder ax to the nearest box vertex proj=dDOT14(pb,R1+1)-dDOT14(p1,R1+1); Ax[0]=pb[0]-p1[0]-R1[1]*proj; Ax[1]=pb[1]-p1[1]-R1[5]*proj; Ax[2]=pb[2]-p1[2]-R1[9]*proj; dNormalize3(Ax); } boxProj=dFabs(dDOT14(Ax,R2+0)*B1)+ dFabs(dDOT14(Ax,R2+1)*B2)+ dFabs(dDOT14(Ax,R2+2)*B3); TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(radius+boxProj),Ax[0],Ax[1],Ax[2],4); //next three test used to handle collisions between cylinder circles and box ages proj=dDOT14(p1,R2+0)-dDOT14(p2,R2+0); tAx[0]=-p1[0]+p2[0]+R2[0]*proj; tAx[1]=-p1[1]+p2[1]+R2[4]*proj; tAx[2]=-p1[2]+p2[2]+R2[8]*proj; dNormalize3(tAx); //now tAx is normal to first ax of the box to cylinder center //making perpendicular to tAx lying in the plane which is normal to the cylinder axis //it is tangent in the point where projection of tAx on cylinder's ring intersect edge circle cos=dDOT14(tAx,R1+0); sin=dDOT14(tAx,R1+2); tAx[0]=R1[2]*cos-R1[0]*sin; tAx[1]=R1[6]*cos-R1[4]*sin; tAx[2]=R1[10]*cos-R1[8]*sin; //use cross between tAx and first ax of the box as separating axix dCROSS114(Ax,=,tAx,R2+0); dNormalize3(Ax); boxProj=dFabs(dDOT14(Ax,R2+1)*B2)+ dFabs(dDOT14(Ax,R2+0)*B1)+ dFabs(dDOT14(Ax,R2+2)*B3); cos=dFabs(dDOT14(Ax,R1+1)); cos1=dDOT14(Ax,R1+0); cos3=dDOT14(Ax,R1+2); sin=sqrtf(cos1*cos1+cos3*cos3); TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(sin*radius+cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],5); //same thing with the second axis of the box proj=dDOT14(p1,R2+1)-dDOT14(p2,R2+1); tAx[0]=-p1[0]+p2[0]+R2[1]*proj; tAx[1]=-p1[1]+p2[1]+R2[5]*proj; tAx[2]=-p1[2]+p2[2]+R2[9]*proj; dNormalize3(tAx); cos=dDOT14(tAx,R1+0); sin=dDOT14(tAx,R1+2); tAx[0]=R1[2]*cos-R1[0]*sin; tAx[1]=R1[6]*cos-R1[4]*sin; tAx[2]=R1[10]*cos-R1[8]*sin; dCROSS114(Ax,=,tAx,R2+1); dNormalize3(Ax); boxProj=dFabs(dDOT14(Ax,R2+0)*B1)+ dFabs(dDOT14(Ax,R2+1)*B2)+ dFabs(dDOT14(Ax,R2+2)*B3); cos=dFabs(dDOT14(Ax,R1+1)); cos1=dDOT14(Ax,R1+0); cos3=dDOT14(Ax,R1+2); sin=sqrtf(cos1*cos1+cos3*cos3); TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(sin*radius+cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],6); //same thing with the third axis of the box proj=dDOT14(p1,R2+2)-dDOT14(p2,R2+2); Ax[0]=-p1[0]+p2[0]+R2[2]*proj; Ax[1]=-p1[1]+p2[1]+R2[6]*proj; Ax[2]=-p1[2]+p2[2]+R2[10]*proj; dNormalize3(tAx); cos=dDOT14(tAx,R1+0); sin=dDOT14(tAx,R1+2); tAx[0]=R1[2]*cos-R1[0]*sin; tAx[1]=R1[6]*cos-R1[4]*sin; tAx[2]=R1[10]*cos-R1[8]*sin; dCROSS114(Ax,=,tAx,R2+2); dNormalize3(Ax); boxProj=dFabs(dDOT14(Ax,R2+1)*B2)+ dFabs(dDOT14(Ax,R2+2)*B3)+ dFabs(dDOT14(Ax,R2+0)*B1); cos=dFabs(dDOT14(Ax,R1+1)); cos1=dDOT14(Ax,R1+0); cos3=dDOT14(Ax,R1+2); sin=sqrtf(cos1*cos1+cos3*cos3); TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(sin*radius+cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],7); #undef TEST // note: cross product axes need to be scaled when s is computed. // normal (n1,n2,n3) is relative to box 1. #define TEST(expr1,expr2,n1,n2,n3,cc) \ s2 = dFabs(expr1) - (expr2); \ if (s2 > 0) return 0; \ l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ if (l > 0) { \ s2 /= l; \ if (s2 > s) { \ s = s2; \ normalR = 0; \ normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ invert_normal = ((expr1) < 0); \ *code = (cc); \ } \ } //crosses between cylinder axis and box axes // separating axis = u2 x (v1,v2,v3) TEST(pp[0]*R31-pp[2]*R11,(radius+B2*Q23+B3*Q22),R31,0,-R11,8); TEST(pp[0]*R32-pp[2]*R12,(radius+B1*Q23+B3*Q21),R32,0,-R12,9); TEST(pp[0]*R33-pp[2]*R13,(radius+B1*Q22+B2*Q21),R33,0,-R13,10); #undef TEST // if we get to this point, the boxes interpenetrate. compute the normal // in global coordinates. if (normalR) { normal[0] = normalR[0]; normal[1] = normalR[4]; normal[2] = normalR[8]; } else { if(*code>7) dMULTIPLY0_331 (normal,R1,normalC); else {normal[0] =normalC[0];normal[1] = normalC[1];normal[2] = normalC[2];} } if (invert_normal) { normal[0] = -normal[0]; normal[1] = -normal[1]; normal[2] = -normal[2]; } *depth = -s; // compute contact point(s) if (*code > 7) { //find point on the cylinder pa deepest along normal dVector3 pa; dReal sign, cos1,cos3,factor; for (i=0; i<3; i++) pa[i] = p1[i]; cos1 = dDOT14(normal,R1+0); cos3 = dDOT14(normal,R1+2) ; factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; for (i=0; i<3; i++) pa[i] += cos1 * radius * R1[i*4]; sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) pa[i] += sign * hlz * R1[i*4+1]; for (i=0; i<3; i++) pa[i] += cos3 * radius * R1[i*4+2]; // find vertex of the box deepest along normal dVector3 pb; for (i=0; i<3; i++) pb[i] = p2[i]; sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) pb[i] += sign * B1 * R2[i*4]; sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) pb[i] += sign * B2 * R2[i*4+1]; sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) pb[i] += sign * B3 * R2[i*4+2]; dReal alpha,beta; dVector3 ua,ub; for (i=0; i<3; i++) ua[i] = R1[1 + i*4]; for (i=0; i<3; i++) ub[i] = R2[*code-8 + i*4]; lineClosestApproach (pa,ua,pb,ub,&alpha,&beta); for (i=0; i<3; i++) pa[i] += ua[i]*alpha; for (i=0; i<3; i++) pb[i] += ub[i]*beta; for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); contact[0].depth = *depth; return 1; } if(*code==4){ for (i=0; i<3; i++) contact[0].pos[i] = pb[i]; contact[0].depth = *depth; return 1; } dVector3 vertex; if (*code == 0) { dReal sign; for (i=0; i<3; i++) vertex[i] = p2[i]; sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) vertex[i] += sign * B1 * R2[i*4]; sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) vertex[i] += sign * B2 * R2[i*4+1]; sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); for (i=0; i<3; i++) vertex[i] += sign * B3 * R2[i*4+2]; } else { dReal sign,cos1,cos3,factor; for (i=0; i<3; i++) vertex[i] = p1[i]; cos1 = dDOT14(normal,R1+0) ; cos3 = dDOT14(normal,R1+2); factor=sqrtf(cos1*cos1+cos3*cos3); factor= factor ? factor : 1.f; cos1/=factor; cos3/=factor; for (i=0; i<3; i++) vertex[i] += cos1 * radius * R1[i*4]; sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) vertex[i] += sign * hlz * R1[i*4+1]; for (i=0; i<3; i++) vertex[i] += cos3 * radius * R1[i*4+2]; } for (i=0; i<3; i++) contact[0].pos[i] = vertex[i]; contact[0].depth = *depth; return 1; } //**************************************************************************** extern "C" int dCylCyl (const dVector3 p1, const dMatrix3 R1, const dReal radius1,const dReal lz1, const dVector3 p2, const dMatrix3 R2, const dReal radius2,const dReal lz2, dVector3 normal, dReal *depth, int *code, int maxc, dContactGeom *contact, int skip) { dVector3 p,pp1,pp2,normalC; const dReal *normalR = 0; dReal hlz1,hlz2,s,s2; int i,invert_normal; // get vector from centers of box 1 to box 2, relative to box 1 p[0] = p2[0] - p1[0]; p[1] = p2[1] - p1[1]; p[2] = p2[2] - p1[2]; dMULTIPLY1_331 (pp1,R1,p); // get pp1 = p relative to body 1 dMULTIPLY1_331 (pp2,R2,p); // get side lengths / 2 hlz1 = lz1*REAL(0.5); hlz2 = lz2*REAL(0.5); dReal proj,cos,sin,cos1,cos3; #define TEST(expr1,expr2,norm,cc) \ s2 = dFabs(expr1) - (expr2); \ if (s2 > 0) return 0; \ if (s2 > s) { \ s = s2; \ normalR = norm; \ invert_normal = ((expr1) < 0); \ *code = (cc); \ } s = -dInfinity; invert_normal = 0; *code = 0; cos=dFabs(dDOT44(R1+1,R2+1)); sin=sqrtf(1.f-(cos>1.f ? 1.f : cos)); TEST (pp1[1],(hlz1 + radius2*sin + hlz2*cos ),R1+1,0);//pp TEST (pp2[1],(radius1*sin + hlz1*cos + hlz2),R2+1,1); // note: cross product axes need to be scaled when s is computed. #undef TEST #define TEST(expr1,expr2,n1,n2,n3,cc) \ s2 = dFabs(expr1) - (expr2); \ if (s2 > 0) return 0; \ if (s2 > s) { \ s = s2; \ normalR = 0; \ normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ invert_normal = ((expr1) < 0); \ *code = (cc); \ } dVector3 tAx,Ax,pa,pb; //cross between cylinders' axes dCROSS144(Ax,=,R1+1,R2+1); dNormalize3(Ax); TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius1+radius2,Ax[0],Ax[1],Ax[2],6); { dReal sign, factor; //making ax which is perpendicular to cyl1 ax passing across cyl2 position// //(project p on cyl1 flat surface ) for (i=0; i<3; i++) pb[i] = p2[i]; //cos1 = dDOT14(p,R1+0); //cos3 = dDOT14(p,R1+2) ; tAx[0]=pp1[0]*R1[0]+pp1[2]*R1[2]; tAx[1]=pp1[0]*R1[4]+pp1[2]*R1[6]; tAx[2]=pp1[0]*R1[8]+pp1[2]*R1[10]; dNormalize3(tAx); //find deepest point pb of cyl2 on opposite direction of tAx cos1 = dDOT14(tAx,R2+0); cos3 = dDOT14(tAx,R2+2) ; factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; for (i=0; i<3; i++) pb[i] -= cos1 * radius2 * R2[i*4]; sign = (dDOT14(tAx,R2+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) pb[i] -= sign * hlz2 * R2[i*4+1]; for (i=0; i<3; i++) pb[i] -= cos3 * radius2 * R2[i*4+2]; //making perpendicular to cyl1 ax passing across pb proj=dDOT14(pb,R1+1)-dDOT14(p1,R1+1); Ax[0]=pb[0]-p1[0]-R1[1]*proj; Ax[1]=pb[1]-p1[1]-R1[5]*proj; Ax[2]=pb[2]-p1[2]-R1[9]*proj; } dNormalize3(Ax); cos=dFabs(dDOT14(Ax,R2+1)); cos1=dDOT14(Ax,R2+0); cos3=dDOT14(Ax,R2+2); sin=sqrtf(cos1*cos1+cos3*cos3); TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius1+cos*hlz2+sin*radius2,Ax[0],Ax[1],Ax[2],3); { dReal sign, factor; for (i=0; i<3; i++) pa[i] = p1[i]; //making ax which is perpendicular to cyl2 ax passing across cyl1 position// //(project p on cyl2 flat surface ) //cos1 = dDOT14(p,R2+0); //cos3 = dDOT14(p,R2+2) ; tAx[0]=pp2[0]*R2[0]+pp2[2]*R2[2]; tAx[1]=pp2[0]*R2[4]+pp2[2]*R2[6]; tAx[2]=pp2[0]*R2[8]+pp2[2]*R2[10]; dNormalize3(tAx); cos1 = dDOT14(tAx,R1+0); cos3 = dDOT14(tAx,R1+2) ; factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; //find deepest point pa of cyl2 on direction of tAx for (i=0; i<3; i++) pa[i] += cos1 * radius1 * R1[i*4]; sign = (dDOT14(tAx,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) pa[i] += sign * hlz1 * R1[i*4+1]; for (i=0; i<3; i++) pa[i] += cos3 * radius1 * R1[i*4+2]; proj=dDOT14(pa,R2+1)-dDOT14(p2,R2+1); Ax[0]=pa[0]-p2[0]-R2[1]*proj; Ax[1]=pa[1]-p2[1]-R2[5]*proj; Ax[2]=pa[2]-p2[2]-R2[9]*proj; } dNormalize3(Ax); cos=dFabs(dDOT14(Ax,R1+1)); cos1=dDOT14(Ax,R1+0); cos3=dDOT14(Ax,R1+2); sin=sqrtf(cos1*cos1+cos3*cos3); TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius2+cos*hlz1+sin*radius1,Ax[0],Ax[1],Ax[2],4); ////test circl //@ this needed to set right normal when cylinders edges intersect //@ the most precise axis for this test may be found as a line between nearest points of two //@ circles. But it needs comparatively a lot of computation. //@ I use a trick which lets not to solve quadric equation. //@ In the case when cylinder eidges touches the test below rather accurate. //@ I still not sure about problems with sepparation but they have not been revealed during testing. dVector3 point; { dVector3 ca,cb; dReal sign; for (i=0; i<3; i++) ca[i] = p1[i]; for (i=0; i<3; i++) cb[i] = p2[i]; //find two nearest flat rings sign = (pp1[1] > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) ca[i] += sign * hlz1 * R1[i*4+1]; sign = (pp2[1] > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) cb[i] -= sign * hlz2 * R2[i*4+1]; dVector3 tAx,tAx1; circleIntersection(R1+1,ca,radius1,R2+1,cb,radius2,point); Ax[0]=point[0]-ca[0]; Ax[1]=point[1]-ca[1]; Ax[2]=point[2]-ca[2]; cos1 = dDOT14(Ax,R1+0); cos3 = dDOT14(Ax,R1+2) ; tAx[0]=cos3*R1[0]-cos1*R1[2]; tAx[1]=cos3*R1[4]-cos1*R1[6]; tAx[2]=cos3*R1[8]-cos1*R1[10]; Ax[0]=point[0]-cb[0]; Ax[1]=point[1]-cb[1]; Ax[2]=point[2]-cb[2]; cos1 = dDOT14(Ax,R2+0); cos3 = dDOT14(Ax,R2+2) ; tAx1[0]=cos3*R2[0]-cos1*R2[2]; tAx1[1]=cos3*R2[4]-cos1*R2[6]; tAx1[2]=cos3*R2[8]-cos1*R2[10]; dCROSS(Ax,=,tAx,tAx1); dNormalize3(Ax); dReal cyl1Pr,cyl2Pr; cos=dFabs(dDOT14(Ax,R1+1)); cos1=dDOT14(Ax,R1+0); cos3=dDOT14(Ax,R1+2); sin=sqrtf(cos1*cos1+cos3*cos3); cyl1Pr=cos*hlz1+sin*radius1; cos=dFabs(dDOT14(Ax,R2+1)); cos1=dDOT14(Ax,R2+0); cos3=dDOT14(Ax,R2+2); sin=sqrtf(cos1*cos1+cos3*cos3); cyl2Pr=cos*hlz2+sin*radius2; TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],cyl1Pr+cyl2Pr,Ax[0],Ax[1],Ax[2],5); } #undef TEST // if we get to this point, the cylinders interpenetrate. compute the normal // in global coordinates. if (normalR) { normal[0] = normalR[0]; normal[1] = normalR[4]; normal[2] = normalR[8]; } else { normal[0] =normalC[0];normal[1] = normalC[1];normal[2] = normalC[2]; } if (invert_normal) { normal[0] = -normal[0]; normal[1] = -normal[1]; normal[2] = -normal[2]; } *depth = -s; // compute contact point(s) if(*code==3){ for (i=0; i<3; i++) contact[0].pos[i] = pb[i]; contact[0].depth = *depth; return 1; } if(*code==4){ for (i=0; i<3; i++) contact[0].pos[i] = pa[i]; contact[0].depth = *depth; return 1; } if(*code==5){ for (i=0; i<3; i++) contact[0].pos[i] = point[i]; contact[0].depth = *depth; return 1; } if (*code == 6) { dVector3 pa; dReal sign, cos1,cos3,factor; for (i=0; i<3; i++) pa[i] = p1[i]; cos1 = dDOT14(normal,R1+0); cos3 = dDOT14(normal,R1+2) ; factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; for (i=0; i<3; i++) pa[i] += cos1 * radius1 * R1[i*4]; sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) pa[i] += sign * hlz1 * R1[i*4+1]; for (i=0; i<3; i++) pa[i] += cos3 * radius1 * R1[i*4+2]; // find a point pb on the intersecting edge of cylinder 2 dVector3 pb; for (i=0; i<3; i++) pb[i] = p2[i]; cos1 = dDOT14(normal,R2+0); cos3 = dDOT14(normal,R2+2) ; factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; for (i=0; i<3; i++) pb[i] -= cos1 * radius2 * R2[i*4]; sign = (dDOT14(normal,R2+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) pb[i] -= sign * hlz2 * R2[i*4+1]; for (i=0; i<3; i++) pb[i] -= cos3 * radius2 * R2[i*4+2]; dReal alpha,beta; dVector3 ua,ub; for (i=0; i<3; i++) ua[i] = R1[1 + i*4]; for (i=0; i<3; i++) ub[i] = R2[1 + i*4]; lineClosestApproach (pa,ua,pb,ub,&alpha,&beta); for (i=0; i<3; i++) pa[i] += ua[i]*alpha; for (i=0; i<3; i++) pb[i] += ub[i]*beta; for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); contact[0].depth = *depth; return 1; } // okay, we have a face-something intersection (because the separating // axis is perpendicular to a face). // @@@ temporary: make deepest point on the "other" cylinder the contact point. // @@@ this kind of works, but we need multiple contact points for stability, // @@@ especially for face-face contact. dVector3 vertex; if (*code == 0) { // flat face from cylinder 1 touches a edge/face from cylinder 2. dReal sign,cos1,cos3,factor; for (i=0; i<3; i++) vertex[i] = p2[i]; cos1 = dDOT14(normal,R2+0) ; cos3 = dDOT14(normal,R2+2); factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; for (i=0; i<3; i++) vertex[i] -= cos1 * radius2 * R2[i*4]; sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) vertex[i] -= sign * hlz2 * R2[i*4+1]; for (i=0; i<3; i++) vertex[i] -= cos3 * radius2 * R2[i*4+2]; } else { // flat face from cylinder 2 touches a edge/face from cylinder 1. dReal sign,cos1,cos3,factor; for (i=0; i<3; i++) vertex[i] = p1[i]; cos1 = dDOT14(normal,R1+0) ; cos3 = dDOT14(normal,R1+2); factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; for (i=0; i<3; i++) vertex[i] += cos1 * radius1 * R1[i*4]; sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) vertex[i] += sign * hlz1 * R1[i*4+1]; for (i=0; i<3; i++) vertex[i] += cos3 * radius1 * R1[i*4+2]; } for (i=0; i<3; i++) contact[0].pos[i] = vertex[i]; contact[0].depth = *depth; return 1; } //**************************************************************************** int dCollideCylS (dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (dGeomGetClass(o2) == dSphereClass); dIASSERT (dGeomGetClass(o1) == dCylinderClassUser); const dReal* p1=dGeomGetPosition(o1); const dReal* p2=dGeomGetPosition(o2); const dReal* R=dGeomGetRotation(o1); dVector3 p,normalC,normal; const dReal *normalR = 0; dReal cylRadius; dReal hl; dGeomCylinderGetParams(o1,&cylRadius,&hl); dReal sphereRadius; sphereRadius=dGeomSphereGetRadius(o2); int i,invert_normal; // get vector from centers of cyl to shere p[0] = p2[0] - p1[0]; p[1] = p2[1] - p1[1]; p[2] = p2[2] - p1[2]; dReal s,s2; unsigned char code; #define TEST(expr1,expr2,norm,cc) \ s2 = dFabs(expr1) - (expr2); \ if (s2 > 0) return 0; \ if (s2 > s) { \ s = s2; \ normalR = norm; \ invert_normal = ((expr1) < 0); \ code = (cc); \ } s = -dInfinity; invert_normal = 0; code = 0; // separating axis cyl ax TEST (dDOT14(p,R+1),sphereRadius+hl,R+1,2); // note: cross product axes need to be scaled when s is computed. // normal (n1,n2,n3) is relative to #undef TEST #define TEST(expr1,expr2,n1,n2,n3,cc) \ s2 = dFabs(expr1) - (expr2); \ if (s2 > 0) return 0; \ if (s2 > s) { \ s = s2; \ normalR = 0; \ normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ invert_normal = ((expr1) < 0); \ code = (cc); \ } //making ax which is perpendicular to cyl1 ax to sphere center// dReal proj,cos,sin,cos1,cos3; dVector3 Ax; proj=dDOT14(p2,R+1)-dDOT14(p1,R+1); Ax[0]=p2[0]-p1[0]-R[1]*proj; Ax[1]=p2[1]-p1[1]-R[5]*proj; Ax[2]=p2[2]-p1[2]-R[9]*proj; dNormalize3(Ax); TEST(dDOT(p,Ax),sphereRadius+cylRadius,Ax[0],Ax[1],Ax[2],9); Ax[0]=p[0]; Ax[1]=p[1]; Ax[2]=p[2]; dNormalize3(Ax); dVector3 pa; dReal sign, factor; for (i=0; i<3; i++) pa[i] = p1[i]; cos1 = dDOT14(Ax,R+0); cos3 = dDOT14(Ax,R+2) ; factor=sqrtf(cos1*cos1+cos3*cos3); cos1/=factor; cos3/=factor; for (i=0; i<3; i++) pa[i] += cos1 * cylRadius * R[i*4]; sign = (dDOT14(normal,R+1) > 0) ? REAL(1.0) : REAL(-1.0); for (i=0; i<3; i++) pa[i] += sign * hl * R[i*4+1]; for (i=0; i<3; i++) pa[i] += cos3 * cylRadius * R[i*4+2]; Ax[0]=p2[0]-pa[0]; Ax[1]=p2[1]-pa[1]; Ax[2]=p2[2]-pa[2]; dNormalize3(Ax); cos=dFabs(dDOT14(Ax,R+1)); cos1=dDOT14(Ax,R+0); cos3=dDOT14(Ax,R+2); sin=sqrtf(cos1*cos1+cos3*cos3); TEST(dDOT(p,Ax),sphereRadius+cylRadius*sin+hl*cos,Ax[0],Ax[1],Ax[2],14); #undef TEST if (normalR) { normal[0] = normalR[0]; normal[1] = normalR[4]; normal[2] = normalR[8]; } else { normal[0] = normalC[0]; normal[1] = normalC[1]; normal[2] = normalC[2]; } if (invert_normal) { normal[0] = -normal[0]; normal[1] = -normal[1]; normal[2] = -normal[2]; } // compute contact point(s) contact->depth=-s; contact->normal[0]=-normal[0]; contact->normal[1]=-normal[1]; contact->normal[2]=-normal[2]; contact->g1=const_cast (o1); contact->g2=const_cast (o2); contact->pos[0]=p2[0]-normal[0]*sphereRadius; contact->pos[1]=p2[1]-normal[1]*sphereRadius; contact->pos[2]=p2[2]-normal[2]*sphereRadius; return 1; } int dCollideCylB (dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dVector3 normal; dReal depth; int code; dReal cylRadius,cylLength; dVector3 boxSides; dGeomCylinderGetParams(o1,&cylRadius,&cylLength); dGeomBoxGetLengths(o2,boxSides); int num = dCylBox(dGeomGetPosition(o1),dGeomGetRotation(o1),cylRadius,cylLength, dGeomGetPosition(o2),dGeomGetRotation(o2),boxSides, normal,&depth,&code,flags & NUMC_MASK,contact,skip); for (int i=0; inormal[0] = -normal[0]; CONTACT(contact,i*skip)->normal[1] = -normal[1]; CONTACT(contact,i*skip)->normal[2] = -normal[2]; CONTACT(contact,i*skip)->g1 = const_cast (o1); CONTACT(contact,i*skip)->g2 = const_cast (o2); } return num; } int dCollideCylCyl (dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dVector3 normal; dReal depth; int code; dReal cylRadius1,cylRadius2; dReal cylLength1,cylLength2; dGeomCylinderGetParams(o1,&cylRadius1,&cylLength1); dGeomCylinderGetParams(o2,&cylRadius2,&cylLength2); int num = dCylCyl (dGeomGetPosition(o1),dGeomGetRotation(o1),cylRadius1,cylLength1, dGeomGetPosition(o2),dGeomGetRotation(o2),cylRadius2,cylLength2, normal,&depth,&code,flags & NUMC_MASK,contact,skip); for (int i=0; inormal[0] = -normal[0]; CONTACT(contact,i*skip)->normal[1] = -normal[1]; CONTACT(contact,i*skip)->normal[2] = -normal[2]; CONTACT(contact,i*skip)->g1 = const_cast (o1); CONTACT(contact,i*skip)->g2 = const_cast (o2); } return num; } struct dxPlane { dReal p[4]; }; int dCollideCylPlane ( dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip){ dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (dGeomGetClass(o1) == dCylinderClassUser); dIASSERT (dGeomGetClass(o2) == dPlaneClass); contact->g1 = const_cast (o1); contact->g2 = const_cast (o2); unsigned int ret = 0; dReal radius; dReal hlz; dGeomCylinderGetParams(o1,&radius,&hlz); hlz /= 2; const dReal *R = dGeomGetRotation(o1);// rotation of cylinder const dReal* p = dGeomGetPosition(o1); dVector4 n; // normal vector dReal pp; dGeomPlaneGetParams (o2, n); pp=n[3]; dReal cos1,sin1; cos1=dFabs(dDOT14(n,R+1)); cos1=cos10 ? hlz*R[1]:-hlz*R[1]; pos[1]-= A2>0 ? hlz*R[5]:-hlz*R[5]; pos[2]-= A2>0 ? hlz*R[9]:-hlz*R[9]; contact->pos[0] = pos[0]; contact->pos[1] = pos[1]; contact->pos[2] = pos[2]; contact->depth = outDepth; ret=1; if(dFabs(Q2)>M_SQRT1_2){ CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A1*R[0]; CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A1*R[4]; CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A1*R[8]; CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q1*2.f*A1); if(CONTACT(contact,ret*skip)->depth>0.f) ret++; CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A3*R[2]; CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A3*R[6]; CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A3*R[10]; CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q3*2.f*A3); if(CONTACT(contact,ret*skip)->depth>0.f) ret++; } else { CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*(A2>0 ? hlz*R[1]:-hlz*R[1]); CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*(A2>0 ? hlz*R[5]:-hlz*R[5]); CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*(A2>0 ? hlz*R[9]:-hlz*R[9]); CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q2*2.f*A2); if(CONTACT(contact,ret*skip)->depth>0.f) ret++; } for (unsigned int i=0; ig1 = const_cast (o1); CONTACT(contact,i*skip)->g2 = const_cast (o2); CONTACT(contact,i*skip)->normal[0] =n[0]; CONTACT(contact,i*skip)->normal[1] =n[1]; CONTACT(contact,i*skip)->normal[2] =n[2]; } return ret; } int dCollideCylRay(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) { dIASSERT (skip >= (int)sizeof(dContactGeom)); dIASSERT (dGeomGetClass(o1) == dCylinderClassUser); dIASSERT (dGeomGetClass(o2) == dRayClass); contact->g1 = const_cast (o1); contact->g2 = const_cast (o2); dReal radius; dReal lz; dGeomCylinderGetParams(o1,&radius,&lz); dReal lz2=lz*REAL(0.5); const dReal *R = dGeomGetRotation(o1); // rotation of the cylinder const dReal *p = dGeomGetPosition(o1); // position of the cylinder dVector3 start,dir; dGeomRayGet(o2,start,dir); // position and orientation of the ray dReal length = dGeomRayGetLength(o2); // compute some useful info dVector3 cs,q,r; dReal C,k; cs[0] = start[0] - p[0]; cs[1] = start[1] - p[1]; cs[2] = start[2] - p[2]; k = dDOT41(R+1,cs); // position of ray start along cyl axis (Y) q[0] = k*R[0*4+1] - cs[0]; q[1] = k*R[1*4+1] - cs[1]; q[2] = k*R[2*4+1] - cs[2]; C = dDOT(q,q) - radius*radius; // if C < 0 then ray start position within infinite extension of cylinder // if ray start position is inside the cylinder int inside_cyl=0; if (C<0 && !(k<-lz2 || k>lz2)) inside_cyl=1; // compute ray collision with infinite cylinder, except for the case where // the ray is outside the cylinder but within the infinite cylinder // (it that case the ray can only hit endcaps) if (!inside_cyl && C < 0) { // set k to cap position to check if (k < 0) k = -lz2; else k = lz2; } else { dReal uv = dDOT41(R+1,dir); r[0] = uv*R[0*4+1] - dir[0]; r[1] = uv*R[1*4+1] - dir[1]; r[2] = uv*R[2*4+1] - dir[2]; dReal A = dDOT(r,r); dReal B = 2*dDOT(q,r); k = B*B-4*A*C; if (k < 0) { // the ray does not intersect the infinite cylinder, but if the ray is // inside and parallel to the cylinder axis it may intersect the end // caps. set k to cap position to check. if (!inside_cyl) return 0; if (uv < 0) k = -lz2; else k = lz2; } else { k = dSqrt(k); A = dRecip (2*A); dReal alpha = (-B-k)*A; if (alpha < 0) { alpha = (-B+k)*A; if (alpha<0) return 0; } if (alpha>length) return 0; // the ray intersects the infinite cylinder. check to see if the // intersection point is between the caps contact->pos[0] = start[0] + alpha*dir[0]; contact->pos[1] = start[1] + alpha*dir[1]; contact->pos[2] = start[2] + alpha*dir[2]; q[0] = contact->pos[0] - p[0]; q[1] = contact->pos[1] - p[1]; q[2] = contact->pos[2] - p[2]; k = dDOT14(q,R+1); dReal nsign = inside_cyl ? -1 : 1; if (k >= -lz2 && k <= lz2) { contact->normal[0] = nsign * (contact->pos[0] - (p[0] + k*R[0*4+1])); contact->normal[1] = nsign * (contact->pos[1] - (p[1] + k*R[1*4+1])); contact->normal[2] = nsign * (contact->pos[2] - (p[2] + k*R[2*4+1])); dNormalize3 (contact->normal); contact->depth = alpha; return 1; } // the infinite cylinder intersection point is not between the caps. // set k to cap position to check. if (k < 0) k = -lz2; else k = lz2; } } // check for ray intersection with the caps. k must indicate the cap // position to check // perform a ray plan interesection // R+1 is the plan normal q[0] = start[0] - (p[0] + k*R[0*4+1]); q[1] = start[1] - (p[1] + k*R[1*4+1]); q[2] = start[2] - (p[2] + k*R[2*4+1]); dReal alpha = -dDOT14(q,R+1); dReal k2 = dDOT14(dir,R+1); if (k2==0) return 0; // ray parallel to the plane alpha/=k2; if (alpha<0 || alpha>length) return 0; // too short contact->pos[0]=start[0]+alpha*dir[0]; contact->pos[1]=start[1]+alpha*dir[1]; contact->pos[2]=start[2]+alpha*dir[2]; dReal nsign = (k<0)?-1:1; contact->normal[0]=nsign*R[0*4+1]; contact->normal[1]=nsign*R[1*4+1]; contact->normal[2]=nsign*R[2*4+1]; contact->depth=alpha; return 1; } static dColliderFn * dCylinderColliderFn (int num) { if (num == dBoxClass) return (dColliderFn *) &dCollideCylB; else if (num == dSphereClass) return (dColliderFn *) &dCollideCylS; else if (num == dCylinderClassUser) return (dColliderFn *) &dCollideCylCyl; else if (num == dPlaneClass) return (dColliderFn *) &dCollideCylPlane; else if (num == dRayClass) return (dColliderFn *) &dCollideCylRay; return 0; } static void dCylinderAABB (dxGeom *geom, dReal aabb[6]) { dReal radius,lz; dGeomCylinderGetParams(geom,&radius,&lz); const dReal* R= dGeomGetRotation(geom); const dReal* pos= dGeomGetPosition(geom); dReal xrange = dFabs (R[0] *radius) + REAL(0.5) *dFabs (R[1] * lz) + dFabs (R[2] * radius); dReal yrange = dFabs (R[4] *radius) + REAL(0.5) * dFabs (R[5] * lz) + dFabs (R[6] * radius); dReal zrange = dFabs (R[8] * radius) + REAL(0.5) *dFabs (R[9] * lz) + dFabs (R[10] * radius); aabb[0] = pos[0] - xrange; aabb[1] = pos[0] + xrange; aabb[2] = pos[1] - yrange; aabb[3] = pos[1] + yrange; aabb[4] = pos[2] - zrange; aabb[5] = pos[2] + zrange; } dxGeom *dCreateCylinder (dSpaceID space, dReal r, dReal lz) { dAASSERT (r > 0 && lz > 0); if (dCylinderClassUser == -1) { dGeomClass c; c.bytes = sizeof (dxCylinder); c.collider = &dCylinderColliderFn; c.aabb = &dCylinderAABB; c.aabb_test = 0; c.dtor = 0; dCylinderClassUser=dCreateGeomClass (&c); } dGeomID g = dCreateGeom (dCylinderClassUser); if (space) dSpaceAdd (space,g); dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); c->radius = r; c->lz = lz; return g; } void dGeomCylinderSetParams (dGeomID g, dReal radius, dReal length) { dUASSERT (g && dGeomGetClass(g) == dCylinderClassUser,"argument not a cylinder"); dAASSERT (radius > 0 && length > 0); dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); c->radius = radius; c->lz = length; } void dGeomCylinderGetParams (dGeomID g, dReal *radius, dReal *length) { dUASSERT (g && dGeomGetClass(g) == dCylinderClassUser ,"argument not a cylinder"); dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); *radius = c->radius; *length = c->lz; } /* void dMassSetCylinder (dMass *m, dReal density, dReal radius, dReal length) { dAASSERT (m); dMassSetZero (m); dReal M = length*M_PI*radius*radius*density; m->mass = M; m->_I(0,0) = M/REAL(4.0) * (ly*ly + lz*lz); m->_I(1,1) = M/REAL(12.0) * (lx*lx + lz*lz); m->_I(2,2) = M/REAL(4.0) * (lx*lx + ly*ly); # ifndef dNODEBUG checkMass (m); # endif } */ ode-0.14/contrib/dCylinder/dCylinder.h0000644000000000000000000000047612635011627016360 0ustar rootroot #ifndef dCylinder_h #define dCylinder_h struct dxCylinder; extern int dCylinderClassUser; dxGeom *dCreateCylinder (dSpaceID space, dReal r, dReal lz); void dGeomCylinderSetParams (dGeomID g, dReal radius, dReal length); void dGeomCylinderGetParams (dGeomID g, dReal *radius, dReal *length); #endif //dCylinder_h ode-0.14/contrib/dCylinder/readme.txt0000644000000000000000000000351712635011627016267 0ustar rootrootreadme.txt WARNING: THIS IS NOT VERY RELIABLE CODE. IT HAS BUGS. YOUR SUCCESS MAY VARY. CONTRIBUTIONS OF FIXES/REWRITES ARE WELCOME. /////////////////////////////////////////////////////////////////////// Cylinder geometry class. New in this version: Cylinder class implemented as User Geometry Class so it now can be used with old and new ODE collision detection. Cylinder - Ray has been contributed by Olivier Michel. THE IDENTIFIER dCylinderClass HAS BEEN REPLACED BY dCylinderClassUser to avoid conflict with dCylinderClass in the enum definite in collision.h /////////////////////////////////////////////////////////////////////// The dCylinder class includes the following collisions: Cylinder - Box Cylinder - Cylinder Cylinder - Sphere Cylinder - Plane Cylinder - Ray (contributed by Olivier Michel) Cylinder aligned along axis - Y when created. (Not like Capped Cylinder which aligned along axis - Z). Interface is just the same as Capped Cylinder has. Use functions which have one "C" instead of double "C". to create: dGeomID dCreateCylinder (dSpaceID space, dReal radius, dReal length); to set params: void dGeomCylinderSetParams (dGeomID cylinder, dReal radius, dReal length); to get params: void dGeomCylinderGetParams (dGeomID cylinder, dReal *radius, dReal *length); Return in radius and length the parameters of the given cylinder. Identification number of the class: dCylinderClassUser I do not include a function that sets inertia tensor for cylinder. One may use existing ODE functions dMassSetCappedCylinder or dMassSetBox. To set exact tensor for cylinder use dMassSetParameters. Remember cylinder aligned along axis - Y. /////////////////////////////////////////////////////////////////////////// Konstantin Slipchenko February 5, 2002 ode-0.14/contrib/dRay/0000775000000000000000000000000012635012023013236 5ustar rootrootode-0.14/contrib/dRay/Include/0000775000000000000000000000000012635012023014621 5ustar rootrootode-0.14/contrib/dRay/Include/dRay.h0000644000000000000000000000065512635011627015706 0ustar rootroot#include "ode\ode.h" /* Class ID */ extern int dRayClass; /* Creates a ray */ dxGeom* dGeomCreateRay(dSpaceID space, dReal Length); /* Set/Get length */ void dGeomRaySetLength(dxGeom* g, dReal Length); dReal dGeomRayGetLength(dxGeom* g); /* Utility function to override the ray's pos + rot */ void dGeomRaySet(dxGeom* g, dVector3 Origin, dVector3 Direction); void dGeomRayGet(dxGeom* g, dVector3 Origin, dVector3 Direction); ode-0.14/contrib/dRay/README.txt0000644000000000000000000000133212635011627014742 0ustar rootrootFrom: "Erwin de Vries" To: Subject: [ODE] dRay class Date: Thu, 25 Jul 2002 13:05:28 +0200 Yesterday and today i've written a dRay class. It interacts with dPlane, dSphere, dBox and dCCylinder. It does not generate full contact information. It only generates the pos member. I dont think its useful to anyone to go through hoops and find a reasonable normal and penetration depth, as i dont think anyone will want to use it for dynamics. Just for CD. It should compile in single and double precision mode, and should be platform independant. I hope. The next Tri-Collider release using Opcode 1.1 will also implement a ray collision function along with some other not too interesting improvements. ode-0.14/contrib/dRay/Test/0000775000000000000000000000000012635012023014155 5ustar rootrootode-0.14/contrib/dRay/Test/test_ray.cpp0000644000000000000000000003200412635011627016521 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCappedCylinder dsDrawCappedCylinderD #endif // some constants #define NUM 20 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static dGeomID* Rays; static int RayCount; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnected (b1,b2)) return; dContact contact[32]; // up to 3 contacts per box for (i=0; i<32; i++) { contact[i].surface.mode = dContactBounce; //dContactMu2; contact[i].surface.mu = dInfinity; contact[i].surface.mu2 = 0; contact[i].surface.bounce = 0.5; contact[i].surface.bounce_vel = 0.1; } if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) { dMatrix3 RI; dRSetIdentity (RI); const dReal ss[3] = {0.02,0.02,0.02}; for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command (int cmd) { int i,j,k; dReal sides[3]; dMass m; cmd = locase (cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x') { if (num < NUM) { i = num; num++; } else { i = nextobj; nextobj++; if (nextobj >= num) nextobj = 0; // destroy the body and geoms for slot i dBodyDestroy (obj[i].body); for (k=0; k < GPB; k++) { if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]); } memset (&obj[i],0,sizeof(obj[i])); } obj[i].body = dBodyCreate (world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dBodySetPosition (obj[i].body, dRandReal()*2-1,dRandReal()*2-1,dRandReal()+1); dMatrix3 R; dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); dBodySetRotation (obj[i].body,R); dBodySetData (obj[i].body,(void*) i); if (cmd == 'b') { dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCappedCylinder (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCCylinder (space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere (space,sides[0]); } else if (cmd == 'x') { dGeomID g2[GPB]; // encapsulated geometries dReal dpos[GPB][3]; // delta-positions for encapsulated geometries // start accumulating masses for the encapsulated geometries dMass m2; dMassSetZero (&m); // set random delta positions for (j=0; j= num) selected = 0; if (selected < 0) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable (obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable (obj[selected].body); } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R) { if (!g) return; if (!pos) pos = dGeomGetPosition (g); if (!R) R = dGeomGetRotation (g); int type = dGeomGetClass (g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths (g,sides); dsDrawBox (pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere (pos,R,dGeomSphereGetRadius (g)); } else if (type == dCCylinderClass) { dReal radius,length; dGeomCCylinderGetParams (g,&radius,&length); dsDrawCappedCylinder (pos,R,length,radius); } else if (type == dGeomTransformClass) { dGeomID g2 = dGeomTransformGetGeom (g); const dReal *pos2 = dGeomGetPosition (g2); const dReal *R2 = dGeomGetRotation (g2); dVector3 actual_pos; dMatrix3 actual_R; dMULTIPLY0_331 (actual_pos,R,pos2); actual_pos[0] += pos[0]; actual_pos[1] += pos[1]; actual_pos[2] += pos[2]; dMULTIPLY0_333 (actual_R,R,R2); drawGeom (g2,actual_pos,actual_R); } } // simulation loop static void simLoop (int pause) { dsSetColor (0,0,2); dSpaceCollide (space,0,&nearCallback); if (!pause) dWorldStep (world,0.05); // remove all contact joints dJointGroupEmpty (contactgroup); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (int i=0; iLength = Length; } dReal dGeomRayGetLength(dxGeom* g){ return ((dxRay*)dGeomGetClassData(g))->Length; } void dGeomRaySet(dxGeom* g, dVector3 Origin, dVector3 Direction){ dGeomSetPosition(g, Origin[0], Origin[1], Origin[2]); dVector3 Up, Right; dPlaneSpace(Direction, Up, Right); Origin[3] = Up[3] = Right[3] = REAL(0.0); dMatrix3 Rotation; Rotation[0 * 4 + 0] = Right[0]; Rotation[1 * 4 + 0] = Right[1]; Rotation[2 * 4 + 0] = Right[2]; Rotation[3 * 4 + 0] = Right[3]; Rotation[0 * 4 + 1] = Up[0]; Rotation[1 * 4 + 1] = Up[1]; Rotation[2 * 4 + 1] = Up[2]; Rotation[3 * 4 + 1] = Up[3]; Rotation[0 * 4 + 2] = Direction[0]; Rotation[1 * 4 + 2] = Direction[1]; Rotation[2 * 4 + 2] = Direction[2]; Rotation[3 * 4 + 2] = Direction[3]; dGeomSetRotation(g, Rotation); } void dGeomRayGet(dxGeom* g, dVector3 Origin, dVector3 Direction){ const dReal* Position = dGeomGetPosition(g); Origin[0] = Position[0]; Origin[1] = Position[1]; Origin[2] = Position[2]; Origin[3] = Position[3]; const dReal* Rotation = dGeomGetRotation(g); Direction[0] = Rotation[0 * 4 + 2]; Direction[1] = Rotation[1 * 4 + 2]; Direction[2] = Rotation[2 * 4 + 2]; Direction[3] = Rotation[3 * 4 + 2]; }ode-0.14/contrib/dRay/dRay_Box.cpp0000644000000000000000000000755212635011627015471 0ustar rootroot// Ripped from Magic Software #include "Include\dRay.h" #include "dxRay.h" bool Clip(dReal Denom, dReal Numer, dReal& T0, dReal& T1){ // Return value is 'true' if line segment intersects the current test // plane. Otherwise 'false' is returned in which case the line segment // is entirely clipped. if (Denom > REAL(0.0)){ if (Numer > Denom * T1){ return false; } if (Numer > Denom * T0){ T0 = Numer / Denom; } return true; } else if (Denom < REAL(0.0)){ if (Numer > Denom * T0){ return false; } if (Numer > Denom * T1){ T1 = Numer / Denom; } return true; } else return Numer <= REAL(0.0); } bool FindIntersection(const dVector3 Origin, const dVector3 Direction, const dVector3 Extents, dReal& T0, dReal& T1){ dReal SaveT0 = T0; dReal SaveT1 = T1; bool NotEntirelyClipped = Clip(+Direction[0], -Origin[0] - Extents[0], T0, T1) && Clip(-Direction[0], +Origin[0] - Extents[0], T0, T1) && Clip(+Direction[1], -Origin[1] - Extents[1], T0, T1) && Clip(-Direction[1], +Origin[1] - Extents[1], T0, T1) && Clip(+Direction[2], -Origin[2] - Extents[2], T0, T1) && Clip(-Direction[2], +Origin[2] - Extents[2], T0, T1); return NotEntirelyClipped && (T0 != SaveT0 || T1 != SaveT1); } int dCollideBR(dxGeom* RayGeom, dxGeom* BoxGeom, int Flags, dContactGeom* Contacts, int Stride){ const dVector3& Position = *(const dVector3*)dGeomGetPosition(BoxGeom); const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(BoxGeom); dVector3 Extents; dGeomBoxGetLengths(BoxGeom, Extents); Extents[0] /= 2; Extents[1] /= 2; Extents[2] /= 2; Extents[3] /= 2; dVector3 Origin, Direction; dGeomRayGet(RayGeom, Origin, Direction); dReal Length = dGeomRayGetLength(RayGeom); dVector3 Diff; Diff[0] = Origin[0] - Position[0]; Diff[1] = Origin[1] - Position[1]; Diff[2] = Origin[2] - Position[2]; Diff[3] = Origin[3] - Position[3]; Direction[0] *= Length; Direction[1] *= Length; Direction[2] *= Length; Direction[3] *= Length; dVector3 Rot[3]; Decompose(Rotation, Rot); dVector3 TransOrigin; TransOrigin[0] = dDOT(Diff, Rot[0]); TransOrigin[1] = dDOT(Diff, Rot[1]); TransOrigin[2] = dDOT(Diff, Rot[2]); TransOrigin[3] = REAL(0.0); dVector3 TransDirection; TransDirection[0] = dDOT(Direction, Rot[0]); TransDirection[1] = dDOT(Direction, Rot[1]); TransDirection[2] = dDOT(Direction, Rot[2]); TransDirection[3] = REAL(0.0); dReal T[2]; T[0] = 0.0f; T[1] = dInfinity; bool Intersect = FindIntersection(TransOrigin, TransDirection, Extents, T[0], T[1]); if (Intersect){ if (T[0] > REAL(0.0)){ dContactGeom* Contact0 = CONTACT(Flags, Contacts, 0, Stride); Contact0->pos[0] = Origin[0] + T[0] * Direction[0]; Contact0->pos[1] = Origin[1] + T[0] * Direction[1]; Contact0->pos[2] = Origin[2] + T[0] * Direction[2]; Contact0->pos[3] = Origin[3] + T[0] * Direction[3]; //Contact0->normal = 0; Contact0->depth = 0.0f; Contact0->g1 = RayGeom; Contact0->g2 = BoxGeom; dContactGeom* Contact1 = CONTACT(Flags, Contacts, 1, Stride); Contact1->pos[0] = Origin[0] + T[1] * Direction[0]; Contact1->pos[1] = Origin[1] + T[1] * Direction[1]; Contact1->pos[2] = Origin[2] + T[1] * Direction[2]; Contact1->pos[3] = Origin[3] + T[1] * Direction[3]; //Contact1->normal = 0; Contact1->depth = 0.0f; Contact1->g1 = RayGeom; Contact1->g2 = BoxGeom; return 2; } else{ dContactGeom* Contact = CONTACT(Flags, Contacts, 0, Stride); Contact->pos[0] = Origin[0] + T[1] * Direction[0]; Contact->pos[1] = Origin[1] + T[1] * Direction[1]; Contact->pos[2] = Origin[2] + T[1] * Direction[2]; Contact->pos[3] = Origin[3] + T[1] * Direction[3]; //Contact->normal = 0; Contact->depth = 0.0f; Contact->g1 = RayGeom; Contact->g2 = BoxGeom; return 1; } } else return 0; }ode-0.14/contrib/dRay/dRay_CCylinder.cpp0000644000000000000000000001236512635011627016613 0ustar rootroot// Ripped from Magic Software #include "Include\dRay.h" #include "dxRay.h" int Find(const dVector3 Origin, dVector3 Direction, dReal Length, const dVector3 CCPos, const dMatrix3 CCRot, dReal CCRadius, dReal CCLength, dReal T[2]){ dVector3 U, V, W; Decompose(CCRot, U, V, W); dVector3 CCOrigin; CCOrigin[0] = CCPos[0] - (W[0] * CCLength / 2); CCOrigin[1] = CCPos[1] - (W[1] * CCLength / 2); CCOrigin[2] = CCPos[2] - (W[2] * CCLength / 2); CCOrigin[3] = CCPos[3] - (W[3] * CCLength / 2); dVector3 D; D[0] = dDOT(U, Direction); D[1] = dDOT(V, Direction); D[2] = dDOT(W, Direction); dReal DMag = Length; dReal InvDMag = REAL(1.0) / DMag; dVector3 Diff; Diff[0] = Origin[0] - CCOrigin[0]; Diff[1] = Origin[1] - CCOrigin[1]; Diff[2] = Origin[2] - CCOrigin[2]; Diff[3] = Origin[3] - CCOrigin[3]; dVector3 P; P[0] = dDOT(U, Diff); P[1] = dDOT(V, Diff); P[2] = dDOT(W, Diff); dReal CCRadiusSq = CCRadius * CCRadius; dReal Epsilon = 1e-12f; if (dFabs(D[2]) >= REAL(1.0) - Epsilon){ // line is parallel to capsule axis dReal Discr = CCRadiusSq - P[0] * P[0] - P[1] * P[1]; if (Discr >= REAL(0.0)){ dReal Root = dSqrt(Discr); T[0] = (-P[2] + Root) * InvDMag; T[1] = (CCLength - P[2] + Root) * InvDMag; return 2; } else return 0; } // test intersection with infinite cylinder dReal A = D[0] * D[0] + D[1] * D[1]; dReal B = P[0] * D[0] + P[1] * D[1]; dReal C = P[0] * P[0] + P[1] * P[1] - CCRadiusSq; dReal Discr = B * B - A * C; if (Discr < REAL(0.0)){ // line does not intersect infinite cylinder return 0; } int Count = 0; if (Discr > REAL(0.0)){ // line intersects infinite cylinder in two places dReal Root = dSqrt(Discr); dReal Inv = REAL(1.0) / A; dReal TTemp = (-B - Root) * Inv; dReal Tmp = P[2] + TTemp * D[2]; if (REAL(0.0) <= Tmp && Tmp <= CCLength){ T[Count++] = TTemp * InvDMag; } TTemp = (-B + Root) * Inv; Tmp = P[2] + TTemp * D[2]; if (REAL(0.0) <= Tmp && Tmp <= CCLength){ T[Count++] = TTemp * InvDMag; } if (Count == 2){ // line intersects capsule wall in two places return 2; } } else{ // line is tangent to infinite cylinder dReal TTemp = -B / A; dReal Tmp = P[2] + TTemp * D[2]; if (REAL(0.0) <= Tmp && Tmp <= CCLength){ T[0] = TTemp * InvDMag; return 1; } } // test intersection with bottom hemisphere // fA = 1 B += P[2] * D[2]; C += P[2] * P[2]; Discr = B * B - C; if (Discr > REAL(0.0)){ dReal Root = dSqrt(Discr); dReal TTemp = -B - Root; dReal Tmp = P[2] + TTemp * D[2]; if (Tmp <= REAL(0.0)){ T[Count++] = TTemp * InvDMag; if (Count == 2){ return 2; } } TTemp = -B + Root; Tmp = P[2] + TTemp * D[2]; if (Tmp <= REAL(0.0)){ T[Count++] = TTemp * InvDMag; if (Count == 2){ return 2; } } } else if (Discr == REAL(0.0)){ dReal TTemp = -B; dReal Tmp = P[2] + TTemp * D[2]; if (Tmp <= REAL(0.0)){ T[Count++] = TTemp * InvDMag; if (Count == 2){ return 2; } } } // test intersection with top hemisphere // fA = 1 B -= D[2] * CCLength; C += CCLength * (CCLength - REAL(2.0) * P[2]); Discr = B * B - C; if (Discr > REAL(0.0)){ dReal Root = dSqrt(Discr); dReal TTemp = -B - Root; dReal Tmp = P[2] + TTemp * D[2]; if (Tmp >= CCLength){ T[Count++] = TTemp * InvDMag; if (Count == 2){ return 2; } } TTemp = -B + Root; Tmp = P[2] + TTemp * D[2]; if (Tmp >= CCLength){ T[Count++] = TTemp * InvDMag; if (Count == 2){ return 2; } } } else if (Discr == REAL(0.0)){ dReal TTemp = -B; dReal Tmp = P[2] + TTemp * D[2]; if (Tmp >= CCLength){ T[Count++] = TTemp * InvDMag; if (Count == 2){ return 2; } } } return Count; } int dCollideCCR(dxGeom* RayGeom, dxGeom* CCGeom, int Flags, dContactGeom* Contacts, int Stride){ const dVector3& CCPos = *(const dVector3*)dGeomGetPosition(CCGeom); const dMatrix3& CCRot = *(const dMatrix3*)dGeomGetRotation(CCGeom); dReal CCRadius, CCLength; dGeomCCylinderGetParams(CCGeom, &CCRadius, &CCLength); dVector3 Origin, Direction; dGeomRayGet(RayGeom, Origin, Direction); dReal Length = dGeomRayGetLength(RayGeom); dReal T[2]; int Count = Find(Origin, Direction, Length, CCPos, CCRot, CCRadius, CCLength, T); int ContactCount = 0; for (int i = 0; i < Count; i++){ if (T[i] >= 0.0){ dContactGeom* Contact = CONTACT(Flags, Contacts, ContactCount, Stride); Contact->pos[0] = Origin[0] + T[i] * Direction[0] * Length; Contact->pos[1] = Origin[1] + T[i] * Direction[1] * Length; Contact->pos[2] = Origin[2] + T[i] * Direction[2] * Length; Contact->pos[3] = Origin[3] + T[i] * Direction[3] * Length; //Contact->normal = 0; Contact->depth = 0.0f; Contact->g1 = RayGeom; Contact->g2 = CCGeom; ContactCount++; } } return ContactCount; }ode-0.14/contrib/dRay/dRay_Plane.cpp0000644000000000000000000000172012635011627015767 0ustar rootroot// Ripped from Paul Bourke #include "Include\dRay.h" #include "dxRay.h" int dCollidePR(dxGeom* RayGeom, dxGeom* PlaneGeom, int Flags, dContactGeom* Contact, int Stride){ dVector3 Plane; dGeomPlaneGetParams(PlaneGeom, Plane); dVector3 Origin, Direction; dGeomRayGet(RayGeom, Origin, Direction); dReal Length = dGeomRayGetLength(RayGeom); dReal Denom = Plane[0] * Direction[0] + Plane[1] * Direction[1] + Plane[2] * Direction[2]; if (dFabs(Denom) < 0.00001f){ return 0; // Ray never hits } float T = -(Plane[3] + Plane[0] * Origin[0] + Plane[1] * Origin[1] + Plane[2] * Origin[2]) / Denom; if (T < 0 || T > Length){ return 0; // Ray hits but not within boundaries } Contact->pos[0] = Origin[0] + T * Direction[0]; Contact->pos[1] = Origin[1] + T * Direction[1]; Contact->pos[2] = Origin[2] + T * Direction[2]; Contact->pos[3] = REAL(0.0); //Contact->normal = 0; Contact->depth = 0.0f; Contact->g1 = RayGeom; Contact->g2 = PlaneGeom; return 1; }ode-0.14/contrib/dRay/dRay_Sphere.cpp0000644000000000000000000000536512635011627016167 0ustar rootroot// Ripped from Magic Software #include "Include\dRay.h" #include "dxRay.h" int dCollideSR(dxGeom* RayGeom, dxGeom* SphereGeom, int Flags, dContactGeom* Contacts, int Stride){ const dVector3& Position = *(const dVector3*)dGeomGetPosition(SphereGeom); dReal Radius = dGeomSphereGetRadius(SphereGeom); dVector3 Origin, Direction; dGeomRayGet(RayGeom, Origin, Direction); dReal Length = dGeomRayGetLength(RayGeom); dVector3 Diff; Diff[0] = Origin[0] - Position[0]; Diff[1] = Origin[1] - Position[1]; Diff[2] = Origin[2] - Position[2]; Diff[3] = Origin[3] - Position[3]; Direction[0] *= Length; Direction[1] *= Length; Direction[2] *= Length; Direction[3] *= Length; dReal A = Length * Length; dReal B = dDOT(Diff, Direction); dReal C = dDOT(Diff, Diff) - (Radius * Radius); dReal Discr = B * B - A * C; if (Discr < REAL(0.0)){ return 0; } else if (Discr > REAL(0.0)){ dReal T[2]; dReal Root = dSqrt(Discr); dReal InvA = REAL(1.0) / A; T[0] = (-B - Root) * InvA; T[1] = (-B + Root) * InvA; if (T[0] >= REAL(0.0)){ dContactGeom* Contact0 = CONTACT(Flags, Contacts, 0, Stride); Contact0->pos[0] = Origin[0] + T[0] * Direction[0]; Contact0->pos[1] = Origin[1] + T[0] * Direction[1]; Contact0->pos[2] = Origin[2] + T[0] * Direction[2]; Contact0->pos[3] = Origin[3] + T[0] * Direction[3]; //Contact0->normal = 0; Contact0->depth = 0.0f; Contact0->g1 = RayGeom; Contact0->g2 = SphereGeom; dContactGeom* Contact1 = CONTACT(Flags, Contacts, 1, Stride); Contact1->pos[0] = Origin[0] + T[1] * Direction[0]; Contact1->pos[1] = Origin[1] + T[1] * Direction[1]; Contact1->pos[2] = Origin[2] + T[1] * Direction[2]; Contact1->pos[3] = Origin[3] + T[1] * Direction[3]; //Contact1->normal = 0; Contact1->depth = 0.0f; Contact1->g1 = RayGeom; Contact1->g2 = SphereGeom; return 2; } else if (T[1] >= REAL(0.0)){ dContactGeom* Contact = CONTACT(Flags, Contacts, 1, Stride); Contact->pos[0] = Origin[0] + T[1] * Direction[0]; Contact->pos[1] = Origin[1] + T[1] * Direction[1]; Contact->pos[2] = Origin[2] + T[1] * Direction[2]; Contact->pos[3] = Origin[3] + T[1] * Direction[3]; //Contact->normal = 0; Contact->depth = 0.0f; Contact->g1 = RayGeom; Contact->g2 = SphereGeom; return 1; } else return 0; } else{ dReal T; T = -B / A; if (T >= REAL(0.0)){ dContactGeom* Contact = CONTACT(Flags, Contacts, 0, Stride); Contact->pos[0] = Origin[0] + T * Direction[0]; Contact->pos[1] = Origin[1] + T * Direction[1]; Contact->pos[2] = Origin[2] + T * Direction[2]; Contact->pos[3] = Origin[3] + T * Direction[3]; //Contact->normal = 0; Contact->depth = 0.0f; Contact->g1 = RayGeom; Contact->g2 = SphereGeom; return 1; } else return 0; } }ode-0.14/contrib/dRay/dxRay.h0000644000000000000000000000233012635011627014503 0ustar rootrootstruct dxRay{ dReal Length; }; inline void Decompose(const dMatrix3 Matrix, dVector3 Right, dVector3 Up, dVector3 Direction){ Right[0] = Matrix[0 * 4 + 0]; Right[1] = Matrix[1 * 4 + 0]; Right[2] = Matrix[2 * 4 + 0]; Right[3] = Matrix[3 * 4 + 0]; Up[0] = Matrix[0 * 4 + 1]; Up[1] = Matrix[1 * 4 + 1]; Up[2] = Matrix[2 * 4 + 1]; Up[3] = Matrix[3 * 4 + 1]; Direction[0] = Matrix[0 * 4 + 2]; Direction[1] = Matrix[1 * 4 + 2]; Direction[2] = Matrix[2 * 4 + 2]; Direction[3] = Matrix[3 * 4 + 2]; } inline void Decompose(const dMatrix3 Matrix, dVector3 Vectors[3]){ Decompose(Matrix, Vectors[0], Vectors[1], Vectors[2]); } inline dContactGeom* CONTACT(int Flags, dContactGeom* Contacts, int Index, int Stride){ dIASSERT(Index >= 0 && Index < (Flags & 0x0ffff)); return ((dContactGeom*)(((char*)Contacts) + (Index * Stride))); } int dCollidePR(dxGeom* RayGeom, dxGeom* PlaneGeom, int Flags, dContactGeom* Contacts, int Stride); int dCollideSR(dxGeom* RayGeom, dxGeom* SphereGeom, int Flags, dContactGeom* Contacts, int Stride); int dCollideBR(dxGeom* RayGeom, dxGeom* BoxGeom, int Flags, dContactGeom* Contacts, int Stride); int dCollideCCR(dxGeom* RayGeom, dxGeom* CCylinderGeom, int Flags, dContactGeom* Contacts, int Stride);ode-0.14/drawstuff/0000775000000000000000000000000012635012023012704 5ustar rootrootode-0.14/drawstuff/Makefile.am0000644000000000000000000000010512635011627014743 0ustar rootrootif ENABLE_DRAWSTUFF SUBDIRS = src dstest EXTRA_DIST = textures endif ode-0.14/drawstuff/dstest/0000775000000000000000000000000012635012023014212 5ustar rootrootode-0.14/drawstuff/dstest/Makefile.am0000644000000000000000000000063212635011627016256 0ustar rootrootnoinst_PROGRAMS= dstest AM_CPPFLAGS = -I$(top_srcdir)/drawstuff/src -I$(top_srcdir)/include dstest_SOURCES= dstest.cpp dstest_LDADD=$(top_builddir)/drawstuff/src/libdrawstuff.la \ @GL_LIBS@ if WIN32 resources.o: $(top_srcdir)/drawstuff/src/resources.rc $(top_srcdir)/drawstuff/src/resource.h $(WINDRES) $(top_srcdir)/drawstuff/src/resources.rc -o resources.o dstest_LDADD += resources.o endif ode-0.14/drawstuff/dstest/dstest.cpp0000644000000000000000000000715512635011627016243 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include #ifndef M_PI #define M_PI (3.14159265358979323846) #endif void start() { // adjust the starting viewpoint a bit float xyz[3],hpr[3]; dsGetViewpoint (xyz,hpr); hpr[0] += 7; dsSetViewpoint (xyz,hpr); } void simLoop (int pause) { float pos[3]; float R[12]; static float a = 0; if (!pause) a += 0.02f; if (a > (2*M_PI)) a -= (float) (2*M_PI); float ca = (float) cos(a); float sa = (float) sin(a); dsSetTexture (DS_WOOD); float b = (a > M_PI) ? (2*(a-(float)M_PI)) : a*2; pos[0] = -0.3f; pos[1] = 0; pos[2] = (float) (0.1f*(2*M_PI*b - b*b) + 0.65f); R[0] = ca; R[1] = 0; R[2] = -sa; R[4] = 0; R[5] = 1; R[6] = 0; R[8] = sa; R[9] = 0; R[10] = ca; dsSetColor (1,0.8f,0.6f); dsDrawSphere (pos,R,0.3f); dsSetTexture (DS_NONE); pos[0] = -0.2f; pos[1] = 0.8f; pos[2] = 0.4f; R[0] = ca; R[1] = -sa; R[2] = 0; R[4] = sa; R[5] = ca; R[6] = 0; R[8] = 0; R[9] = 0; R[10] = 1; float sides[3] = {0.1f,0.4f,0.8f}; dsSetColor (0.6f,0.6f,1); dsDrawBox (pos,R,sides); dsSetTexture (DS_WOOD); float r = 0.3f; // cylinder radius float d = (float)cos(a*2) * 0.4f; float cd = (float)cos(-d/r); float sd = (float)sin(-d/r); pos[0] = -0.2f; pos[1] = -1 + d; pos[2] = 0.3f; R[0] = 0; R[1] = 0; R[2] = -1; R[4] = -sd; R[5] = cd; R[6] = 0; R[8] = cd; R[9] = sd; R[10] = 0; dsSetColor (0.4f,1,1); dsDrawCylinder (pos,R,0.8f,r); pos[0] = 0; pos[1] = 0; pos[2] = 0.2f; R[0] = 0; R[1] = sa; R[2] = -ca; R[4] = 0; R[5] = ca; R[6] = sa; R[8] = 1; R[9] = 0; R[10] = 0; dsSetColor (1,0.9f,0.2f); dsDrawCappedCylinder (pos,R,0.8f,0.2f); } void command (int cmd) { dsPrint ("received command %d (`%c')\n",cmd,cmd); } int main (int argc, char **argv) { // setup pointers to callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = command; fn.stop = 0; fn.path_to_textures = 0; // uses default // run simulation dsSimulationLoop (argc,argv,400,400,&fn); return 0; } ode-0.14/drawstuff/src/0000775000000000000000000000000012635012023013473 5ustar rootrootode-0.14/drawstuff/src/Makefile.am0000644000000000000000000000123712635011627015541 0ustar rootroot# Drawstuff is meant as an aid for testing and not as a full # rendering library. noinst_LTLIBRARIES = libdrawstuff.la libdrawstuff_la_SOURCES = drawstuff.cpp internal.h AM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_builddir)/include \ -I$(top_srcdir)/ode/src \ -DDEFAULT_PATH_TO_TEXTURES='"$(top_srcdir)/drawstuff/textures/"' \ $(X11_CFLAGS) if WIN32 libdrawstuff_la_SOURCES+= windows.cpp resource.h resources.rc libdrawstuff_la_LIBADD = -lwinmm -lgdi32 libdrawstuff_la_LDFLAGS = -no-undefined endif if X11 libdrawstuff_la_SOURCES+= x11.cpp libdrawstuff_la_LIBADD = $(X11_LIBS) endif if OSX libdrawstuff_la_SOURCES+= osx.cpp endif ode-0.14/drawstuff/src/drawstuff.cpp0000644000000000000000000012155412635011627016223 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* simple graphics. the following command line flags can be used (typically under unix) -notex Do not use any textures -noshadow[s] Do not draw any shadows -pause Start the simulation paused -texturepath Inform an alternative textures path TODO ---- manage openGL state changes better */ #ifdef WIN32 #include #endif #include #include "config.h" #ifdef HAVE_APPLE_OPENGL_FRAMEWORK #include #include #else #include #include #endif #include "drawstuff/drawstuff.h" #include "internal.h" //*************************************************************************** // misc #ifndef DEFAULT_PATH_TO_TEXTURES #if 0 #define DEFAULT_PATH_TO_TEXTURES "..\\textures\\" #else #define DEFAULT_PATH_TO_TEXTURES "../textures/" #endif #endif #ifndef M_PI #define M_PI (3.14159265358979323846) #endif // constants to convert degrees to radians and the reverse #define RAD_TO_DEG (180.0/M_PI) #define DEG_TO_RAD (M_PI/180.0) // light vector. LIGHTZ is implicitly 1 #define LIGHTX (1.0f) #define LIGHTY (0.4f) // ground and sky #define SHADOW_INTENSITY (0.65f) #define GROUND_R (0.5f) // ground color for when there's no texture #define GROUND_G (0.5f) #define GROUND_B (0.3f) const float ground_scale = 1.0f/1.0f; // ground texture scale (1/size) const float ground_ofsx = 0.5; // offset of ground texture const float ground_ofsy = 0.5; const float sky_scale = 1.0f/4.0f; // sky texture scale (1/size) const float sky_height = 1.0f; // sky height above viewpoint //*************************************************************************** // misc mathematics stuff static void normalizeVector3 (float v[3]) { float len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; if (len <= 0.0f) { v[0] = 1; v[1] = 0; v[2] = 0; } else { len = 1.0f / (float)sqrt(len); v[0] *= len; v[1] *= len; v[2] *= len; } } static void crossProduct3(float res[3], const float a[3], const float b[3]) { float res_0 = a[1]*b[2] - a[2]*b[1]; float res_1 = a[2]*b[0] - a[0]*b[2]; float res_2 = a[0]*b[1] - a[1]*b[0]; // Only assign after all the calculations are over to avoid incurring memory aliasing res[0] = res_0; res[1] = res_1; res[2] = res_2; } //*************************************************************************** // PPM image object typedef unsigned char byte; class Image { int image_width,image_height; byte *image_data; public: Image (char *filename); // load from PPM file ~Image(); int width() { return image_width; } int height() { return image_height; } byte *data() { return image_data; } }; // skip over whitespace and comments in a stream. static void skipWhiteSpace (char *filename, FILE *f) { int c,d; for(;;) { c = fgetc(f); if (c==EOF) dsError ("unexpected end of file in \"%s\"",filename); // skip comments if (c == '#') { do { d = fgetc(f); if (d==EOF) dsError ("unexpected end of file in \"%s\"",filename); } while (d != '\n'); continue; } if (c > ' ') { ungetc (c,f); return; } } } // read a number from a stream, this return 0 if there is none (that's okay // because 0 is a bad value for all PPM numbers anyway). static int readNumber (char *filename, FILE *f) { int c,n=0; for(;;) { c = fgetc(f); if (c==EOF) dsError ("unexpected end of file in \"%s\"",filename); if (c >= '0' && c <= '9') n = n*10 + (c - '0'); else { ungetc (c,f); return n; } } } Image::Image (char *filename) { FILE *f = fopen (filename,"rb"); if (!f) dsError ("Can't open image file `%s'",filename); // read in header if (fgetc(f) != 'P' || fgetc(f) != '6') dsError ("image file \"%s\" is not a binary PPM (no P6 header)",filename); skipWhiteSpace (filename,f); // read in image parameters image_width = readNumber (filename,f); skipWhiteSpace (filename,f); image_height = readNumber (filename,f); skipWhiteSpace (filename,f); int max_value = readNumber (filename,f); // check values if (image_width < 1 || image_height < 1) dsError ("bad image file \"%s\"",filename); if (max_value != 255) dsError ("image file \"%s\" must have color range of 255",filename); // read either nothing, LF (10), or CR,LF (13,10) int c = fgetc(f); if (c == 10) { // LF } else if (c == 13) { // CR c = fgetc(f); if (c != 10) ungetc (c,f); } else ungetc (c,f); // read in rest of data image_data = new byte [image_width*image_height*3]; if (fread (image_data,image_width*image_height*3,1,f) != 1) dsError ("Can not read data from image file `%s'",filename); fclose (f); } Image::~Image() { delete[] image_data; } //*************************************************************************** // Texture object. class Texture { Image *image; GLuint name; public: Texture (char *filename); ~Texture(); void bind (int modulate); }; Texture::Texture (char *filename) { image = new Image (filename); glGenTextures (1,&name); glBindTexture (GL_TEXTURE_2D,name); // set pixel unpacking mode glPixelStorei (GL_UNPACK_SWAP_BYTES, 0); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); // glTexImage2D (GL_TEXTURE_2D, 0, 3, image->width(), image->height(), 0, // GL_RGB, GL_UNSIGNED_BYTE, image->data()); gluBuild2DMipmaps (GL_TEXTURE_2D, 3, image->width(), image->height(), GL_RGB, GL_UNSIGNED_BYTE, image->data()); // set texture parameters - will these also be bound to the texture??? glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); } Texture::~Texture() { delete image; glDeleteTextures (1,&name); } void Texture::bind (int modulate) { glBindTexture (GL_TEXTURE_2D,name); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, modulate ? GL_MODULATE : GL_DECAL); } //*************************************************************************** // the current drawing state (for when the user's step function is drawing) static float color[4] = {0,0,0,0}; // current r,g,b,alpha color static int tnum = 0; // current texture number //*************************************************************************** // OpenGL utility stuff static void setCamera (float x, float y, float z, float h, float p, float r) { glMatrixMode (GL_MODELVIEW); glLoadIdentity(); glRotatef (90, 0,0,1); glRotatef (90, 0,1,0); glRotatef (r, 1,0,0); glRotatef (p, 0,1,0); glRotatef (-h, 0,0,1); glTranslatef (-x,-y,-z); } // sets the material color, not the light color static void setColor (float r, float g, float b, float alpha) { GLfloat light_ambient[4],light_diffuse[4],light_specular[4]; light_ambient[0] = r*0.3f; light_ambient[1] = g*0.3f; light_ambient[2] = b*0.3f; light_ambient[3] = alpha; light_diffuse[0] = r*0.7f; light_diffuse[1] = g*0.7f; light_diffuse[2] = b*0.7f; light_diffuse[3] = alpha; light_specular[0] = r*0.2f; light_specular[1] = g*0.2f; light_specular[2] = b*0.2f; light_specular[3] = alpha; glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, light_ambient); glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, light_diffuse); glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, light_specular); glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 5.0f); } static void setTransform (const float pos[3], const float R[12]) { GLfloat matrix[16]; matrix[0]=R[0]; matrix[1]=R[4]; matrix[2]=R[8]; matrix[3]=0; matrix[4]=R[1]; matrix[5]=R[5]; matrix[6]=R[9]; matrix[7]=0; matrix[8]=R[2]; matrix[9]=R[6]; matrix[10]=R[10]; matrix[11]=0; matrix[12]=pos[0]; matrix[13]=pos[1]; matrix[14]=pos[2]; matrix[15]=1; glPushMatrix(); glMultMatrixf (matrix); } static void setTransformD (const double pos[3], const double R[12]) { GLdouble matrix[16]; matrix[0]=R[0]; matrix[1]=R[4]; matrix[2]=R[8]; matrix[3]=0; matrix[4]=R[1]; matrix[5]=R[5]; matrix[6]=R[9]; matrix[7]=0; matrix[8]=R[2]; matrix[9]=R[6]; matrix[10]=R[10]; matrix[11]=0; matrix[12]=pos[0]; matrix[13]=pos[1]; matrix[14]=pos[2]; matrix[15]=1; glPushMatrix(); glMultMatrixd (matrix); } // set shadow projection transform static void setShadowTransform() { GLfloat matrix[16]; for (int i=0; i<16; i++) matrix[i] = 0; matrix[0]=1; matrix[5]=1; matrix[8]=-LIGHTX; matrix[9]=-LIGHTY; matrix[15]=1; glPushMatrix(); glMultMatrixf (matrix); } static void drawConvex (const float *_planes, unsigned int _planecount, const float *_points, unsigned int /*_pointcount*/, const unsigned int *_polygons) { unsigned int polyindex=0; for(unsigned int i=0;i<_planecount;++i) { unsigned int pointcount=_polygons[polyindex]; polyindex++; glBegin (GL_POLYGON); glNormal3f(_planes[(i*4)+0], _planes[(i*4)+1], _planes[(i*4)+2]); for(unsigned int j=0;j 0) { float q1[3],q2[3],q3[3]; // sub-vertices for (i=0; i<3; i++) { q1[i] = 0.5f*(p1[i]+p2[i]); q2[i] = 0.5f*(p2[i]+p3[i]); q3[i] = 0.5f*(p3[i]+p1[i]); } float length1 = (float)(1.0/sqrt(q1[0]*q1[0]+q1[1]*q1[1]+q1[2]*q1[2])); float length2 = (float)(1.0/sqrt(q2[0]*q2[0]+q2[1]*q2[1]+q2[2]*q2[2])); float length3 = (float)(1.0/sqrt(q3[0]*q3[0]+q3[1]*q3[1]+q3[2]*q3[2])); for (i=0; i<3; i++) { q1[i] *= length1; q2[i] *= length2; q3[i] *= length3; } drawPatch (p1,q1,q3,level-1); drawPatch (q1,p2,q2,level-1); drawPatch (q1,q2,q3,level-1); drawPatch (q3,q2,p3,level-1); } else { glNormal3f (p1[0],p1[1],p1[2]); glVertex3f (p1[0],p1[1],p1[2]); glNormal3f (p2[0],p2[1],p2[2]); glVertex3f (p2[0],p2[1],p2[2]); glNormal3f (p3[0],p3[1],p3[2]); glVertex3f (p3[0],p3[1],p3[2]); } } // draw a sphere of radius 1 static int sphere_quality = 1; static void drawSphere() { // icosahedron data for an icosahedron of radius 1.0 # define ICX 0.525731112119133606f # define ICZ 0.850650808352039932f static GLfloat idata[12][3] = { {-ICX, 0, ICZ}, {ICX, 0, ICZ}, {-ICX, 0, -ICZ}, {ICX, 0, -ICZ}, {0, ICZ, ICX}, {0, ICZ, -ICX}, {0, -ICZ, ICX}, {0, -ICZ, -ICX}, {ICZ, ICX, 0}, {-ICZ, ICX, 0}, {ICZ, -ICX, 0}, {-ICZ, -ICX, 0} }; static int index[20][3] = { {0, 4, 1}, {0, 9, 4}, {9, 5, 4}, {4, 5, 8}, {4, 8, 1}, {8, 10, 1}, {8, 3, 10}, {5, 3, 8}, {5, 2, 3}, {2, 7, 3}, {7, 10, 3}, {7, 6, 10}, {7, 11, 6}, {11, 0, 6}, {0, 1, 6}, {6, 1, 10}, {9, 0, 11}, {9, 11, 2}, {9, 2, 5}, {7, 2, 11}, }; static GLuint listnum = 0; if (listnum==0) { listnum = glGenLists (1); glNewList (listnum,GL_COMPILE); glBegin (GL_TRIANGLES); for (int i=0; i<20; i++) { drawPatch (&idata[index[i][2]][0],&idata[index[i][1]][0], &idata[index[i][0]][0],sphere_quality); } glEnd(); glEndList(); } glCallList (listnum); } static void drawSphereShadow (float px, float py, float pz, float radius) { // calculate shadow constants based on light vector static int init=0; static float len2,len1,scale; if (!init) { len2 = LIGHTX*LIGHTX + LIGHTY*LIGHTY; len1 = 1.0f/(float)sqrt(len2); scale = (float) sqrt(len2 + 1); init = 1; } // map sphere center to ground plane based on light vector px -= LIGHTX*pz; py -= LIGHTY*pz; const float kx = 0.96592582628907f; const float ky = 0.25881904510252f; float x=radius, y=0; glBegin (GL_TRIANGLE_FAN); for (int i=0; i<24; i++) { // for all points on circle, scale to elongated rotated shadow and draw float x2 = (LIGHTX*x*scale - LIGHTY*y)*len1 + px; float y2 = (LIGHTY*x*scale + LIGHTX*y)*len1 + py; glTexCoord2f (x2*ground_scale+ground_ofsx,y2*ground_scale+ground_ofsy); glVertex3f (x2,y2,0); // rotate [x,y] vector float xtmp = kx*x - ky*y; y = ky*x + kx*y; x = xtmp; } glEnd(); } static void drawTriangle (const float *v0, const float *v1, const float *v2, int solid) { float u[3],v[3],normal[3]; u[0] = v1[0] - v0[0]; u[1] = v1[1] - v0[1]; u[2] = v1[2] - v0[2]; v[0] = v2[0] - v0[0]; v[1] = v2[1] - v0[1]; v[2] = v2[2] - v0[2]; crossProduct3(normal,u,v); normalizeVector3 (normal); glBegin(solid ? GL_TRIANGLES : GL_LINE_STRIP); glNormal3fv (normal); glVertex3fv (v0); glVertex3fv (v1); glVertex3fv (v2); glEnd(); } static void drawTriangleD (const double *v0, const double *v1, const double *v2, int solid) { float u[3],v[3],normal[3]; u[0] = float( v1[0] - v0[0] ); u[1] = float( v1[1] - v0[1] ); u[2] = float( v1[2] - v0[2] ); v[0] = float( v2[0] - v0[0] ); v[1] = float( v2[1] - v0[1] ); v[2] = float( v2[2] - v0[2] ); crossProduct3(normal,u,v); normalizeVector3 (normal); glBegin(solid ? GL_TRIANGLES : GL_LINE_STRIP); glNormal3fv (normal); glVertex3dv (v0); glVertex3dv (v1); glVertex3dv (v2); glEnd(); } // draw a capped cylinder of length l and radius r, aligned along the x axis static int capped_cylinder_quality = 3; static void drawCapsule (float l, float r) { int i,j; float tmp,nx,ny,nz,start_nx,start_ny,a,ca,sa; // number of sides to the cylinder (divisible by 4): const int n = capped_cylinder_quality*4; l *= 0.5; a = float(M_PI*2.0)/float(n); sa = (float) sin(a); ca = (float) cos(a); // draw cylinder body ny=1; nz=0; // normal vector = (0,ny,nz) glBegin (GL_TRIANGLE_STRIP); for (i=0; i<=n; i++) { glNormal3d (ny,nz,0); glVertex3d (ny*r,nz*r,l); glNormal3d (ny,nz,0); glVertex3d (ny*r,nz*r,-l); // rotate ny,nz tmp = ca*ny - sa*nz; nz = sa*ny + ca*nz; ny = tmp; } glEnd(); // draw first cylinder cap start_nx = 0; start_ny = 1; for (j=0; j<(n/4); j++) { // get start_n2 = rotated start_n float start_nx2 = ca*start_nx + sa*start_ny; float start_ny2 = -sa*start_nx + ca*start_ny; // get n=start_n and n2=start_n2 nx = start_nx; ny = start_ny; nz = 0; float nx2 = start_nx2, ny2 = start_ny2, nz2 = 0; glBegin (GL_TRIANGLE_STRIP); for (i=0; i<=n; i++) { glNormal3d (ny2,nz2,nx2); glVertex3d (ny2*r,nz2*r,l+nx2*r); glNormal3d (ny,nz,nx); glVertex3d (ny*r,nz*r,l+nx*r); // rotate n,n2 tmp = ca*ny - sa*nz; nz = sa*ny + ca*nz; ny = tmp; tmp = ca*ny2- sa*nz2; nz2 = sa*ny2 + ca*nz2; ny2 = tmp; } glEnd(); start_nx = start_nx2; start_ny = start_ny2; } // draw second cylinder cap start_nx = 0; start_ny = 1; for (j=0; j<(n/4); j++) { // get start_n2 = rotated start_n float start_nx2 = ca*start_nx - sa*start_ny; float start_ny2 = sa*start_nx + ca*start_ny; // get n=start_n and n2=start_n2 nx = start_nx; ny = start_ny; nz = 0; float nx2 = start_nx2, ny2 = start_ny2, nz2 = 0; glBegin (GL_TRIANGLE_STRIP); for (i=0; i<=n; i++) { glNormal3d (ny,nz,nx); glVertex3d (ny*r,nz*r,-l+nx*r); glNormal3d (ny2,nz2,nx2); glVertex3d (ny2*r,nz2*r,-l+nx2*r); // rotate n,n2 tmp = ca*ny - sa*nz; nz = sa*ny + ca*nz; ny = tmp; tmp = ca*ny2- sa*nz2; nz2 = sa*ny2 + ca*nz2; ny2 = tmp; } glEnd(); start_nx = start_nx2; start_ny = start_ny2; } } // draw a cylinder of length l and radius r, aligned along the z axis static void drawCylinder (float l, float r, float zoffset) { int i; float tmp,ny,nz,a,ca,sa; const int n = 24; // number of sides to the cylinder (divisible by 4) l *= 0.5; a = float(M_PI*2.0)/float(n); sa = (float) sin(a); ca = (float) cos(a); // draw cylinder body ny=1; nz=0; // normal vector = (0,ny,nz) glBegin (GL_TRIANGLE_STRIP); for (i=0; i<=n; i++) { glNormal3d (ny,nz,0); glVertex3d (ny*r,nz*r,l+zoffset); glNormal3d (ny,nz,0); glVertex3d (ny*r,nz*r,-l+zoffset); // rotate ny,nz tmp = ca*ny - sa*nz; nz = sa*ny + ca*nz; ny = tmp; } glEnd(); // draw top cap glShadeModel (GL_FLAT); ny=1; nz=0; // normal vector = (0,ny,nz) glBegin (GL_TRIANGLE_FAN); glNormal3d (0,0,1); glVertex3d (0,0,l+zoffset); for (i=0; i<=n; i++) { if (i==1 || i==n/2+1) setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]); glNormal3d (0,0,1); glVertex3d (ny*r,nz*r,l+zoffset); if (i==1 || i==n/2+1) setColor (color[0],color[1],color[2],color[3]); // rotate ny,nz tmp = ca*ny - sa*nz; nz = sa*ny + ca*nz; ny = tmp; } glEnd(); // draw bottom cap ny=1; nz=0; // normal vector = (0,ny,nz) glBegin (GL_TRIANGLE_FAN); glNormal3d (0,0,-1); glVertex3d (0,0,-l+zoffset); for (i=0; i<=n; i++) { if (i==1 || i==n/2+1) setColor (color[0]*0.75f,color[1]*0.75f,color[2]*0.75f,color[3]); glNormal3d (0,0,-1); glVertex3d (ny*r,nz*r,-l+zoffset); if (i==1 || i==n/2+1) setColor (color[0],color[1],color[2],color[3]); // rotate ny,nz tmp = ca*ny + sa*nz; nz = -sa*ny + ca*nz; ny = tmp; } glEnd(); } //*************************************************************************** // motion model // current camera position and orientation static float view_xyz[3]; // position x,y,z static float view_hpr[3]; // heading, pitch, roll (degrees) // initialize the above variables static void initMotionModel() { view_xyz[0] = 2; view_xyz[1] = 0; view_xyz[2] = 1; view_hpr[0] = 180; view_hpr[1] = 0; view_hpr[2] = 0; } static void wrapCameraAngles() { for (int i=0; i<3; i++) { while (view_hpr[i] > 180) view_hpr[i] -= 360; while (view_hpr[i] < -180) view_hpr[i] += 360; } } // call this to update the current camera position. the bits in `mode' say // if the left (1), middle (2) or right (4) mouse button is pressed, and // (deltax,deltay) is the amount by which the mouse pointer has moved. void dsMotion (int mode, int deltax, int deltay) { float side = 0.01f * float(deltax); float fwd = (mode==4) ? (0.01f * float(deltay)) : 0.0f; float s = (float) sin (view_hpr[0]*DEG_TO_RAD); float c = (float) cos (view_hpr[0]*DEG_TO_RAD); if (mode==1) { view_hpr[0] += float (deltax) * 0.5f; view_hpr[1] += float (deltay) * 0.5f; } else { view_xyz[0] += -s*side + c*fwd; view_xyz[1] += c*side + s*fwd; if (mode==2 || mode==5) view_xyz[2] += 0.01f * float(deltay); } wrapCameraAngles(); } //*************************************************************************** // drawing loop stuff // the current state: // 0 = uninitialized // 1 = dsSimulationLoop() called // 2 = dsDrawFrame() called static int current_state = 0; // textures and shadows static int use_textures=1; // 1 if textures to be drawn static int use_shadows=1; // 1 if shadows to be drawn static Texture *sky_texture = 0; static Texture *ground_texture = 0; static Texture *wood_texture = 0; static Texture *checkered_texture = 0; static Texture *texture[4+1]; // +1 since index 0 is not used #if !defined(macintosh) || defined(ODE_PLATFORM_OSX) void dsStartGraphics (int /*width*/, int /*height*/, dsFunctions *fn) { const char *prefix = DEFAULT_PATH_TO_TEXTURES; if (fn->version >= 2 && fn->path_to_textures) prefix = fn->path_to_textures; char *s = (char*) alloca (strlen(prefix) + 20); strcpy (s,prefix); strcat (s,"/sky.ppm"); texture[DS_SKY] = sky_texture = new Texture (s); strcpy (s,prefix); strcat (s,"/ground.ppm"); texture[DS_GROUND] = ground_texture = new Texture (s); strcpy (s,prefix); strcat (s,"/wood.ppm"); texture[DS_WOOD] = wood_texture = new Texture (s); strcpy (s,prefix); strcat (s,"/checkered.ppm"); texture[DS_CHECKERED] = checkered_texture = new Texture (s); } #else // macintosh void dsStartGraphics (int width, int height, dsFunctions *fn) { // All examples build into the same dir char *prefix = "::::drawstuff:textures"; char *s = (char*) alloca (strlen(prefix) + 20); strcpy (s,prefix); strcat (s,":sky.ppm"); sky_texture = new Texture (s); strcpy (s,prefix); strcat (s,":ground.ppm"); ground_texture = new Texture (s); strcpy (s,prefix); strcat (s,":wood.ppm"); wood_texture = new Texture (s); } #endif void dsStopGraphics() { delete sky_texture; delete ground_texture; delete wood_texture; sky_texture = 0; ground_texture = 0; wood_texture = 0; } static void drawSky (float view_xyz[3]) { glDisable (GL_LIGHTING); if (use_textures) { glEnable (GL_TEXTURE_2D); sky_texture->bind (0); } else { glDisable (GL_TEXTURE_2D); glColor3f (0,0.5,1.0); } // make sure sky depth is as far back as possible glShadeModel (GL_FLAT); glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LEQUAL); glDepthRange (1,1); const float ssize = 1000.0f; static float offset = 0.0f; float x = ssize*sky_scale; float z = view_xyz[2] + sky_height; glBegin (GL_QUADS); glNormal3f (0,0,-1); glTexCoord2f (-x+offset,-x+offset); glVertex3f (-ssize+view_xyz[0],-ssize+view_xyz[1],z); glTexCoord2f (-x+offset,x+offset); glVertex3f (-ssize+view_xyz[0],ssize+view_xyz[1],z); glTexCoord2f (x+offset,x+offset); glVertex3f (ssize+view_xyz[0],ssize+view_xyz[1],z); glTexCoord2f (x+offset,-x+offset); glVertex3f (ssize+view_xyz[0],-ssize+view_xyz[1],z); glEnd(); offset = offset + 0.002f; if (offset > 1) offset -= 1; glDepthFunc (GL_LESS); glDepthRange (0,1); } static void drawGround() { glDisable (GL_LIGHTING); glShadeModel (GL_FLAT); glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LESS); // glDepthRange (1,1); if (use_textures) { glEnable (GL_TEXTURE_2D); ground_texture->bind (0); } else { glDisable (GL_TEXTURE_2D); glColor3f (GROUND_R,GROUND_G,GROUND_B); } // ground fog seems to cause problems with TNT2 under windows /* GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1}; glEnable (GL_FOG); glFogi (GL_FOG_MODE, GL_EXP2); glFogfv (GL_FOG_COLOR, fogColor); glFogf (GL_FOG_DENSITY, 0.05f); glHint (GL_FOG_HINT, GL_NICEST); // GL_DONT_CARE); glFogf (GL_FOG_START, 1.0); glFogf (GL_FOG_END, 5.0); */ const float gsize = 100.0f; const float offset = 0; // -0.001f; ... polygon offsetting doesn't work well glBegin (GL_QUADS); glNormal3f (0,0,1); glTexCoord2f (-gsize*ground_scale + ground_ofsx, -gsize*ground_scale + ground_ofsy); glVertex3f (-gsize,-gsize,offset); glTexCoord2f (gsize*ground_scale + ground_ofsx, -gsize*ground_scale + ground_ofsy); glVertex3f (gsize,-gsize,offset); glTexCoord2f (gsize*ground_scale + ground_ofsx, gsize*ground_scale + ground_ofsy); glVertex3f (gsize,gsize,offset); glTexCoord2f (-gsize*ground_scale + ground_ofsx, gsize*ground_scale + ground_ofsy); glVertex3f (-gsize,gsize,offset); glEnd(); glDisable (GL_FOG); } static void drawPyramidGrid() { // setup stuff glEnable (GL_LIGHTING); glDisable (GL_TEXTURE_2D); glShadeModel (GL_FLAT); glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LESS); // draw the pyramid grid for (int i=-1; i<=1; i++) { for (int j=-1; j<=1; j++) { glPushMatrix(); glTranslatef ((float)i,(float)j,(float)0); if (i==1 && j==0) setColor (1,0,0,1); else if (i==0 && j==1) setColor (0,0,1,1); else setColor (1,1,0,1); const float k = 0.03f; glBegin (GL_TRIANGLE_FAN); glNormal3f (0,-1,1); glVertex3f (0,0,k); glVertex3f (-k,-k,0); glVertex3f ( k,-k,0); glNormal3f (1,0,1); glVertex3f ( k, k,0); glNormal3f (0,1,1); glVertex3f (-k, k,0); glNormal3f (-1,0,1); glVertex3f (-k,-k,0); glEnd(); glPopMatrix(); } } } void dsDrawFrame (int width, int height, dsFunctions *fn, int pause) { if (current_state < 1) dsDebug ("internal error"); current_state = 2; // setup stuff glEnable (GL_LIGHTING); glEnable (GL_LIGHT0); glDisable (GL_TEXTURE_2D); glDisable (GL_TEXTURE_GEN_S); glDisable (GL_TEXTURE_GEN_T); glShadeModel (GL_FLAT); glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LESS); glEnable (GL_CULL_FACE); glCullFace (GL_BACK); glFrontFace (GL_CCW); // setup viewport glViewport (0,0,width,height); glMatrixMode (GL_PROJECTION); glLoadIdentity(); const float vnear = 0.1f; const float vfar = 100.0f; const float k = 0.8f; // view scale, 1 = +/- 45 degrees if (width >= height) { float k2 = float(height)/float(width); glFrustum (-vnear*k,vnear*k,-vnear*k*k2,vnear*k*k2,vnear,vfar); } else { float k2 = float(width)/float(height); glFrustum (-vnear*k*k2,vnear*k*k2,-vnear*k,vnear*k,vnear,vfar); } // setup lights. it makes a difference whether this is done in the // GL_PROJECTION matrix mode (lights are scene relative) or the // GL_MODELVIEW matrix mode (lights are camera relative, bad!). static GLfloat light_ambient[] = { 0.5, 0.5, 0.5, 1.0 }; static GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; static GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; glLightfv (GL_LIGHT0, GL_AMBIENT, light_ambient); glLightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv (GL_LIGHT0, GL_SPECULAR, light_specular); glColor3f (1.0, 1.0, 1.0); // clear the window glClearColor (0.5,0.5,0.5,0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // snapshot camera position (in MS Windows it is changed by the GUI thread) float view2_xyz[3]; float view2_hpr[3]; memcpy (view2_xyz,view_xyz,sizeof(float)*3); memcpy (view2_hpr,view_hpr,sizeof(float)*3); // go to GL_MODELVIEW matrix mode and set the camera glMatrixMode (GL_MODELVIEW); glLoadIdentity(); setCamera (view2_xyz[0],view2_xyz[1],view2_xyz[2], view2_hpr[0],view2_hpr[1],view2_hpr[2]); // set the light position (for some reason we have to do this in model view. static GLfloat light_position[] = { LIGHTX, LIGHTY, 1.0, 0.0 }; glLightfv (GL_LIGHT0, GL_POSITION, light_position); // draw the background (ground, sky etc) drawSky (view2_xyz); drawGround(); // draw the little markers on the ground drawPyramidGrid(); // leave openGL in a known state - flat shaded white, no textures glEnable (GL_LIGHTING); glDisable (GL_TEXTURE_2D); glShadeModel (GL_FLAT); glEnable (GL_DEPTH_TEST); glDepthFunc (GL_LESS); glColor3f (1,1,1); setColor (1,1,1,1); // draw the rest of the objects. set drawing state first. color[0] = 1; color[1] = 1; color[2] = 1; color[3] = 1; tnum = 0; if (fn->step) fn->step (pause); } int dsGetShadows() { return use_shadows; } void dsSetShadows (int a) { use_shadows = (a != 0); } int dsGetTextures() { return use_textures; } void dsSetTextures (int a) { use_textures = (a != 0); } //*************************************************************************** // C interface // sets lighting and texture modes, sets current color static void setupDrawingMode() { glEnable (GL_LIGHTING); if (tnum) { if (use_textures) { glEnable (GL_TEXTURE_2D); texture[tnum]->bind (1); glEnable (GL_TEXTURE_GEN_S); glEnable (GL_TEXTURE_GEN_T); glTexGeni (GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR); glTexGeni (GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR); static GLfloat s_params[4] = {1.0f,1.0f,0.0f,1}; static GLfloat t_params[4] = {0.817f,-0.817f,0.817f,1}; glTexGenfv (GL_S,GL_OBJECT_PLANE,s_params); glTexGenfv (GL_T,GL_OBJECT_PLANE,t_params); } else { glDisable (GL_TEXTURE_2D); } } else { glDisable (GL_TEXTURE_2D); } setColor (color[0],color[1],color[2],color[3]); if (color[3] < 1) { glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } else { glDisable (GL_BLEND); } } static void setShadowDrawingMode() { glDisable (GL_LIGHTING); if (use_textures) { glEnable (GL_TEXTURE_2D); ground_texture->bind (1); glColor3f (SHADOW_INTENSITY,SHADOW_INTENSITY,SHADOW_INTENSITY); glEnable (GL_TEXTURE_2D); glEnable (GL_TEXTURE_GEN_S); glEnable (GL_TEXTURE_GEN_T); glTexGeni (GL_S,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR); glTexGeni (GL_T,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR); static GLfloat s_params[4] = {ground_scale,0,0,ground_ofsx}; static GLfloat t_params[4] = {0,ground_scale,0,ground_ofsy}; glTexGenfv (GL_S,GL_EYE_PLANE,s_params); glTexGenfv (GL_T,GL_EYE_PLANE,t_params); } else { glDisable (GL_TEXTURE_2D); glColor3f (GROUND_R*SHADOW_INTENSITY,GROUND_G*SHADOW_INTENSITY, GROUND_B*SHADOW_INTENSITY); } glDepthRange (0,0.9999); } extern "C" void dsSimulationLoop (int argc, char **argv, int window_width, int window_height, dsFunctions *fn) { if (current_state != 0) dsError ("dsSimulationLoop() called more than once"); current_state = 1; // look for flags that apply to us int initial_pause = 0; for (int i=1; ipath_to_textures = argv[i]; } if (fn->version > DS_VERSION) dsDebug ("bad version number in dsFunctions structure"); initMotionModel(); dsPlatformSimLoop (window_width,window_height,fn,initial_pause); current_state = 0; } extern "C" void dsSetViewpoint (float xyz[3], float hpr[3]) { if (current_state < 1) dsError ("dsSetViewpoint() called before simulation started"); if (xyz) { view_xyz[0] = xyz[0]; view_xyz[1] = xyz[1]; view_xyz[2] = xyz[2]; } if (hpr) { view_hpr[0] = hpr[0]; view_hpr[1] = hpr[1]; view_hpr[2] = hpr[2]; wrapCameraAngles(); } } extern "C" void dsGetViewpoint (float xyz[3], float hpr[3]) { if (current_state < 1) dsError ("dsGetViewpoint() called before simulation started"); if (xyz) { xyz[0] = view_xyz[0]; xyz[1] = view_xyz[1]; xyz[2] = view_xyz[2]; } if (hpr) { hpr[0] = view_hpr[0]; hpr[1] = view_hpr[1]; hpr[2] = view_hpr[2]; } } extern "C" void dsSetTexture (int texture_number) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); tnum = texture_number; } extern "C" void dsSetColor (float red, float green, float blue) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); color[0] = red; color[1] = green; color[2] = blue; color[3] = 1; } extern "C" void dsSetColorAlpha (float red, float green, float blue, float alpha) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); color[0] = red; color[1] = green; color[2] = blue; color[3] = alpha; } extern "C" void dsDrawBox (const float pos[3], const float R[12], const float sides[3]) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glShadeModel (GL_FLAT); setTransform (pos,R); drawBox (sides); glPopMatrix(); if (use_shadows) { setShadowDrawingMode(); setShadowTransform(); setTransform (pos,R); drawBox (sides); glPopMatrix(); glPopMatrix(); glDepthRange (0,1); } } extern "C" void dsDrawConvex (const float pos[3], const float R[12], const float *_planes,unsigned int _planecount, const float *_points, unsigned int _pointcount, const unsigned int *_polygons) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glShadeModel (GL_FLAT); setTransform (pos,R); drawConvex(_planes,_planecount,_points,_pointcount,_polygons); glPopMatrix(); if (use_shadows) { setShadowDrawingMode(); setShadowTransform(); setTransform (pos,R); drawConvex(_planes,_planecount,_points,_pointcount,_polygons); glPopMatrix(); glPopMatrix(); glDepthRange (0,1); } } extern "C" void dsDrawSphere (const float pos[3], const float R[12], float radius) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glEnable (GL_NORMALIZE); glShadeModel (GL_SMOOTH); setTransform (pos,R); glScaled (radius,radius,radius); drawSphere(); glPopMatrix(); glDisable (GL_NORMALIZE); // draw shadows if (use_shadows) { glDisable (GL_LIGHTING); if (use_textures) { ground_texture->bind (1); glEnable (GL_TEXTURE_2D); glDisable (GL_TEXTURE_GEN_S); glDisable (GL_TEXTURE_GEN_T); glColor3f (SHADOW_INTENSITY,SHADOW_INTENSITY,SHADOW_INTENSITY); } else { glDisable (GL_TEXTURE_2D); glColor3f (GROUND_R*SHADOW_INTENSITY,GROUND_G*SHADOW_INTENSITY, GROUND_B*SHADOW_INTENSITY); } glShadeModel (GL_FLAT); glDepthRange (0,0.9999); drawSphereShadow (pos[0],pos[1],pos[2],radius); glDepthRange (0,1); } } extern "C" void dsDrawTriangle (const float pos[3], const float R[12], const float *v0, const float *v1, const float *v2, int solid) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glShadeModel (GL_FLAT); setTransform (pos,R); drawTriangle (v0, v1, v2, solid); glPopMatrix(); } extern "C" void dsDrawCylinder (const float pos[3], const float R[12], float length, float radius) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glShadeModel (GL_SMOOTH); setTransform (pos,R); drawCylinder (length,radius,0); glPopMatrix(); if (use_shadows) { setShadowDrawingMode(); setShadowTransform(); setTransform (pos,R); drawCylinder (length,radius,0); glPopMatrix(); glPopMatrix(); glDepthRange (0,1); } } extern "C" void dsDrawCapsule (const float pos[3], const float R[12], float length, float radius) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glShadeModel (GL_SMOOTH); setTransform (pos,R); drawCapsule (length,radius); glPopMatrix(); if (use_shadows) { setShadowDrawingMode(); setShadowTransform(); setTransform (pos,R); drawCapsule (length,radius); glPopMatrix(); glPopMatrix(); glDepthRange (0,1); } } static void drawLine(const float pos1[3], const float pos2[3]) { glDisable (GL_LIGHTING); glLineWidth (2); glShadeModel (GL_FLAT); glBegin (GL_LINES); glVertex3f (pos1[0],pos1[1],pos1[2]); glVertex3f (pos2[0],pos2[1],pos2[2]); glEnd(); } extern "C" void dsDrawLine (const float pos1[3], const float pos2[3]) { setupDrawingMode(); glColor4f(color[0], color[1], color[2], color[3]); drawLine(pos1, pos2); if (use_shadows) { setShadowDrawingMode(); setShadowTransform(); drawLine(pos1, pos2); glPopMatrix(); glDepthRange (0,1); } } extern "C" void dsDrawBoxD (const double pos[3], const double R[12], const double sides[3]) { int i; float pos2[3],R2[12],fsides[3]; for (i=0; i<3; i++) pos2[i]=(float)pos[i]; for (i=0; i<12; i++) R2[i]=(float)R[i]; for (i=0; i<3; i++) fsides[i]=(float)sides[i]; dsDrawBox (pos2,R2,fsides); } extern "C" void dsDrawConvexD (const double pos[3], const double R[12], const double *_planes, unsigned int _planecount, const double *_points, unsigned int _pointcount, const unsigned int *_polygons) { if (current_state != 2) dsError ("drawing function called outside simulation loop"); setupDrawingMode(); glShadeModel (GL_FLAT); setTransformD (pos,R); drawConvexD(_planes,_planecount,_points,_pointcount,_polygons); glPopMatrix(); if (use_shadows) { setShadowDrawingMode(); setShadowTransform(); setTransformD (pos,R); drawConvexD(_planes,_planecount,_points,_pointcount,_polygons); glPopMatrix(); glPopMatrix(); glDepthRange (0,1); } } void dsDrawSphereD (const double pos[3], const double R[12], float radius) { int i; float pos2[3],R2[12]; for (i=0; i<3; i++) pos2[i]=(float)pos[i]; for (i=0; i<12; i++) R2[i]=(float)R[i]; dsDrawSphere (pos2,R2,radius); } void dsDrawTriangleD (const double pos[3], const double R[12], const double *v0, const double *v1, const double *v2, int solid) { int i; float pos2[3],R2[12]; for (i=0; i<3; i++) pos2[i]=(float)pos[i]; for (i=0; i<12; i++) R2[i]=(float)R[i]; setupDrawingMode(); glShadeModel (GL_FLAT); setTransform (pos2,R2); drawTriangleD (v0, v1, v2, solid); glPopMatrix(); } void dsDrawCylinderD (const double pos[3], const double R[12], float length, float radius) { int i; float pos2[3],R2[12]; for (i=0; i<3; i++) pos2[i]=(float)pos[i]; for (i=0; i<12; i++) R2[i]=(float)R[i]; dsDrawCylinder (pos2,R2,length,radius); } void dsDrawCapsuleD (const double pos[3], const double R[12], float length, float radius) { int i; float pos2[3],R2[12]; for (i=0; i<3; i++) pos2[i]=(float)pos[i]; for (i=0; i<12; i++) R2[i]=(float)R[i]; dsDrawCapsule (pos2,R2,length,radius); } void dsDrawLineD (const double _pos1[3], const double _pos2[3]) { int i; float pos1[3],pos2[3]; for (i=0; i<3; i++) pos1[i]=(float)_pos1[i]; for (i=0; i<3; i++) pos2[i]=(float)_pos2[i]; dsDrawLine (pos1,pos2); } void dsSetSphereQuality (int n) { sphere_quality = n; } void dsSetCapsuleQuality (int n) { capped_cylinder_quality = n; } void dsSetDrawMode(int mode) { switch(mode) { case DS_POLYFILL: glPolygonMode(GL_FRONT,GL_FILL); break; case DS_WIREFRAME: glPolygonMode(GL_FRONT,GL_LINE); break; } } ode-0.14/drawstuff/src/internal.h0000644000000000000000000000424712635011627015476 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* functions supplied and used by the platform specific code */ #ifndef __DS_INTERNAL_H #define __DS_INTERNAL_H #include "drawstuff/drawstuff.h" // supplied by platform specific code void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn, int initial_pause); // used by platform specific code void dsStartGraphics (int width, int height, dsFunctions *fn); void dsDrawFrame (int width, int height, dsFunctions *fn, int pause); void dsStopGraphics(); void dsMotion (int mode, int deltax, int deltay); int dsGetShadows(); void dsSetShadows (int a); int dsGetTextures(); void dsSetTextures (int a); #endif ode-0.14/drawstuff/src/osx.cpp0000644000000000000000000002407712635011627015031 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ // Platform-specific code for Mac OS X using Carbon+AGL // // Created using x11.cpp and the window-initialization -routines from GLFW // as reference. // Not thoroughly tested and is certain to contain deficiencies and bugs #include #include "config.h" #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #include #include #include "internal.h" #include #include // Global variables static bool paused = false; // 1 if in `pause' mode static bool singlestep = false; // 1 if single step key pressed static bool writeframes = false; // 1 if frame files to be written static int windowWidth = -1; static int windowHeight = -1; static int mouseButtonMode = 0; static bool mouseWithOption = false; // Set if dragging the mouse with alt pressed static bool mouseWithControl = false; // Set if dragging the mouse with ctrl pressed static dsFunctions* functions = NULL; static int windowReference; static int frame = 1; static int prev_x = 0; static int prev_y = 0; //*************************************************************************** // error handling for unix static void printMessage (const char *msg1, const char *msg2, va_list ap) { fflush (stderr); fflush (stdout); fprintf (stderr,"\n%s: ",msg1); vfprintf (stderr,msg2,ap); fprintf (stderr,"\n"); fflush (stderr); } extern "C" void dsError (const char *msg, ...) { va_list ap; va_start (ap,msg); printMessage ("Error",msg,ap); va_end (ap); exit (1); } extern "C" void dsDebug (const char *msg, ...) { va_list ap; va_start (ap,msg); printMessage ("INTERNAL ERROR",msg,ap); va_end (ap); // *((char *)0) = 0; ... commit SEGVicide ? abort(); } extern "C" void dsPrint (const char *msg, ...) { va_list ap; va_start (ap,msg); vprintf (msg,ap); va_end (ap); } static void captureFrame( int num ){ fprintf( stderr,"\rcapturing frame %04d", num ); unsigned char buffer[windowWidth*windowHeight][3]; glReadPixels( 0, 0, windowWidth, windowHeight, GL_RGB, GL_UNSIGNED_BYTE, &buffer ); char s[100]; sprintf (s,"frame%04d.ppm",num); FILE *f = fopen (s,"wb"); if( !f ){ dsError( "can't open \"%s\" for writing", s ); } fprintf( f,"P6\n%d %d\n255\n", windowWidth, windowHeight ); for( int y=windowHeight-1; y>-1; y-- ){ fwrite( buffer[y*windowWidth], 3*windowWidth, 1, f ); } fclose (f); } extern "C" void dsStop() { } extern "C" double dsElapsedTime() { #if HAVE_GETTIMEOFDAY static double prev=0.0; timeval tv ; gettimeofday(&tv, 0); double curr = tv.tv_sec + (double) tv.tv_usec / 1000000.0 ; if (!prev) prev=curr; double retval = curr-prev; prev=curr; if (retval>1.0) retval=1.0; if (retval= 'a' && key <= 'z') uppercase = key - ('a' - 'A'); else uppercase = key; int modifierMask = osxGetModifierMask(); if (modifierMask == 0) { if( key >= ' ' && key <= 126 && functions -> command ) functions -> command( key ); } else if (modifierMask & GLUT_ACTIVE_CTRL) { // ctrl+key was pressed uppercase += 'A' - 1; switch(uppercase ){ case 'T': dsSetTextures( !dsGetTextures() ); break; case 'S': dsSetShadows( !dsGetShadows() ); break; case 'X': exit(0); break; case 'P': paused = !paused; singlestep = false; break; case 'O': if( paused ){ singlestep = true; } break; case 'V': { float xyz[3],hpr[3]; dsGetViewpoint( xyz,hpr ); printf( "Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n", xyz[0], xyz[1], xyz[2], hpr[0], hpr[1], hpr[2] ); break; } case 'W': writeframes = !writeframes; if( writeframes ){ printf( "Now writing frames to PPM files\n" ); } break; } } } void osxMouseEventHandler(int button, int state, int x, int y) { prev_x = x; prev_y = y; bool buttonDown = false; switch( state ){ case GLUT_DOWN: buttonDown = true; case GLUT_UP: if( button == GLUT_LEFT_BUTTON ){ int modifierMask = osxGetModifierMask(); if( modifierMask & GLUT_ACTIVE_CTRL ){ // Ctrl+button == right button = GLUT_RIGHT_BUTTON; mouseWithControl = true; } else if( modifierMask & GLUT_ACTIVE_ALT ){ // Alt+button == left+right mouseButtonMode = 5; mouseWithOption = true; return; } } if( buttonDown ){ if( button == GLUT_LEFT_BUTTON ) mouseButtonMode |= 1; // Left if( button == GLUT_MIDDLE_BUTTON ) mouseButtonMode |= 2; // Middle if( button == GLUT_RIGHT_BUTTON ) mouseButtonMode |= 4; // Right } else{ if( button == GLUT_LEFT_BUTTON ) mouseButtonMode &= (~1); // Left if( button == GLUT_MIDDLE_BUTTON ) mouseButtonMode &= (~2); // Middle if( button == GLUT_RIGHT_BUTTON ) mouseButtonMode &= (~4); // Right } return; } } void osxMotionEventHandler(int x, int y) { dsMotion( mouseButtonMode, x - prev_x, y - prev_y ); prev_x = x; prev_y = y; } void osxWindowReshapeEventHandler(int width, int height) { windowWidth = width; windowHeight = height; } static void osxCreateMainWindow( int width, int height ) { int argc = 1; char* argv[2]; argv[0] = (char*)""; argv[1] = NULL; glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(width, height); windowReference = glutCreateWindow("ODE - Drawstuff"); windowWidth = width; windowHeight = height; } void osxRedisplayEventHandler() { dsDrawFrame( windowWidth, windowHeight, functions, paused && !singlestep ); singlestep = false; glutSwapBuffers(); // capture frames if necessary if( !paused && writeframes ){ captureFrame( frame ); frame++; } } void osxTimerEventHandler(int); void osxInstallTimerHandler() { glutTimerFunc(1000/60, osxTimerEventHandler, 0); } void osxTimerEventHandler(int) { glutPostRedisplay(); osxInstallTimerHandler(); } int osxInstallEventHandlers() { glutKeyboardFunc(osxKeyEventHandler); glutMouseFunc(osxMouseEventHandler); glutMotionFunc(osxMotionEventHandler); glutDisplayFunc(osxRedisplayEventHandler); glutReshapeFunc(osxWindowReshapeEventHandler); osxInstallTimerHandler(); return GL_TRUE; } extern void dsPlatformSimLoop( int givenWindowWidth, int givenWindowHeight, dsFunctions *fn, int givenPause ){ functions = fn; paused = givenPause; osxCreateMainWindow( givenWindowWidth, givenWindowHeight ); osxInstallEventHandlers(); dsStartGraphics( windowWidth, windowHeight, fn ); static bool firsttime=true; if( firsttime ) { fprintf ( stderr, "\n" "Simulation test environment v%d.%02d\n" " Ctrl-P : pause / unpause (or say `-pause' on command line).\n" " Ctrl-O : single step when paused.\n" " Ctrl-T : toggle textures (or say `-notex' on command line).\n" " Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n" " Ctrl-V : print current viewpoint coordinates (x,y,z,h,p,r).\n" " Ctrl-W : write frames to ppm files: frame/frameNNN.ppm\n" " Ctrl-X : exit.\n" "\n" "Change the camera position by clicking + dragging in the window.\n" " Left button - pan and tilt.\n" " Right button (or Ctrl + button) - forward and sideways.\n" " Left + Right button (or middle button, or Alt + button) - sideways and up.\n" "\n",DS_VERSION >> 8,DS_VERSION & 0xff ); firsttime = false; } if( fn -> start ) fn->start(); glutMainLoop(); } ode-0.14/drawstuff/src/resource.h0000644000000000000000000000173312635011627015506 0ustar rootroot//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by resources.rc // #define IDD_MSGDLG 101 #define IDR_MENU1 102 #define IDD_ABOUT 103 #define IDR_ACCELERATOR1 104 #define IDC_LIST1 1000 #define IDM_EXIT 40001 #define IDM_ABOUT 40002 #define IDM_PAUSE 40003 #define IDM_PERF_MONITOR 40004 #define IDM_SHADOWS 40005 #define IDM_TEXTURES 40006 #define IDM_SAVE_SETTINGS 40007 #define IDM_SINGLE_STEP 40008 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 108 #define _APS_NEXT_COMMAND_VALUE 40009 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ode-0.14/drawstuff/src/resources.rc0000644000000000000000000000760112635011627016046 0ustar rootroot//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // //#include "afxres.h" // added by RLS to make this work with windres #include "winresrc.h" #define IDC_STATIC (-1) ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUT DIALOG DISCARDABLE 0, 0, 257, 105 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,200,84,50,14 LTEXT "Simulation test environment",IDC_STATIC,7,7,243,8 LTEXT "Change the camera position by clicking + dragging in the main window.", IDC_STATIC,7,24,243,8 LTEXT "Left button - pan and tilt.",IDC_STATIC,25,37,225,8 LTEXT "Right button - forward and sideways.",IDC_STATIC,25,48, 225,8 LTEXT "Left + Right button (or middle button) - sideways and up.", IDC_STATIC,25,59,225,8 END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN //"#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_MENU1 MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Exit\tCtrl+X", IDM_EXIT END POPUP "&Simulation" BEGIN MENUITEM "&Pause\tCtrl+P", IDM_PAUSE MENUITEM "Single Step\tCtrl+O", IDM_SINGLE_STEP MENUITEM "Performance &Monitor", IDM_PERF_MONITOR, GRAYED MENUITEM SEPARATOR MENUITEM "&Shadows\tCtrl+S", IDM_SHADOWS, CHECKED MENUITEM "&Textures\tCtrl+T", IDM_TEXTURES, CHECKED MENUITEM SEPARATOR MENUITEM "S&ave Settings", IDM_SAVE_SETTINGS, GRAYED END POPUP "&Help" BEGIN MENUITEM "&About", IDM_ABOUT END END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_ABOUT, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 250 VERTGUIDE, 25 TOPMARGIN, 7 BOTTOMMARGIN, 98 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE BEGIN "O", IDM_SINGLE_STEP, VIRTKEY, CONTROL, NOINVERT "P", IDM_PAUSE, VIRTKEY, CONTROL, NOINVERT "S", IDM_SHADOWS, VIRTKEY, CONTROL, NOINVERT "T", IDM_TEXTURES, VIRTKEY, CONTROL, NOINVERT "X", IDM_EXIT, VIRTKEY, CONTROL, NOINVERT END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ode-0.14/drawstuff/src/windows.cpp0000644000000000000000000003660212635011627015707 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #if defined(WIN32) || defined(__CYGWIN__)// this prevents warnings when dependencies built #include #endif #include #include #include #include "config.h" #include "resource.h" #include "internal.h" //*************************************************************************** // application globals static HINSTANCE ghInstance = 0; static int gnCmdShow = 0; static HACCEL accelerators = 0; static HWND main_window = 0; //*************************************************************************** // error and message handling static void errorBox (const char *title, const char *msg, va_list ap) { char s[1000]; vsprintf (s,msg,ap); MessageBox (0,s,title,MB_OK | MB_APPLMODAL | MB_ICONEXCLAMATION); } static void dsWarning (const char *msg, ...) { va_list ap; va_start (ap,msg); errorBox ("Warning",msg,ap); va_end (ap); } extern "C" void dsError (const char *msg, ...) { va_list ap; va_start (ap,msg); errorBox ("Error",msg,ap); va_end (ap); exit (1); } extern "C" void dsDebug (const char *msg, ...) { va_list ap; va_start (ap,msg); errorBox ("INTERNAL ERROR",msg,ap); va_end (ap); // *((char *)0) = 0; ... commit SEGVicide ? abort(); exit (1); // should never get here, but just in case... } extern "C" void dsPrint (const char *msg, ...) { va_list ap; va_start (ap,msg); vprintf (msg,ap); va_end (ap); } //*************************************************************************** // rendering thread // globals used to communicate with rendering thread static volatile int renderer_run = 1; static volatile int renderer_pause = 0; // 0=run, 1=pause static volatile int renderer_ss = 0; // single step command static volatile int renderer_width = 1; static volatile int renderer_height = 1; static dsFunctions *renderer_fn = 0; static volatile HDC renderer_dc = 0; static volatile int keybuffer[16]; // fifo ring buffer for keypresses static volatile int keybuffer_head = 0; // index of next key to put in (modified by GUI) static volatile int keybuffer_tail = 0; // index of next key to take out (modified by renderer) static void setupRendererGlobals() { renderer_run = 1; renderer_pause = 0; renderer_ss = 0; renderer_width = 1; renderer_height = 1; renderer_fn = 0; renderer_dc = 0; keybuffer[16]; keybuffer_head = 0; keybuffer_tail = 0; } static unsigned CALLBACK renderingThread (LPVOID lpParam) { // create openGL context and make it current HGLRC glc = wglCreateContext (renderer_dc); if (glc==NULL) dsError ("could not create OpenGL context"); if (wglMakeCurrent (renderer_dc,glc) != TRUE) dsError ("could not make OpenGL context current"); // test openGL capabilities int maxtsize=0; glGetIntegerv (GL_MAX_TEXTURE_SIZE,&maxtsize); if (maxtsize < 128) dsWarning ("max texture size too small (%dx%d)", maxtsize,maxtsize); dsStartGraphics (renderer_width,renderer_height,renderer_fn); if (renderer_fn->start) renderer_fn->start(); while (renderer_run) { // need to make local copy of renderer_ss to help prevent races int ss = renderer_ss; dsDrawFrame (renderer_width,renderer_height,renderer_fn, renderer_pause && !ss); if (ss) renderer_ss = 0; // read keys out of ring buffer and feed them to the command function while (keybuffer_head != keybuffer_tail) { if (renderer_fn->command) renderer_fn->command (keybuffer[keybuffer_tail]); keybuffer_tail = (keybuffer_tail+1) & 15; } // swap buffers SwapBuffers (renderer_dc); } if (renderer_fn->stop) renderer_fn->stop(); dsStopGraphics(); // delete openGL context wglMakeCurrent (NULL,NULL); wglDeleteContext (glc); return 123; // magic value used to test for thread termination } //*************************************************************************** // window handling // callback function for "about" dialog box static LRESULT CALLBACK AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch (wParam) { case IDOK: EndDialog (hDlg, TRUE); return TRUE; } break; } return FALSE; } // callback function for the main window static LRESULT CALLBACK mainWndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { static int button=0,lastx=0,lasty=0; int ctrl = int(wParam & MK_CONTROL); switch (msg) { case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: if (msg==WM_LBUTTONDOWN) button |= 1; else if (msg==WM_MBUTTONDOWN) button |= 2; else button |= 4; lastx = SHORT(LOWORD(lParam)); lasty = SHORT(HIWORD(lParam)); SetCapture (hWnd); break; case WM_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: if (msg==WM_LBUTTONUP) button &= ~1; else if (msg==WM_MBUTTONUP) button &= ~2; else button &= ~4; if (button==0) ReleaseCapture(); break; case WM_MOUSEMOVE: { int x = SHORT(LOWORD(lParam)); int y = SHORT(HIWORD(lParam)); if (button) dsMotion (button,x-lastx,y-lasty); lastx = x; lasty = y; break; } case WM_CHAR: { if (wParam >= ' ' && wParam <= 126) { int nexth = (keybuffer_head+1) & 15; if (nexth != keybuffer_tail) { keybuffer[keybuffer_head] = int(wParam); keybuffer_head = nexth; } } break; } case WM_SIZE: // lParam will contain the size of the *client* area! renderer_width = LOWORD(lParam); renderer_height = HIWORD(lParam); break; case WM_COMMAND: switch (wParam & 0xffff) { case IDM_ABOUT: DialogBox (ghInstance,MAKEINTRESOURCE(IDD_ABOUT),hWnd, (DLGPROC) AboutDlgProc); break; case IDM_PAUSE: { renderer_pause ^= 1; CheckMenuItem (GetMenu(hWnd),IDM_PAUSE, renderer_pause ? MF_CHECKED : MF_UNCHECKED); if (renderer_pause) renderer_ss = 0; break; } case IDM_SINGLE_STEP: { if (renderer_pause) renderer_ss = 1; else SendMessage( hWnd, WM_COMMAND, IDM_PAUSE, 0 ); break; } case IDM_PERF_MONITOR: { dsWarning ("Performance monitor not yet implemented."); break; } case IDM_TEXTURES: { static int tex = 1; tex ^= 1; CheckMenuItem (GetMenu(hWnd),IDM_TEXTURES, tex ? MF_CHECKED : MF_UNCHECKED); dsSetTextures (tex); break; } case IDM_SHADOWS: { static int shadows = 1; shadows ^= 1; CheckMenuItem (GetMenu(hWnd),IDM_SHADOWS, shadows ? MF_CHECKED : MF_UNCHECKED); dsSetShadows (shadows); break; } case IDM_SAVE_SETTINGS: { dsWarning ("\"Save Settings\" not yet implemented."); break; } case IDM_EXIT: PostQuitMessage (0); break; } break; case WM_CLOSE: PostQuitMessage (0); break; default: return (DefWindowProc (hWnd, msg, wParam, lParam)); } return 0; } // this comes from an MSDN example. believe it or not, this is the recommended // way to get the console window handle. static HWND GetConsoleHwnd() { // the console window title to a "unique" value, then find the window // that has this title. char title[1024]; wsprintf (title,"DrawStuff:%d/%d",GetTickCount(),GetCurrentProcessId()); SetConsoleTitle (title); Sleep(40); // ensure window title has been updated return FindWindow (NULL,title); } static void drawStuffStartup() { static int startup_called = 0; if (startup_called) return; startup_called = 1; if (!ghInstance) ghInstance = GetModuleHandleA (NULL); gnCmdShow = SW_SHOWNORMAL; // @@@ fix this later // redirect standard I/O to a new console (except on cygwin and mingw) #if !defined(__CYGWIN__) && !defined(__MINGW32__) FreeConsole(); if (AllocConsole()==0) dsError ("AllocConsole() failed"); if (freopen ("CONIN$","rt",stdin)==0) dsError ("could not open stdin"); if (freopen ("CONOUT$","wt",stdout)==0) dsError ("could not open stdout"); if (freopen ("CONOUT$","wt",stderr)==0) dsError ("could not open stderr"); BringWindowToTop (GetConsoleHwnd()); SetConsoleTitle ("DrawStuff Messages"); #endif // register the window class WNDCLASS wc; wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; wc.lpfnWndProc = mainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInstance; wc.hIcon = LoadIcon (NULL,IDI_APPLICATION); wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); wc.lpszClassName = "SimAppClass"; if (RegisterClass (&wc)==0) dsError ("could not register window class"); // load accelerators accelerators = LoadAccelerators (ghInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1)); if (accelerators==NULL) dsError ("could not load accelerators"); } void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn, int initial_pause) { drawStuffStartup(); setupRendererGlobals(); renderer_pause = initial_pause; // create window - but first get window size for desired size of client area. // if this adjustment isn't made then the openGL area will be shifted into // the nonclient area and determining the frame buffer coordinate from the // client area coordinate will be hard. RECT winrect; winrect.left = 50; winrect.top = 80; winrect.right = winrect.left + window_width; winrect.bottom = winrect.top + window_height; DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; AdjustWindowRect (&winrect,style,1); char title[100]; sprintf (title,"Simulation test environment v%d.%02d", DS_VERSION >> 8,DS_VERSION & 0xff); main_window = CreateWindow ("SimAppClass",title,style, winrect.left,winrect.top,winrect.right-winrect.left,winrect.bottom-winrect.top, NULL,NULL,ghInstance,NULL); if (main_window==NULL) dsError ("could not create main window"); ShowWindow (main_window, gnCmdShow); HDC dc = GetDC (main_window); // get DC for this window if (dc==NULL) dsError ("could not get window DC"); // set pixel format for DC PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version number PFD_DRAW_TO_WINDOW | // support window PFD_SUPPORT_OPENGL | // support OpenGL PFD_DOUBLEBUFFER, // double buffered PFD_TYPE_RGBA, // RGBA type 24, // 24-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 0, // no alpha buffer 0, // shift bit ignored 0, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 32, // 32-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; // get the best available match of pixel format for the device context int iPixelFormat = ChoosePixelFormat (dc,&pfd); if (iPixelFormat==0) dsError ("could not find a good OpenGL pixel format"); // set the pixel format of the device context if (SetPixelFormat (dc,iPixelFormat,&pfd)==FALSE) dsError ("could not set DC pixel format for OpenGL"); // ********** // start the rendering thread // set renderer globals renderer_dc = dc; renderer_width = window_width; renderer_height = window_height; renderer_fn = fn; unsigned threadId; HANDLE hThread; hThread = (HANDLE)_beginthreadex( NULL, // no security attributes 0, // use default stack size &renderingThread, // thread function NULL, // argument to thread function 0, // use default creation flags &threadId); // returns the thread identifier if (hThread==NULL) dsError ("Could not create rendering thread"); // ********** // start GUI message processing MSG msg; while (GetMessage (&msg,main_window,0,0)) { if (!TranslateAccelerator (main_window,accelerators,&msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } // terminate rendering thread renderer_run = 0; DWORD ret = WaitForSingleObject (hThread,2000); if (ret==WAIT_TIMEOUT) dsWarning ("Could not kill rendering thread (1)"); DWORD exitcode=0; if (!(GetExitCodeThread (hThread,&exitcode) && exitcode == 123)) dsWarning ("Could not kill rendering thread (2)"); CloseHandle (hThread); // dont need thread handle anymore // destroy window DestroyWindow (main_window); } extern "C" void dsStop() { // just calling PostQuitMessage() here wont work, as this function is // typically called from the rendering thread, not the GUI thread. // instead we must post the message to the GUI window explicitly. if (main_window) PostMessage (main_window,WM_QUIT,0,0); } extern "C" double dsElapsedTime() { static double prev=0.0; double curr = timeGetTime()/1000.0; if (!prev) prev=curr; double retval = curr-prev; prev=curr; if (retval>1.0) retval=1.0; if (retval #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include #include #include "internal.h" //*************************************************************************** // error handling for unix static void printMessage (const char *msg1, const char *msg2, va_list ap) { fflush (stderr); fflush (stdout); fprintf (stderr,"\n%s: ",msg1); vfprintf (stderr,msg2,ap); fprintf (stderr,"\n"); fflush (stderr); } extern "C" void dsError (const char *msg, ...) { va_list ap; va_start (ap,msg); printMessage ("Error",msg,ap); va_end (ap); exit (1); } extern "C" void dsDebug (const char *msg, ...) { va_list ap; va_start (ap,msg); printMessage ("INTERNAL ERROR",msg,ap); va_end (ap); // *((char *)0) = 0; ... commit SEGVicide ? abort(); } extern "C" void dsPrint (const char *msg, ...) { va_list ap; va_start (ap,msg); vprintf (msg,ap); va_end (ap); } //*************************************************************************** // openGL window // X11 display info static Display *display=0; static int screen=0; static XVisualInfo *visual=0; // best visual for openGL static Colormap colormap=0; // window's colormap static Atom wm_protocols_atom = 0; static Atom wm_delete_window_atom = 0; // window and openGL static Window win=0; // X11 window, 0 if not initialized static int width=0,height=0; // window size static GLXContext glx_context=0; // openGL rendering context static int last_key_pressed=0; // last key pressed in the window static int run=1; // 1 if simulation running static int pausemode=0; // 1 if in `pause' mode static int singlestep=0; // 1 if single step key pressed static int writeframes=0; // 1 if frame files to be written static void createMainWindow (int _width, int _height) { // create X11 display connection display = XOpenDisplay (NULL); if (!display) dsError ("can not open X11 display"); screen = DefaultScreen(display); // get GL visual static int attribListDblBuf[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE,16, GLX_RED_SIZE,4, GLX_GREEN_SIZE,4, GLX_BLUE_SIZE,4, None}; static int attribList[] = {GLX_RGBA, GLX_DEPTH_SIZE,16, GLX_RED_SIZE,4, GLX_GREEN_SIZE,4, GLX_BLUE_SIZE,4, None}; visual = glXChooseVisual (display,screen,attribListDblBuf); if (!visual) visual = glXChooseVisual (display,screen,attribList); if (!visual) dsError ("no good X11 visual found for OpenGL"); // create colormap colormap = XCreateColormap (display,RootWindow(display,screen), visual->visual,AllocNone); // initialize variables win = 0; width = _width; height = _height; glx_context = 0; last_key_pressed = 0; if (width < 1 || height < 1) dsDebug (0,"bad window width or height"); // create the window XSetWindowAttributes attributes; attributes.background_pixel = BlackPixel(display,screen); attributes.colormap = colormap; attributes.event_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | ButtonMotionMask | PointerMotionHintMask | StructureNotifyMask; win = XCreateWindow (display,RootWindow(display,screen),50,50,width,height, 0,visual->depth, InputOutput,visual->visual, CWBackPixel | CWColormap | CWEventMask,&attributes); // associate a GLX context with the window glx_context = glXCreateContext (display,visual,0,GL_TRUE); if (!glx_context) dsError ("can't make an OpenGL context"); // set the window title XTextProperty window_name; window_name.value = (unsigned char *) "Simulation"; window_name.encoding = XA_STRING; window_name.format = 8; window_name.nitems = strlen((char *) window_name.value); XSetWMName (display,win,&window_name); // participate in the window manager 'delete yourself' protocol wm_protocols_atom = XInternAtom (display,"WM_PROTOCOLS",False); wm_delete_window_atom = XInternAtom (display,"WM_DELETE_WINDOW",False); if (XSetWMProtocols (display,win,&wm_delete_window_atom,1)==0) dsError ("XSetWMProtocols() call failed"); // pop up the window XMapWindow (display,win); XSync (display,win); } static void destroyMainWindow() { glXDestroyContext (display,glx_context); XDestroyWindow (display,win); XSync (display,0); XCloseDisplay(display); display = 0; win = 0; glx_context = 0; } static void handleEvent (XEvent &event, dsFunctions *fn) { static int mx=0,my=0; // mouse position static int mode = 0; // mouse button bits switch (event.type) { case ButtonPress: { if (event.xbutton.button == Button1) mode |= 1; if (event.xbutton.button == Button2) mode |= 2; if (event.xbutton.button == Button3) mode |= 4; mx = event.xbutton.x; my = event.xbutton.y; } return; case ButtonRelease: { if (event.xbutton.button == Button1) mode &= (~1); if (event.xbutton.button == Button2) mode &= (~2); if (event.xbutton.button == Button3) mode &= (~4); mx = event.xbutton.x; my = event.xbutton.x; } return; case MotionNotify: { if (event.xmotion.is_hint) { Window root,child; unsigned int mask; XQueryPointer (display,win,&root,&child,&event.xbutton.x_root, &event.xbutton.y_root,&event.xbutton.x,&event.xbutton.y, &mask); } dsMotion (mode, event.xmotion.x - mx, event.xmotion.y - my); mx = event.xmotion.x; my = event.xmotion.y; } return; case KeyPress: { KeySym key; XLookupString (&event.xkey,NULL,0,&key,0); if ((event.xkey.state & ControlMask) == 0) { if (key >= ' ' && key <= 126 && fn->command) fn->command (key); } else if (event.xkey.state & ControlMask) { switch (key) { case 't': case 'T': dsSetTextures (dsGetTextures() ^ 1); break; case 's': case 'S': dsSetShadows (dsGetShadows() ^ 1); break; case 'x': case 'X': run = 0; break; case 'p': case 'P': pausemode ^= 1; singlestep = 0; break; case 'o': case 'O': if (pausemode) singlestep = 1; break; case 'v': case 'V': { float xyz[3],hpr[3]; dsGetViewpoint (xyz,hpr); printf ("Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n", xyz[0],xyz[1],xyz[2],hpr[0],hpr[1],hpr[2]); break; } case 'w': case 'W': writeframes ^= 1; if (writeframes) printf ("Now writing frames to PPM files\n"); break; } } last_key_pressed = key; // a kludgy place to put this... } return; case KeyRelease: { // hmmmm... } return; case ClientMessage: if (event.xclient.message_type == wm_protocols_atom && event.xclient.format == 32 && Atom(event.xclient.data.l[0]) == wm_delete_window_atom) { run = 0; return; } return; case ConfigureNotify: width = event.xconfigure.width; height = event.xconfigure.height; return; } } // return the index of the highest bit static int getHighBitIndex (unsigned int x) { int i = 0; while (x) { i++; x >>= 1; } return i-1; } // shift x left by i, where i can be positive or negative #define SHIFTL(x,i) (((i) >= 0) ? ((x) << (i)) : ((x) >> (-i))) static void captureFrame (int num) { fprintf (stderr,"capturing frame %04d\n",num); char s[100]; sprintf (s,"frame/frame%04d.ppm",num); FILE *f = fopen (s,"wb"); if (!f) dsError ("can't open \"%s\" for writing",s); fprintf (f,"P6\n%d %d\n255\n",width,height); XImage *image = XGetImage (display,win,0,0,width,height,~0,ZPixmap); int rshift = 7 - getHighBitIndex (image->red_mask); int gshift = 7 - getHighBitIndex (image->green_mask); int bshift = 7 - getHighBitIndex (image->blue_mask); for (int y=0; yred_mask,rshift); b[1] = SHIFTL(pixel & image->green_mask,gshift); b[2] = SHIFTL(pixel & image->blue_mask,bshift); fwrite (b,3,1,f); } } fclose (f); XDestroyImage (image); } void processDrawFrame(int *frame, dsFunctions *fn) { dsDrawFrame (width,height,fn,pausemode && !singlestep); singlestep = 0; glFlush(); glXSwapBuffers (display,win); XSync (display,0); // capture frames if necessary if (pausemode==0 && writeframes) { captureFrame (*frame); (*frame)++; } } void microsleep(int usecs) { #ifdef HAVE_UNISTD_H usleep(usecs); #endif } void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn, int initial_pause) { pausemode = initial_pause; createMainWindow (window_width, window_height); glXMakeCurrent (display,win,glx_context); dsStartGraphics (window_width,window_height,fn); static bool firsttime=true; if (firsttime) { fprintf ( stderr, "\n" "Simulation test environment v%d.%02d\n" " Ctrl-P : pause / unpause (or say `-pause' on command line).\n" " Ctrl-O : single step when paused.\n" " Ctrl-T : toggle textures (or say `-notex' on command line).\n" " Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n" " Ctrl-V : print current viewpoint coordinates (x,y,z,h,p,r).\n" " Ctrl-W : write frames to ppm files: frame/frameNNN.ppm\n" " Ctrl-X : exit.\n" "\n" "Change the camera position by clicking + dragging in the window.\n" " Left button - pan and tilt.\n" " Right button - forward and sideways.\n" " Left + Right button (or middle button) - sideways and up.\n" "\n",DS_VERSION >> 8,DS_VERSION & 0xff ); firsttime = false; } if (fn->start) fn->start(); #if HAVE_GETTIMEOFDAY timeval tv; gettimeofday(&tv, 0); double prev = tv.tv_sec + (double) tv.tv_usec / 1000000.0 ; #endif int frame = 1; run = 1; while (run) { // read in and process all pending events for the main window XEvent event; while (run && XPending (display)) { XNextEvent (display,&event); handleEvent (event,fn); } #if HAVE_GETTIMEOFDAY gettimeofday(&tv, 0); double curr = tv.tv_sec + (double) tv.tv_usec / 1000000.0 ; if (curr-prev >= 1.0/60.0) { prev = curr; processDrawFrame(&frame, fn); } else microsleep(1000); #else processDrawFrame(&frame, fn); #endif }; if (fn->stop) fn->stop(); dsStopGraphics(); destroyMainWindow(); } extern "C" void dsStop() { run = 0; } extern "C" double dsElapsedTime() { #if HAVE_GETTIMEOFDAY static double prev=0.0; timeval tv ; gettimeofday(&tv, 0); double curr = tv.tv_sec + (double) tv.tv_usec / 1000000.0 ; if (!prev) prev=curr; double retval = curr-prev; prev=curr; if (retval>1.0) retval=1.0; if (retvalB9owulttslnv}{|||ultnv{{u{{u{{|lksmk{{}{{|z{||red{u{lri|z||{tttsl||{ttslezl|uzt{u{{u{ztl{{tllduslesle}tt{j]\f]cf]cultultlks{ttedk\[b{{llkddc]bZ{{tlld{tt}]cd{u{ttsUTS|zttsuztekdlld|ztl\[bmttlksSKJ{ttlrikk]dc\UUYsle[[TjcVmttkd\||rg]tts{||tllsleJHFddcdc\b[Uult{||\[[:97zll{{ttslztlsreUMRztltts\UZ{{t{{tttslek}|ult{{t}kk]d\\{u{vtzltslzlllrif]c|uutUTSulttzlf]c||ult{u{{u{|}ldd[TTSKJ{{t~ztl{tt{ttreddc\{tt{||uztSKJ{zmek]lrittslddvu{{UMRultD;9UTSLKRlri{u{{u{{{{{tt{lekttslri}tts]cd{{u{{{{lksmtt{{^fs|mtt{{~tt{tll{{{|||zedk||{ttSKJ{tt}|j]\tllJHF{{{{lri|zdc\tsl{||{{{{kd\ztl\UZ}|{||f]cv~f]c{{{tt||lek|u{ttuztulttts}||}}lld}{ttu{{ultlks{{tts|z\UZllk[TTddctsl]bZtzlSKJreduztu{{ldd}|{ttekdztfred[[T{{tek]redllk}[TT:97zllkk]d\\kd\lldred\[bf]clldlri{u{{||tzllddf]c|llkult{zmztl}v{kd\ttslks}mttu{{mttuzt]cdultut||[[T|{tt|{||||lri||ztlbVZ[[T||cbVlldMRKd\\ekd}SKJj]\SKJUMRult{zm|mw{{}}ult{{|]cd]cd}lkslkstt{{{\[b{{f]cmtt{zm}v{Ó{zmtts|]cdlektsltt{ztltts|ztsl{zmtslultu{{tll|v|tlltsl{{}b[Uv{}v{ldd{{fkk}UTS}{|||llk{tt{{t}tlllekv}ldd{u{||tt{|{u{cbV|lldiq]jV[}ztltslSKJutVTLlrivlriUTSlddJHFFD;llkttsSKJ:97lld{u{||rg]JHFlek[[T|zekdlddbVU|zVTLek]|zdc\|z}||tsltllut{||tt{llkekdtllu{{t[[T{{|z{{VTLtt{tlltts}tsl{tttts[TTyl{u{lddekdVTLUMRwlsre{u{kd\lksu{{\UZf]csleg\rredmttv{{||{u{}||lek{||{{{{{||}{{tt{|mttmtt^fs{{|{{{{{{|}ă}lddv{tlluzttsl{{tf]cJHFf]culttt{u||[[Tsle[[Tkd\f]c||tt{\UZ{{|\[blkslri]bZttssle{ttttszllkd\tllult}lekmttedk{{{{{{{{lld|zlldlrittscbVUTStt{|z\[[{{t\UZ{ttttssreslerfk|||u{ttfkkddc[[TllkzlmttlriztlUMR:97||ukd\ztlu{{ylekd\{tttllek]llk|{tt||{||wl}]bZlriuztldd}{{t|uuztult{{ult{||||||z{{f]czllult||SKJ{ttsleuzt||{{MRKUMRlekf]c{ttdc\tlld\\tsltllj]\VTLVTLutt{vtsl|[[T[TT\UZultzllultedkldd|z{u{lddddc{{tts{{{{yllks|\UZmtt|{{nv{{|{{nv{{{{}u{{}lriuztllklek{||f]c\[[llk|z{ttultmwlekb[Ulrimttf]csle{ttVZ[mtt]cdnv|lks]bZzlltslldd{ttultfkku{{{{lddtsl\[[lri{{ttt{d\\VTL||ttslrikd\|SKJaWM[[Tf]c[TTVTLlldlriJHFUUYsle||ldd||{ttultedkvlritsltts{{||{zmultntzlsretts|zztl{tt{{t{{|ztllut|]bZkd\{u{ztlldd{{d\\edktt{||UUY[[TLKR{{f]cultttslksultUMRlksddc\UZ\UZlek}rfk}|tsl|{{tulttts}{||tllf]cmtt{{tj]\f]c}mk{tt|zmttu{{lks{{|lksult\UZtlllek\[b|^^q\[[mtt|n{{MSSult{{~{{^fs}{||}|llk{tt|]bZ|}{{uttll|u||{{t||lri|ztt{{||SKJekd{{t|{{lri||{{tuzt{u{}mttfkkult|uuztuztlksultttsb[U|zultlek|||srerg]||d\\ddcztllldFD;f]clkskk]|z|zllk3+*ttsUMRf]cr]g{u{tsllek{zmsletzllek}}ttsldd|zztl{{t{u{{||}||}|}|kd\ult{{tsl|}{u{[[Tddclld{||VTLJHFVZTtsllks{u{{||{{t{{\[[\[[}f]c{ttlldttsf]c|uttskk]aWMVTLedklksmtt||f]clddtt{\[bult{||{{{u{|{{t}{{ttsttsmtt\[bedk\[bmtt{{mttnv~{{tttssre|tts{||||tts|z}|z}{{t|zwlu{u{ulttt{lek\[[||{||llk{{\[blks}}VZ[UMRedkuzt}{{tfkk{{{{{{f]c}ultult[[Tmttfkklek{tt{tt|ddckk]yfdtts||kk]|ttsSKJtt{tzl[[T]cdlek}UTS*)(ultbVZlek{{t{u{||{{wluztlriu{{{||f]cu{{|z||}|ultrg]wlsleut||{tt|tt{{{t|z|uztf]c[TTddctlld\\tllkd\ldd\[[ultttsekdlkslks||UTSd\\llkVTLtt{tts|{||{||[[Tg\rLKRlksf]cek]dc\VTLkd\]cd]cdek]||}ult|llklksmtt{{{{|{{edk|\[[edk{{{{vuzt{{{{tt{}{u{|ztsllksultult||tll||{||]bZttstt{\[[lri|ztzl]bZttsu{{tllwl}u|zedkuztu{{{{mttult{{t{{lri\[b]cdmtt|zz}lri|lksf]c|u{{\UZ}|ult}tll{tt|uUMRllk{{tlksultlks{u{mtttts}}[[TSKJbVZ}tt{}[TTllktslkd\||sle|ztll{{tllk74,SKJtllddcmttldd{{tslef]cslesle|lri|z|u{tt|usre|lldmtt|ddctt{{u{tslr]Zu{{|uultllkfkkSKJ]bZ]bZF=CF=Cmttlri|{{ttsllkstlltts]bZlekuzt|ddclkslrid\\sleu{{slesred\\cbVtll}uztlritll{tt{{llk{u{}lks|{{|tt{||nv|{{lks{||}{{tlltts[TT{tt}v{ztl||mtt{u{{||SKJ|u{{t~{{|edk|tsltzl{{t{{lektt{{{mttldd]cdvlksu{{\[bUUYmtt|{{{{VZ[|mtttt{lkslksult\[[dc\||UMRyflreddc\j]\j]\{ttllkedkb[Uultult]cddc\[TTVTLtll[[Ttllr]g}{{tekdultbVZj]\UTSC8.JHFlddJHF!ekd{{{{tultllksle|zb[U{{|||}{tt}v{|ttssleuf]c}mtt{{tlri|{||tt{dc\tllekdlldvmkmtt{|||rfkekd[TTekdlldmttek]}lek\UZVTLlks}redultd\\{{{||}\[[ddcult{||}lks|tts|v||~|lks{u{ldd{{mttMSSUTStts~ztlv|]bZcbV|z\UZddc\[[[TT{|||mtt\UZlksultJHF\[bUMR}|||ult{{tult||z~{{}f]c[TTleksleztl{u{red{ttrfkult|ddcztl|||j]\u|cbVddcztlllk}kd\u{{t||{zmMRK*)(|ztlltts[TTlriredtsl|}lld||n||u}{zmlriztlbVU{tt|ztt{uzttts|z||ttsmttUTS^^qlks{u{{{{||lddztldc\ult}||}{{}\UZ{{||}~|{u{uzt{{|ultmttedk{ttllkult|ult|z|{||tzlsle{|||]bZult{||{zm||{{|z{{t}{{t{{t|{{tdc\tsl[TTkk]f]cf]c{{tt{tt{lek|tt{fkkmtt]cd}|Ù{{ult|}{||tsl{||llkedk}||{u{ldd{tt||slesle{{tj]\}kd\ek]dc\ekdredVTLb[UVTL]bZSKJlksVTL*)(|{u{{u{ztlttsutsre|u{{b[U|zultut|iq]{{t{||b[U{zm{{t|z{||{u{tt{tt{tslmttuzt|z}ttsuztlritsl]cdMRKllkmtttll\[[|ztl{{{{t{tt|utsl{tt|zbVZ}}{ttmttlldSKJlddJHF|z}|}lrimttmtt{{|}wl~mtt|ztt{|{||ultu{{mttmttlks{||lks|ddcf]c{{{u{lks[TT\[[dc\|ztsl|z}}{{d\\llktsl{{t}ttsdc\ult[[TUUYlriuztMRKtllllkylddc{{ult{||}tt{ztl{||tsltt{u{{ddc\[blldlddedkdc\{{tlldj]\{ttSKJSKJ]bZlridc\d\\j]\j]\lddekdttsUTS*)({tti\Vldd{tt}zllsre{{t{{tllktsllrid\\yle||{u{lldyletts}|{||d\\|u|{|||lrikd\kd\uztu{{uzt]cdUMR]cdddcd\\]bZult\UZd\\nsleu{{||{ttf]c{{tdc\|}JHF{tt[TT|utsl|mwUMRttslksultlkstts{u{{{||{||{{t|lks{{{{{{{{{{{{nvlksnjultu{{ut{{tts{{{||\UZult]cdult{ttultllk|ultedktts\[bf]cult{u{{{ttsmtt|tt{mtt{{}lld|zdc\v{tts|zd\\lks|d\\red{{}\[[tslSKJ||tsl{ttultdkVSKJVTLVZTmtt\UZredtllztl\[[SKJ{{tJHF*)(dc\ultd\\i\V{tt|~sred\\v{lldek]f]c|z||zlltll{tttt{|z|llk|||}ek]|cbVlldmttd\\lldllkedk{{llkulttts~bVU[[T|sreddcttsf]cv|||sleb[U|utt{d\\\[bLKR{{llku{{{||}rfk}{{{u{zllu{{ultult{{{{{{tsl}|{||lldmttlrittsslemtt\[bult}|zuztlldttslriurfk}dc\JHFf]cultlldult{u{f]c}{||mttlld{{}{u{ztl|z{{ttslsleudc\ztl|tzlslelksekd{{t{||ultleksleUTS{||d\\slett{vldd{ttsle{{tUUYztlult|sremttSKJcbVF=C*)(d\\tts[TTv{{tt{{tu{zmultred{{t}lddllk|z\[blld{{|uu|ult|zf]c|z}ttsu{{]cdJHF}[[Tf]c\[[tt{ulttlllri{{}lekedkllk|z|u|udc\llkb[Ui\VUTSlddUMRkd\VTLrg]f]cf]c|u|v{{{||tll}|uztlks{{{{|}{{^fs}|~}tll|tt{tsllriullk}lektt{}lldf]ctts{tt|uztj]\|}tzl}ukjV||ztltll\[[ddcultult{u{{{tlluzt|utll{{|{{{u{u{{{||]bZlriUTSd\\u{{f]c}ult{||d\\{ttsle|uztl}u{{|{||{u{||{|||||u}JHF[TTkd\VTL74,ulttslttsbVU|wl[TTsle{tt{ttultvleklldlriekd||tll|ut|u}|{|||z{tt{{t|zulttslult}{||ekdf]cUMRVZ[\[b}||u{{ek][TTlri{{|ddclridc\j]\lriultlek}[TT}}{{~|tt{}uztlri}|zu{{lriuzt{||lkstt{{{||lld||z|||ztts{ttlekUTStts}}|{zm{{tv{ttsVTLlldlldSKJlekedkuzttts}}{u{{ttult~tts||mttf]c}lldv{}tt{ztlrfkultbVUu{{|ultslev{{}{||cbV{{tedk{||JHF*)({{lddttsztlultcbV||rfk{zm}tllj]\uztuztztflddd\\|tt{u|{||lri{{t|llklek{||||tts||}mtt}d\\{||srett{lekztltzlkd\|kk]kd\{zm}{ttu{{lrilldf]cztl~{{tddcvmttrfkUTStsl{{|lldtslylult{||mtt{||{{tleku{{}|{u{lriuzt{u{ē}bVZsleult}lekrg]sle}lri{zmtzl{{t[[Tllduztu{{mtt}]bZultu{u{ulttsllksVZT{{u{{}{u{}{{}lldsle|z{{ttslkd\ultlksult}ddcu{{bVZ[TTd\\{tt{tttygtts{{tlektllkd\|ulkslldtslFD;*)(|vtt{rg]||utsltsltll{u{kd\|vztllriedk{{|uultzllld{{}lldf]c}{{ttlltts|\[[rfk||uzt|zu{{lri{{{{|z||}{tt}rg]{{t|z}}|zlriuzt}leklldllk~u{{llk{u{||{||tts{||vtts{ttf]ctt{|{{t{{tddc}u{{tts{{|mtttt{u{{{{|||{u{edk{{u{{redtll}VTLztl}usleztlVTL{u{}f]c|u{{mtttt{lks||z||u{{~bVUtsl~JHFek]lks\[[lrilri\UZbVUultkd\zll[TTd\\uzt|usred\\uztmw[[TSKJ|JHFd\\ultJHF*)(|uztlredulekrg]ztlult}sreult|zttsfkk|z}srellk{u{{||{u{lldu{{|uztultLKRVTL\UZlekuzttts{u{[[T{{lldultllk||uztl}redvlddtsl{ttuztlldlks||~lri[TTtslf]cuttsltllv{}||||lks|||zult{{||{{{{}{u{llkĂvyfd||rfk}{||ztluztlri|lrillktt{|{{]cd]cdmttfkkfkk{{Ù|}|{{mtt{||lldlrikk]lldddc|zlld||ddcldd{{{{JHFUUYu{{lddJHFf]cldd||ttsllklriv{ddclldj]\dc\}}lri|JHFJHFuztlld{ttztlllkjV[|z|zkd\uzttsl}|zztl}tsltts{tt{||ult|zlekuzt]bZMRKlld]bZ|tt{{{tllk||u{{||zbVUtsllldfkk|tslsred\\fkkldd}|{{t}{||tts]bZ{u{~|||{u{tts{||f]c|u|tts~ldduztu{{|}||mtt|{{||ttstt{uzt{ttut~}~f]cmw}llklektts{{lrilriedkultJHFlks{{{{lksedk|z|zlks|zuzt}|}|uVTL|v}slerr]tzl|z|[TT|lri}|tslUTSd\\|ekduztyl[[T}~VZTlekvlldultztlf]c{ttF=Ckk]rg]UTS*)(slej]\}||uldd}}ttsrg]sle|utt{VTLsleztl}zll|}u{{{{tts|zlriUTSJHF[TT{{{{}|uzt{{t{||fkktslmttsre{ttu{{}b[U}{||tzlkd\74,{u{ztl}ztl||uztmtt{u{f]clrid\\lddttsultult}[TTlks{{|z|fkk||{{ttsu{{]cdtts{u{||\[[}|kd\{zmttsekdttsf]ctlldc\tzlJHF{||lkstll{{lkszlld\\dc\v{redv|{u{f]cedku{{~llkekduzt|zttsmtt}{||tllkk]{||tllllklri|zVTLek]dc\|z|dc\{{t{||lksmttultmtt{{}{{|[TTsresle{||lld]bZrr]JHFttsJHF{zm|uJHF:97tsllrilld|}|}}uukd\v{|tt{}{u{u{{lks||lri||{||llkmttf]c{{{||{{t|zuztlekdc\tt{kk]lek||d\\|z|z{||||||kd\VTL{||tllsre|||UMR~}{tt||kk]}{{{u{{{|{tt|z|{||{||{{{||}ttsuztUTSUTSSKJSKJ|}utultslelksddcd\\lek||uztddctsl}{u{\[b}{{f]c]cdJHFultllktsl||lddD;9lldbVUuztekd|z{ttek]|z|z|z|z|z||yleekd}||||[[TbVU{||||{{t|dc\\[[mttlld[[TSKJVTL}tts|\[b{{tj]\JHF*)({tt|z|u}}|u{zmdc\leklld|{{tslellk||uzt{||}zl||||llk{u{|z~{{v{mttlekullk{{ldd|{{ekd{tt|z|ttsldd{u{|z|u|ztllztldc\b[U[[TddcVZTtlldc\ekdldduztlri||{ttlek}u{{ekd{||}zll{{ultmtt{{{{{{mttek]lri||z|z{{tlldultttsUUYdc\v|Ē}|v{s_qred}VTL]cdtzltzlmtt{||f]c[[T|lksedk\[[}tt{|u{{}b[U{{d\\tt{|mtt{{{{}|||redslej]\ultbVUr]ZcbVkd\slelddkd\{tttll\UZVZ[dc\edkuzt[[T[TT\UZlld[[Tzllkd\VTLj]\>EC:97ult|z{{tzllztlVTL|}}|}|red{tt{tttllttsuult||ultdc\{u{}vedk{{{|||LKRtslmttu{{ttsd\\ttsuztldduztj]\|tt{llklddkk]tt{|uldd|{zm|zlrid\\||ekdlek|z|z{u{{zm[TT|zttsUTS|u{{t||{{{ttfkklks{{|]cdtt{fkktt{||mttultttsf]c|z|z{u{{u{ultkd\SKJkd\tll}{{t{{t}uttslSKJJHFb[U|tslvldd|]bZdc\mtt|ttsVZTult|{{}{u{}ċ||bVU~ult|z}dc\ldd|ztslUTSSKJlld[TTslej]\\[[MRK[[T{{tlksllk{||{||mttlrimttddc[TTj]\}kk]lddtslu{{{u{\[bVZ[}|JHF*)(tll|z|uyleutkd\sle||j]\{{tvddc}kk]ztl||}tts}|{tttt{|ztts{tttsl{{t{u{tsllriuVTL\[b[[Tedk|u|zlektt{{{lddtts||leklddlldtll}tll||tsl\[[{||ult{{tMSS|z|zu{{|lddu{{|{tt|sleSKJfkkVTL{ttztltzl|u}{{t{{{zmtllv{ult{{|znvultmttult|zttstt{|{{tkd\dc\{{kd\ult}{tt}kd\iq]|zUTS|{ttllk[TTedklksu{{]bZVZ[lri]cdlek|lekllkllkkk]{tt{{tllk||u|ulksllkb[Udc\VTLjcVcbV]bZlddVTL}dc\\[[uzt{{tlksttslddmtt|z]cdlld{u{[[TVTL{{tlrillk{{tuddc[[TedkmttUMR>EC74,|||ztsl|utllkd\{zmldd|z]bZ|u}}tt{{zm|ztl{u{lks|z}|}u{{||{ttf]c[[Tsre{|||ztslldd]cdtt{{{lks|lksfkk||tllSKJlddSKJ[[Tlek}ultekdlld\[[||uMSS\[b\[[lldd\\edkf]ckd\|zult|||zultult}|edkf]c{{lks|{{mttmtt|{u{|tsl{{{{Ǧ}sreutsre}{{t{u{{tt|zwv{{tukd\|ulldtsl{{ttt{leklksult}u{{ulttts{tt~ultllk|||llku{{tts|kd\||ult|zllkkd\usre}VZTekdlksJHFUMRlri|]cdbVZ|zlldUTS|ulld||dc\sleVTLJHFJHFJHFztlJHF3+*{u{u]bZtsl|u{ttut{{tjcVb[Ukd\ttssle||{u{{u{rfkutfkk}llkult{||}|zf]c{u{zll\[[tt{lekdc\\[bf]cult{{tllkllkldd}uf]cv{|uultVTLuztttsslef]c||ddc\[[|z}u{{ldd|||tllrfkttslek{||{||tzl{{t|{u{|}lriedkllk}{{|||z|{{||bVUredtllƨ|udc\}|uv~]bZuztkd\lek~\UZ|bVZultf]cf]c}}}fkk{{{{mttUTStzl}tllultult{{tultdc\u{{uztekd[[Tlridc\|zlrisleddctzldc\VZ[lriUTS\[[ddcVZT|fkk}bVUtt{|tsllld{zmlriulldf]c{ttUTS|zJHF*)(lksuztuztzlluu{tt{ttuzt}{u{|bVU|u}tll}{||uzt{u{lekvtts{||}v{{u{{||{{t{u{SKJlld{{t|{u{ult{u{lld{||{||{tt}j]\}s_qzll}tsl|ud\\zllcbVtslmtttsl\[[tll\UZ{zmuztu{{u{{|{{t}ttslek}uzt{{tult}{tt{{~ttstt{{{uzttt{ldd|zu{{|z|tsltt{tt{ddcddcSKJ{tttllv{}||ztlmw{||uztfkkMRKlrilrillkddc}{||edk{{f]cleku{{u{{mtt{{tsl|mtt|z{||tsl|dc\{u{edk|JHFVTLVTLiq]VTLu{{]bZlekllkuzt\UZttsJHF]bZvJHF]cd]bZSKJut}ub[UlldcbVzll|}|{{t|zmttmttJHF*)(ldd{zmvu{zm}|{{tut|vutv{{||tts|u{tttts{zm}{u{tlltt{ztl|{||}v{||llktlllldlddlri}{{f]cult||}mttf]c||ultrfkulttll~}{tt{||{ttddctzluztttsuzt||edktts{||{{{{tmtt||{tt}|tts}d\\lekttstt{|}}tts{ttekd}|b[Uzll{tt}lksult{u{~}tllv{v{tll{{|z|zlldf]c}{{]cduzt}{{}v{[[Tuzt{||{{tVTLcbVllk|tzl[[TuztUTSuzt\UZVZ[ekdtll\[[uztUMRlri[[Ttts}|zkk]ekd{zm||ztzl[[Tedkv{:973+*|zttslld{zm}||ztlldd|utsl||{ttą{{t{u{||lrif]c{{\UZ\[bf]c{{}||[TT}\UZ{u{sle~ut|z|lriuztSKJ{||ultlksMSS|{{}|zlks{||||}|uzt}{tttts||ult}vuztttslddlddtsllks}ultlksultlddldd~||}ulttll}|zlridc\|zekdlri|tslf]c||{{t{{uzt|z|lldllduztkk]]bZ{ttllk[[T|mttddcVTL{{}f]cUTSlkslkslri{||lksttsultultlks}|{{tdc\]bZ|z[[T[[TLKR*)({{tll{zm|z{{t}z}|{tttt{uzt}{||}}|ddc{u{{{{||ttsleku{{ttslek\UZlddVZ[}lkstt{{||tllttsrfk}|v|lddrg]v{utlddlldekdtzlekdtlllld~{{}\[[f]c|z{||llkllk{tt|lldtts{u{{{{{ddcttsultult{{|z{{}d\\{ttv{}tt{tllf]cut{{\UZrfkult|||uztllk}sle{u{d\\]bZtsllrillkmtt{ttmttd\\|||v{ult|tsltzl{|||lriuztlksztl||z{{t{{t[TTlldekd}d\\{u{d\\[TTJHFVZTuzt{||ekdf]c{{lek||lrizllztltzl|z{{t]bZ]cdu{{:97*)(kk][TTu|uzt}}}sle}|ult}|{||edk|z}{{d\\]cd|z}}~ylemttkd\ddcf]c{u{sre}ttskd\zlldc\llktslttsd\\|ultu{{ttslrilksddclksddc||lks}}||z{{{ttrfk{zmtsl{{tv{{}tts|{{t|tts|{{tv|}}}}\[b}ddc{{ttllf]culritsl}|{zm||}}]cdu{{u{{[TT{{mttv{|ztl{{tll{u{{{|z|z|zlrikk]|z}tzltllllk{tt|\[[kk]||tllVZT|u{{tt{|z]bZ}[TTtt{lri{||ultlld|zllkekd[TT{||mtttzltll{||F=C7-2utztl||{zmsrekd\{{tsleultzlut{u{}}mtt}{u{uzt|lksmtt{ttu{{{{tuztdc\tt{ult{||||tll[TT{{tddcut{||\[[{||ekdlld|{{t{||tts\[blks|lrilks}llklddllkllkf]c\[[tts|ulldu{{edk}}ut}|u{||}|ttssre}}}u}{{f]c{u{zlllddztl{ttttslksedkFD;kd\zl[TT}UMR\UZ|lksedkUTSu{{u{{|zyl{{t}{{tllkd\\||{{|ult{||]bZ{{tlddVTL{||||{{t|mttf]cuztultlksllktt{{u{edkrfktll}lri{{{tt|u}ztl[[Tztl~|{{tlldlldJHF*)(tsld\\|zztlwl[[T}v{u{{}{tt}~zll}~ttstts{u{|z{||||tlllritt{\[b|}ekdldd||llk{{t|z|ztsl}{{ult{{tcbV{tt}||cbV|u{||VTL\UZ|{{||||uyle|{tt|tllllktts|ztts||~|f]c{{~|lld{u{{{lri{{{{ztl}tlltsl}f]c{u{tts{||[[Td\\zllj]\vSKJv{sre\[[}|{{mttf]c}tts}tzlVZT}\[[ultdc\lri|{{tu{{ult}ddc}|VZTVTLuztmttJHF|z|zlld}lld}tts|ultf]cddc[TTtslf]c{{trfk>EC{{tVTLlldllk{ttfkktsl|z]bZ:97:97}||tll|u{{t|ztl{{t|u}u}|ultdc\slerfk|v{{{t|{||vtt{{{t]cdtt{uzt{ttddclri]bZrfk|{{t|u{{ultlriredu{{|r]g{{t}ldd||lddredredmttUMRu{{{tt{||srett{}{{||rfk{||{||ttslri{||}{tt~f]cv|\[[vtt{llk|u|z|||lldtt{ztf}{||dc\f]c}}|}kd\lekVZTlrisleredzlltllztlsreVTL{{tv{{lks|zuztsle\[b]cd}~uztmttttsmttddc{|||z{||sleJHF|\[[[TTdc\}lri|z\[[]cdrg]ekdtsl||ddcuzttt{|lld|vdc\u{{SKJdc\tslVTLlld[TTsre||lriaWMSKJ|zD;9*)(}tslu}{{t|lekaWMut|}}|[[T[[T]bZmttd\\{zmtsl{{t||}lriztl}{ttldd}{u{}ult||z|zekdu{{f]cztltts}ztfddc{{tsre||{tt{||lksulttt{llk{{sle{{|{{tult}vllktllcbV|z|ztltt{{||mwsresleult{tt}uzllutylelritlltlltzlkd\b[Uddc}lekedkut|||u{{|zllk{{|tslu{{}lld}UTS|z[[Tultuzttt{mtt{{t{{tlld]bZbVUultultUMR}{||b[Uztlf]c{{ultult|{||{{{{kd\tt{fkkf]cd\\utzll{{tlrilridc\\[[ekduzt:97*)(tzlsre}{tttts|{tttts||z{tt||ddcldd|]bZ\[b||tt{v}b[U|z|{||u{{ldd{u{}kd\zllkd\lekv{kd\edk}{{|tts[[T{{mttdc\]cdSKJleklkskk]{||tsllldllkslelld[[T{tt}|ddc|zldd}v{ultuztttslddmw{ttultv{{|||tlltsl{{t{||\UZ{{|{ttSKJttsjcVldd]bZ|}|lekf]cdc\tts{{}lri{{}yledkbVZj]\[[T|uekdd\\{{{ttddcttsf]c[[Tek]sleultlksFD;zllztl||tt{UMRfkkultu{{|uJHFred}}{{{||\UZztl{||||z]bZkk]dc\\[[UTS]bZ:97*)({{t{ttlddred}{zm}ztfztl|}{||{tt||{||ddc{{||lektlld\\lld}sredc\u{{{||sleSKJ|tlltllzllr]gmtt{||tsl}|z{{tuztd\\||ddc|ztllrittsztl|z|||{u{ut{{lld{{t}}|lekult}tt{tts{{UTSlksttslritts{u{||}|uek]|u{||tsl{{t||{||tts|z{{t\UZddcztldc\VTLVTLek]tll{ttyfltt{\[[}[TTtt{leku{{VTL]cduztu{{lksd\\|zf]clri{u{j]\edkttsllk]bZllk{{\[[SKJek]tll|vVZT[TT{||dc\ldd[[Tvlksf]c}ttsf]cJHF]cd{{lektt{fkk}v{|zsle\[b~lrisre]bZ[[TFD;||:97:97rfkkd\{tt{{t|||zult}{{lektts{{tllk{u{{{{ttb[UbVZtsl|ultztfv{{u{llkztlUTS{{sre|mtt||mtt}ek]}{{\[[lrisle{u{}rfk}lri|||}tslultmtt||llk|u}{u{}ttsllk}{||dc\{||ult|z{{ttslult||uztÓ|{||{||lldv}}ultbVUf]cldd}edk[[Tlriultultlriek]{{tdkVmtt}ztlulttt{llkUMRLKR}{tttts{{\[[ttstts}|kk]llk|||uztlek}{{f]cJHF{||VTLlri}|mttllk\[b{u{ultllkttssre{{trg]|zuztMRK\[[dc\:97*)(dc\ztl}||{u{u}|{||}uuzt{{t{{{u{SKJ[TT|zkd\u{{UTS||j]\{zmldd}rfk{{tll{tt{tt{||JHFtslv{{{tu{{uzttts|zlldd\\v{|z}|ullkf]cultult|u{tt|z{||v|ylult{u{|{u{{||ztlult[TT{tt{{[TTtlltsl{u{tlltslred}{||tts{tt|uzt{u{||||z{tt{{[TT]bZb[Ulriuztdc\{tt{{tredult|z{||{{t{zm{{t{{tVTL\UZttsd\\}ddc||\UZek]SKJ{{ttt{UMR{{td\\VZTUMRlri{ttddc||}d\\tsltts[TT|}|u{{zllri}ddcUTS[TTlektslFD;,55}yle}ut||}{{|}~|sre|z|ulri|tllu{{|z}ult|v{||dc\fkkleklks~|{||j]\tll~{u{ututtts{u{}{||uztuztllklld\UZVTL{{|z|lrikk]{{t}tllrr]{{ttt{lddf]cv{lri|~{{|]bZ}~fkk}|llkb[U{u{||d\\||tzldc\cbV{{dc\j]\ddc}|zu{{tsl}{||leklek}zll|zvsle}v{VZ[ultultbVZ}|tllSKJVZ[uztUUYUTS|ddctslllk{{}{ttleku{{lri{{{{tztltll[TT{{{ttut}ddcUUYllklritt{ztlVTL|{{tlddtslmttlriztltslUTSJHF:97*)(}{||ut}tll{{tztlultuzt{{t|{|||u|}|zlks{tt|tsl{tt||v{ddcutJHF}tts}bVU{u{{{t{u{{{slerfk{{|{{tult\[[]cd[[TmttlriVTLlri|ztl||lld|{ttd\\{{}{{tll~||}}lri{tt{||llkzll|slellk{u{sletll|u||}lkstzl||ulld|v~{tt{u{\[[}{||uzt[[Trfkd\\{u{tsl|z|uult{u{UUY\[[ldd{{t{u{utult{{t}ultj]\lektt{ztllriddc{ttb[ULKRVZ[lksf]cttslddult||{u{ultut{{tbVU{||VZT\[[{{ttllVZ[mtt{ttmtt{{tf]cSKJ{u{|\UZztldc\SKJv{tsl{{tuztuzt|\[[VZTUTS:97*)(||kd\{{tztl||srettstsltt{}|z{u{UTSztl|z{||tts{||ekdbVZekdu|uVTL\UZ{||f]cult{u{}|lekv{{u{leklksf]clldUMR{{cbVddcSKJuztddc|usle{u{}kd\ult}}{{t{{{ttdc\zllztlut||zv{{tttsl|kd\}j]\~{{{tttts[TTmttu{{kk]leku{ttuztlekedklrimttd\\\[[||{{ultwl{u{UTSedkd\\|UUYtllf]ctts}|z||UTS\[[llkUMRrededk{{|lek|sre||utddclrimtttt{{u{|lri\[b\[b[[Tlri{||lldf]cmtttlllekdc\uuttsmttv{[[Tekd:97*)(ztlutsl}||{tt||{{}tsl}{tt|zUTS]cdlritll|lkslldtslmtt||uultwltslrfk}j]\\[[uztleksresre{||{u{||{||d\\}{tttt{|z|ulks}|ulld}|z|tllu{{|||u{{|sle}{u{}lddv{|umwtll{{t}}ttsfkklri{{t{|||ztts{u{b[U{||i\Vvllk}tt{lriSKJb[U]bZ{u{llk{ttdc\uztfkkddc{u{||}tzl{zmtsl{ttztllldllktt{||lri{u{slef]c|{{tMRKsretzlsretslUUYUTS~ttsldd{||{u{\[b[TTf]ctslcbVtlltt{b[UUUY{{kd\ultJHFleklld{ttfkk}UTSJHFVTL|z}JHF*)(}ut|z||}{tt}{||v{||uzt|ztts|lri|uedk]cd]cdf]ctsl{u{|z{{tt{ult|bVUlrif]cJHFbVZlek|ultvslezlltt{}fkkj]\}{ttult{zm{||||}|~n|ztll{u{{{t|zddctllztl{{|z|}}}}{||||||||~ultzll{||llkkd\lek}sle{tt|ullkllkzll~[[Ttlltt{[TT\[[ddcSKJutredu{{tt{|z|zlridc\tt{lrif]c{u{{||{u{lkslektllylezlltslmttsleultJHF{{ek]lldzlllldekdztl|z]cd|ekdUTSultJHFVTLkd\v{sle|tt{tll{{ttts}lek{{tlks]bZF=C*)(lld|z|tslvtll~rfk{{tts{||ttstll||sremttu{{fkk|uzt{ttuztmtt}{||||z{||uzt||tts}tt{f]cJHFfkk{||ddc{tt}ultult|zddcsle}lrillk|sle||tll|{{||lrilks|u{||||{u{tll|ztt{v[[T|u|ztl|uwlzllsleuztut{u{yfdllklld{||{u{cbV}||ttszllb[U}ttsrg]ultUMRrfk[TT{||ttslldllkJHFedk{zm]bZred||cbVlkslks}|ultrfkulttts|ult[TTztlVTL{{|ult[[T{zmfkklrilekJHFdc\tsl~lddlldlri|{{tztlSKJ||mttiWUd\\lritzl}ldd{||tzlfkkLKR*)(u{{|||v{|z{|||z}{||{||lkslddlrilri{{||u||ztl{|||uJHF|rfk{tt{{kd\leklksf]cmttbVUult[TTtts]bZdc\tslv{ztlttsekd||uddc\UZsle{ttu{{tts|z{tt|z{u{tts||\UZztlwl|mw||urfk}|f]cultsleu{{}{{uzt\[[{||ut}}zllztfVTLlekddc}lddultkd\mttekd]bZ||SKJuzt\UZdc\kk]{||zllv{|tts{{t{{tUTSdc\tt{JHF]cdddcjcVlriyflu{{{{[[Tmtt|zlri|zlks{{tmttVTLredcbVlksdc\ttsuzt||tsl{||ddcfkk]bZJHF*)(||z|u}|~}sre}|z|tsl||tt{|u{{mttlekulttsltts{||lldslelldultf]c}fkktt{f]c{{tlritll|lddultultttslld}{u{{zmtllultekd|{zm|uultult|ttsddc{{tedkred{{}tts}|llk{{}{||ult|u|usle}sleyfl[TT{||ddc{||lri{tttsllksi\V|u{u{{tttll{u{{{rg]tll}v{ttsredtslztltslVZT\[[ekdu{{ek]ultbVZf]clek|ldduzt}rfklksu{{ult|z|{||lld[TTf]clri|{||]bZddcllduzt|llduzt}bVUtlltlltlluv|zfkktzltslllkllklek\[b|zVTLsle\[b:97]bZrr]ut}ztl|\[[{tt|kd\lld{{tultu{{tt{ultu{{lksmttedk{{||{||tll|zf]c||kd\tlllldlld}llk||{{|zultedkekd{u{||JHFtllUTSmttultuzt\UZ}|zd\\ult]bZd\\tts{zmtts|||[TT||lld|||z|z{{|z||u{{dc\{u{llk}}|||v{||||||lks}{tt|uultultleklek}||ututfkkddc}wlj]\{yfj]\f]c|uekdllkv{ultd\\i\V[TTv{v{ttsutek]ldd||\[[ult{{ttllfkk|f]cuztldd{u{uzt}u{{|UTSult{{t]cdVZ[}uztJHFMRK{{t|zSKJ\UZlld}{{llduztllktll|JHFJHFVTLllk\[[&&ek]{||}|||{{ldd||z}{||}|lriultlksmttlriUMR{{sle{{lriult}bVZtslfkk}{u{ddc{tt]cdUTS|mw{||d\\|dc\llk{||lri||{ttu{{ultldd}{ttUTSVTLrfk{u{slelritllztllld{||}ddc{tt|ttsv|b[Uuzt|{||sle{{tttsulttsltllultred|ulddVTLcbV}||ldd||}v}||ttsttsddctsllekSKJd\\{{t\[[dc\}ult{||llk||v{{u{mttlldf]cbVZf]c}ddcttslek}\UZv|uultredUUY{zmmtt|z{{tult||||~lrilritsltsl|z|zf]cu{{{tttllllklddekd|ztzl|ztl}\UZlek\[[VTLslemttMRK%&tsllld{tt||ultuztuzt|z|UTS|{{|[[T\[[]cdlekd\\{ttleklrif]cldd{{}sle}mttSKJllklldsle{ttddc{ttj]\llklritlluzt|lld|}{ttbVU]cdVZTlldultslef]cdc\ztl||{||||mtttslmtt{{tlltt{|tll{{sleztl{u{|||ukk]v{dc\v|f]c}|v}f]c}|||ukd\||kd\}\[[ztlsre{tt{{t{||sre[[Tlddkk]{||bVZ{{t{{tzllf]clek{tttsltt{ztllekult}{{tf]c|uddc{{j]\{u{f]c\[b|zlek|mttlek]cdtts|z}[[T{ttlddlldlld}ekd\[[dc\lriu{{{u{}llkmttf]clddddcMRK*)(VZTmttztl|u}|}{{t|zlekllktsl|z}[TTd\\{{{u{}f]cttstsl{tttslmttJHFlld[[T{{llkj]\VTL||ldd|z{ttllkult|z{||MRKutll|v|j]\}lldsleulttts}|}|z}}tt{|z}{tt}utrfkb[Utll[[TlksbVZ}|{ttrg]}}ulttt{tts}}lksrfk|j]\{{tllkllk}ut{u{lri}ddckk]|{u{ttstll|lekb[U{tttts{zmuzt{ttuztztlldd}{{}}|tsl[[T||}tllyl\UZ|}[TTVZTtlllri|tllztlrfkultd\\ult|zu{tt{{t{{tlld{||]bZtzl{{lekmttlldztldc\>ECtts{u{}|||z{{|zuzt}SKJ|]bZVTLkd\lld]cd\[blek{u{{tt{{ekdlldult{||{tt{{t{ttSKJlld|lriuzt|{tt||u{{u{{{{|ulttt{lri|zllttsttstt{kk]ut}{u{tlltts}tts}v{|umttldd[[Tlldsleztlultllk|lddztl{{tmtt{tt{u{zllut}{{t||}||tsl{||sle[[Tlldlri{{{{tt{{u{lksuzt{||sled\\SKJ[[Tuzt{|||}{u{|tsl|z{|||||lks]bZmttslemttedktslmttldd{{t{||ultttsj]\llklld{tt}lek{{ttstll[[Tmtt}lek{||{{tlldlld]cd-1+tsl|{||Ĥult|||z}}|lddu{{uztllktt{lek{u{|ztlu{||{||}}}kd\lld{||u{{zlllkstzlmtttts{||ldd{||mtt|z|}}ddc{zm|z{ttlriddc}}tt{{{{{{{tllttsfkktsl{||{tt{u{d\\SKJu{{rfkv{zll{{t||{{tu{||ttskd\tsl||lekut|u{{ztlsre{||]bZtsl{||tlluztuztsle{ttedkzll|ztsltllj]\zllslelld|{tt||tsldc\tsltt{lrikd\slered{u{lddddc|u\[bllkmttSKJtsllrib[Uedk{{ultedk}|ztll}zll\UZllktt{ttslksmtttt{[[Tultlri{{tlrisle\[bLKR%&}{||Ħ|{{{tt}{{{{t||utll|zVTLlddmttmttlksttsult|z\[[ztld\\tlllld{{tsl{{sle|lld||{ttUTSlek{zm{{LKRekd|ukk]|z{ttttsuuzt}||{{t{|||u|fkktts{||{|||z{||ttsu{{lddlddd\\tts~[[Ttsl||}}}|u{{t\[[j]\lriSKJ}||}||ztzl}{tt}ldd|{{ttll{||lddrg]{u{lrilri\[[|mtt{{t|z{{tVTLbVZztl{{ttsldc\]bZllk|ttsldd{u{|tt{u|u{||[[T{{\[btt{b[Umtt{{{ttrfk{u{UTSlritlltts}ult{||ddclri{||tsl|b[Uttsllk[TT\[[ek]FD;}~|{{t||{tt|lri{u{llklri\[[{{{||{u{dc\{tttslzll||{tt}}||sreut{||ddc}ttslrikk]llkllklld{{tUMRttstslultuzt}{ttultlekekdlriddcu{{}lldtt{uzttts{{t|}lddult~|z}SKJ{u{v{sre|ztl}||||mttllk}{ttv{}ldd\[[lldjcV}]bZkk]bVZ{tt}u{zmVTL\[[|\[[f]clddekd|sle{ttutf]cVTL|UTS]bZztluztlridc\}rfk\UZ|z|u{{{{tts}u{{tt{u{{|z}|lrilddf]cVZT{||UTSttsVTLtsl~dc\ultu{{ultllkUTS)+2|||zl{{t|||z{{ddc{||lks}uzt{{t}{u{{u{utlddf]ctllztluVTLult|d\\ultVTL}{{llkllk{tt{u{u{{ztlttskd\JHFlri|tll|||lld|tllsle|ztl\[[}{||tt{||zll{{t}llkdc\yleutlltts}{tt}uzt}{tt{u{ttsdc\{||{{tllkztlztflddlrillkddcek]|zdc\|zdc\lddUTSf]clekred[[T{{|u{{t}edk}|srett{{u{lrimttuztddcekduzt]bZedk|ziq]lks{||sletllutult{||uztu{{dc\tts{{dc\tts\[[|zddc{ttuzt}{u{tll\[bLKR|zu}v|||Ĝ||||fkk{{{||{{}ult{u{tsltt{}tslldddc\rg]llk{ttlldsleutult}llk{||d\\|u|{{llkdc\]bZttslek|uldd{u{}cbV{||{ttu{tt{||{{||z{u{ttsult{||fkk\[[u{{{u{{tt|{tt{zm{tt|u|ldd\UZsled\\kd\{tt{{tlldmtt]bZekdtts}bVZ}llklldkd\SKJddc{u{ztlllktzlb[U{u{{tt{{tu{{lri||r]g||ucbV|z}||zekd|z|zmttuzt||d\\UMR||lksf]c{{t]bZ|uuztmtt[[Tttslri|zdc\JHF}tll}[TT{ttultd\\MSSLKRv{|||tzledk\[b}lks||||llkztl|z{{t||lld|utsl{||}sleu{{|z\[[ttsu}ekdllktt{ddctzltsljcV||{|||zzll}||{ttu{{zll{{t||{tt|tt{tslttstlltt{tt{\[[ultllk}lksu{{t|}tts{u{||tts||}|{ttsle{tt[TTkd\tsl{u{{{tkd\{u{v{JHF}|ztllri{ttultbVUdc\{u{lek}ttsttsut||{{ut{||ztl|zsle|tzl|]bZ|]bZu{{\[buztJHF\[b{tt]bZyle\UZ{||tllredVZTek]fkklddlekedk|ttsu{{]bZ]bZ|zv{ult|||sle\[bMRKUTS|cbV~}|znsle|{||lldllklri|u{|||u{{ult{{}{{lkslldd\\ut}}ztlutv{lek|ured{u{{u{{tt}lddldddc\sle||z\[[{||ult{u{\UZllkf]cf]ctzlsreSKJ|tzl[TTutsle|u[[Tu{||tsltsltsluzttts}|u}uztldd{{tldd||ztl}f]cuztult|u|ztsl}ult}}|ult{||d\\}ult|{{t||uyle{|||usle{{t||tsllldFD;uztllktzllld\[[lld}dc\bVZSKJtzlztllriultztlkd\{{tkk]ztltsluztu{{mttv{u{{{||lksddcllkMSSlldult}{{tUMRf]clektll{{tlld{||u{{tll\[[dc\]cd]bZlriutult}~UMRf]cJHF?;C|}}u}|ztsluztUUY}lksultlksmtt|||{u{}{{t|||z}ldd~{u{cbV{{tuu{zmj]\||ttstts|ztllf]c}|lrilriulri{tt{||zllut||||||z{u{{{ulttll{u{u{{tsl{{t|tllf]c{{||{tt{{zll\[[||{||uu{{b[UslejV[|uztl}ttsv{}j]\|v{tt{tt[TT|u}|ylett{sre||tlllddiq]{u{|||kd\{{ttslf]ctll{u{b[Ulksztl|uzt{{tmtt{||\[b|lksUTS{||\[[|lkssle\[bllk\[bUMRttsuzt\[b{{lekdc\tt{u\[[{{t|[[T{{t|{{tultldd}tlllddbVZldd\UZJHFlks||u}{{t|z|uyleult]cd{{tlekultedklksu{{|dc\lek{||{{tlri{ttultlddUTS|||sleddc\[[lri|lek[[T{tttll|u|uztJHFlkscbV|zllk|z}}|kd\|ztll}tll}{{||{tt|ddculttll[TT{u{}}|zn{||{{tlddmw}||}ylebVZ}|ekd}{ttkd\zll{tt{u{ult[TT}[TTlri{u{{tt}mtttt{ultllkztlUTStll{tt{tt[[Tllk\[[ttsLKR[TTtzl\[[SKJmtt|mttddcu{{lekdc\ultlks{u{ult[[Ttzl{{t}fkkfkk|{||uztuzt{tt{{t}ultkd\tllJHF*)(|zzlī}|}lld}ult{u{llk|lri{tt||utddc||{u{f]c[TTlldcbV}UTSn[[Tlrikd\{{lri{{tlri{zm{tt|zll{{t}|z||{{t|}fkkuttslultu{{}}ddctt{||lddldd{{d\\ultv{{ttlriut|z}uztztlzll||tllttsuzt|ulddztltts||lek|uttsek]||}}}lek||ztlslewldc\uztztl{ttuzt|zllklddu{{|{{t]bZ{u{SKJUMRmttSKJ]cd]bZ|zmttlriMRK}f]clldJHFdc\UTSd\\mtt|tlllriekdlri|\[[tlltt{dc\lridc\{u{{{lddlektll}d\\lddJHF$|lektsl{{t\UZUTS|{ttlri|lri|zltllutv{||ttsslebVUldd|zdc\|j]\dc\redzlluztttsJHFlek{{sretsl{||{zm{||}sleult|uzt}tts||ulttzl{||tt{|lriv{{u{|||zmttultek]{u{ttszllv{lekutslcbV|zuztkd\}zll}tsl|z|uv{red{{r]glrilld{u{{u{}|[[Tkd\}|u|zj]\lddf]ckd\{u{}[TTdc\|ek][TTlld{{t{||{u{ult{|||mtt{{tUTSddc|z\[blrimttuztlriu{{leku{{lksmttlri{{{||{{t{{|zllddcttsuztllkuzt|zlekdc\ztl{u{ult}}{tt{||ttsultVZT*)(|utslwl}Ǥ|zĜ||tzl|z||z[TTVTL[TTlriu{{utv{tll||v{}}zll}lld{{tlldlekyfd~}kd\tsl{tt{{t{tt||v|uztllklddcbV{u{SKJlri|ztzldc\{u{{zm{tt{tt}tsltsl|z|zutsl|utts||}ultult|ttsuzt{{t}|utsl{{tlltts{{tult|zdc\tslv{||{{t|uut{{tuzttzl{zm}||u|uuzt||}|ztllztfb[Uekdttsj]\u|zllk{u{~{u{{||||[[T|]cdUTS|uf]cbVUb[U{{tj]\llk{||}{tt[[T[[Td\\llk|z{tt{{|lks{{MSSlriVTLbVUf]cUMR>B9|||]cdtts]cd|ek]}{{t|z{ttb[U{u{ult{ttr]Z{ttMRK*)(ultmw¿wl{||{ttllku|zFD;ultu{{u{{fkkUTS{ttzll}d\\{u{lld}|||}uzt{ttkk]UMRrfkutttsSKJztlrfktsl\UZwlllkttsb[Uldd{||{||kk]}ek]|ultlldllk{tt}slesle{tttsl{u{}}|ut|uztu{{{{{{t}lri||ttslriult{tt{{tkk]{{tultttsllddc\{{t{zm{{tj]\zllv{{u{tll|tzlb[U{{t}|tll}|}ult}lrilriVTL{zm|u|uultlddzllztlf]ctts|z{tt{||uztlldtsl{||fkkek]tts{zmddctllVTLultuztbVUlriuztekdf]cttstt{u{{UUYJHF]bZ}{{[[Ttsl{{mttv{{tldduztttslriuztuzt{zmllkf]ctllkd\lddv{rfkztlv{leklekJHF,55llklks}|z~v{uzt}|z{tt||ztl|v\[[lritlllld{{t{{t~tyguzttll|z}{||rg]kk]}|ult|tsllek}v{zll[[Tb[Uultrfk||u{u{}{{}|{u{}tt{jcVi\Vu|||{u{|sreztf{u{|u|z{zm|tsl|z|z|}|tll{{t}~{u{}fkku{{tllult{tt\[b{{t|sle|lektll|zu{u{|u}{||tsltslrg]|sle{{t|tslkk]ult|||lld}ut{||bVUrg]kd\lek||tsluzttts{u{zlmtt{zmztlj]\tts{{zlekdtll|yl]bZ|u{||fkk|\[bUTSD;9lksmtt|u{{lksmtt{{}{||ttsuttsltt{|ztlllekredf]cf]c}{tt}tlltllMRK*)(||vƤtts}ttsVTLttsuzt{tttts]bZ|uztllk{{tztl|uztd\\ldd|||uztl}utedkttslldldd}}}f]c{{tldduttts[TTSKJlriekdu}ttsv|}ukk]||ztlult|}}{|||{ttlrikk]{u{|tll{||}{||u{{{{tult|u}tslv{{{trg]{{t||ut{{td\\ttskk]~tts|vsre|u{{tdc\kk]|||d\\{u{slered{tt{tttll\[[{u{lld{||VTL{tt|ttslldztllks{||lrittsuztlddtll|zllk{||VZT\UZlrislef]cu{{{{tlldc\UTSlrilks|{|||{|||zddctsl}ekd{tt[TT|{tt{u{}{tt}dc\JHF*)(}}Ǧ|||tzl}}uuztuzt}tsltts}ddc|z}|zlridc\||ttsuzt||ldd{u{d\\zll|{{tll}ttsyletll|mttVTLtt{|kd\uVTL|uwltt{|ullkdc\tslult||jcVmw{zm{u{{||{u{{||{{ttsl|||{||}tts|z{zmtll{u{|{{t{{t||||{{t||u}yle||red||dc\uzt||slekd\mtttzl\[[ult||sle|||z{{tb[Utlllld|||ztllddtts}|zmtt{tt{{mtt|tt{}redv{lksekdleklksztllekuztdc\[[Tekdlek}lld{||[TTtlllddlek{ttut}}|]bZJHFF=C~|~|ēllk{tt}}lrittstsldc\tts|\[[[[Tkd\VTL[[Tr]gek]{ttlldllkut|ttszlldc\{||rfktsl|||tllllktzl||wl{||redsleSKJ{{t|zllsletsl{zmlekf]crg]vtts}{||sle|z}u{{{ttut}tt{}llkllk|lld{tt{ttultf]c|u}sre{|||u{ttllk{ttJHFtts{zmrg]{{t{{tjcVdc\sre]cd{{tutttsut[TTddcsref]clldultu{{kk]ztl}ultu{{|lri]bZlldfkkVZT]cdllk{tt|uVZ[mtt}llk{ttmtt]bZedkdc\{||fkk{u{lddzll{{tllultyfdredldd|||JHF*)(tsl~wl|vu{{}{||dc\uzt]bZ{|||tzllri}|u{tt{tt|}kd\r]gztltsl{||llkVTLtt{}uzt{||sre{{tsletsl|lddtt{{{kd\sre|ztll||{zm}f]cVTLztl|vsleu|}mtttslultd\\lksldd|ztts}tsl[TT|{zmdc\ztl{tt|u}{{tult{ttlri}zllulttll|uf]cult}sre|lddredSKJtslcbVtll||||sleVTLb[Uddc|tll{{tllkuzt|zSKJlri{||{ttlri{{kd\uzt}JHF|lri}f]c\UZ]bZult|}}lkslrimtt|zttsSKJlriuztedklks|||ttsttsrfkd\\{u{}}{||:97*)(}}}llk{{tuzttll||ztzllri{zm{tt{tt|utztltsl}{||{zm{||{{{u{|uzt{{tVTLf]c|z{||d\\{zmdkV[[Tddc}|u[[T{{{ttsle||f]c{u{}{tt|tsltt{ultzllddc{tt||{{tu{{ut|utll{zm|||wlv{yl}{ttsle}{{t{tt{ttlddekdut}{{tredkd\VTLsleldd{|||u{tt}|z{ttlldlriztl{{tVZ[tts]bZ{||}tll}{zm{tt{||ztlfkkrg]tt{mtttslddcMRKlkslri}tlltts{{{{}|{||ekduztttsedklrilks|lri[TT{{{u{||kd\{tttlltts{{t:97*)(||}}||}}}}}|u|z[[Tkk]|z|z}{zm||uztlu|z{||f]cttstll{{tkd\tzlf]c\UZ{{tut{tt|zekd}ttszlrg]u||}{||utf]c{||lddkd\tllsle|z||{||{tttts}|||{u{|z|z]cdtts{{|||ttsttsult{||ztlwlzll}{{t\UZ{{t{{tn{||wlldd{zm{u{mwzllbVUkd\lddslef]c[[Tredtlluzt{zm\[bj]\VTL|z{{tVTLlri{tt\UZek]lld{{tt{ddclddUMRlldztltt{ddcleklddf]cv{lksVZTf]ccbV{{lldddc{{ultvlksfkk|zuztlld\[[mtt{||ldd|ztt{}llklddztftts|lriVTL:97*)(}|}}~}u||dc\llk||{{tiq]|zuzttzl{{t|u}sle}ttstlltsluzttzld\\{ttlddrfkkd\{{tdc\{ttutu{{tllrg]UTStllsleultred|u{{t|[[Trg]j]\tllldd{{ttsl{ttzll|uddclld{{{||{||lek{{lldultmtt{ttdc\{tt}{ttuzt{u{}ztl}tslulttts|zultutrg]{{t|uVTLSKJkd\|||{{tztlttsd\\ztltllzllkd\f]clld[TT\UZultVTLsrelri]bZ{ttd\\:97{ttekdntt{ztljV[{u{VTL[[Tdc\|lek|{ttultldd{||lld}|UMRbVU}mttFD;llkuztf]clri{{ult{tt[[TVZ[nv\[b]cdtsllkstsluztf]clddd\\lkstsllek}bVUzll||tll|ddcb[U:97*)(ǜu{zmzll}|{||VZT|sleulttzlut|u{{|]bZ[TT{{ukd\sletsl{zm}{{ttts}{|||ddc{||SKJzllslesreUUY|u|UTS{ttVTLJHF|{u{{{taWMmtttsl{u{}|tzldc\uztut{||}{tt}ultut}||lek||{{llk\[[uzttlllldlks|u|z||}}||utll}u||z}VTLvek]tll{zmaWMlldVTLkk]rg]\[[{tttts{u{|u{{tult||[TTultbVUSKJ}dc\dc\{||ldd[TTlrildddc\|u||v{tzl{{t{{tutll{{t{tt}v{~}edkVZ[\UZVZTfkklldUUY{|||z]cdekd||mttlekVZTlksuzt|u{{lekf]clddultsleult||ztl{ttsreJHF74,}}||v{{{{{ttsl|||{tttslddcMRKuztsre\UZ|||}ztlulldVTL||{u{}lddf]c{{rfk~rr]}v{||}||tzl|z{||lks|{{|u||}z|{{t|tt{ut{tt{{|z|z||tt{mtt||u{{tztl||lek}lrirg]|z{ttddcwl|z{tt}dc\|u}wlcbVkd\ztld\\tzl{{tlldkd\tllllk{ttsred\\llklek}redkd\SKJekd\[[dc\\[[UTSsre\[b{{dc\rfkultult}llk}UMR\[[lldddc{||{u{|{{t{ttulttll}||z|tt{}MRK{{mtt{||tsl{||mtt|tts}{{UMRSKJred|lddd\\ttsu>B9:97}|}}}||u||usre|u{||}tlllrilritslultmtt|z|utsltslrfk{tt}|}kd\[[T|zkk]}redUMRbVUrfk||VTLldd{ttut|uut[[TVTLb[Uztlf]clksut}|zred|ulritsllekzll||z{tt}|||ekd}|tts||tsl~{u{sle{{yleut}|f]cttslriUTSd\\lldtsltzlllk{yfslewltsltll|lek|uuiWUslettsslelek||ultult|VTLztlkk]}{||]bZulddtt{tts{zmbVU}f]c|ttstsl{u{}lektll|zaWMlks{{{||}fkk|\[[VZ[ult\[bttsekdf]c{{{||srett{j]\|uj]\lddlddddclriJHF-1+slev|u}{zm|ztf}{tt[TT~|utll[[Tr]Zrfkult{||llk||UMR}}}tllbVZ{zm}tslkk]uzttslUTSmw\UZ{{SKJkd\ztfdc\{u{|uut||}lld{tt|z}|zll{{t||ekd\UZ{{rg]{zmjcVlldult|||lri||{zmu{{tsltt{llkmttUUYredu{{llk|zuzt{||}|dc\}||lksf]credult{{tsle{ttrr]tt{||||{zm{{twltllztl|j]\VTL|}vd\\ulttllultf]cuztlri{||[[Tztlf]cutek]ekduzt{{ztltllult|lritt{ztllek{{t|z{tt}{{{{\[[||lks|u{{{{VZTllkztlult{{t{{{{tts|tsl}lddbVUbVUtts{{tuzttslvMRK*)(wl{tt}}||||{{}|ljsleutyfl||{{}}}|}ultuztztl\[[vlldddc{ttut}ttsb[UlksttsbVUUMRj]\zllztfiWU}d\\}|utult|lddtslSKJlddred||i\V}|zv{}lldedktsl|uzllddclksztl|}{u{llkkd\~llktsltts}d\\{{tlldllk||||v{|u{{|srekd\{u{lek||uzt{{tddcttsfkkv{}UTS{{t||~uzt{||}kd\kd\rg]lritzluztzltts{tttll|{{||f]cddcut|lrif]c}ddcuztu{{tts[TTllk{tt{u{bVUlek{ttldd{{tJHF*)(zllwlü¿wl}|}}i\Vtslzllllk||tllekdlri}u{{tslelldlrilldaWM[[Tj]\}|zdc\ultutSKJ\[[VTLtllztlv{lekUMR{||\UZzllusledc\{{{u{ut{tt|ullkd\\|{tt}{tt|||ttsfkkv{tllleklks|z|||ult{{ult{||{ttlld}lddUTStsl}}{ttztff]cUTSd\\lri|tsllldVTL[[Tsre{u{lldtslddc{tt}slekd\llku}{tt{{t}tsl}|vkk]llkuztult}ultldd{ttttstts{zmtsl|||lkstzllkslekdc\utsleVTLlek|{||b[U{u{}|sle{||tll{{||vtll{{~tslldd{tt{{\[[mtt|lks|z{{\[[slered{u{|:97*)(}}}}ult{tt}{{tzll}slezllUTSVTLtsltts{||{u{{tt}uttsl{|||u|uUTSredrfkuztdc\VTL}{ttVTL}d\\uztyfd|udc\ut||}|f]c{tt|ttsUTSu{||kd\|sle}{tt}||||}}lektsldc\{zmtt{{{tt{|{{||bVZ{||{ttttsd\\[TT[[Tulttll~tll{u{||}VTL|ztl{||aWMbVUVTLSKJcbVlek[[TaWMMRKrg]{||}d\\v{}{tt{{tVTLub[U{tt\UZ{{tUTSkd\{||ult{{ttslb[Uult{{t|{{tbVU}lek\UZzll|tll]bZ{{t{u{tts|z}ttsf]c{{\[[\[b]cd]cd\[b{u{{{{{uzt|tslu{{{{utztlkd\ztllld[[TD;9:97wl|utult{tt}|ulld|ubVZuzt}{yf}lri}}ttsu||ztl|usrelddkk]kd\[[T[[T{tt|ub[Ured}ultv{|}|||f]cr]ZultcbVjcV{||ultred{{tlldrfklrillk|zrfk}}||||}tllu{{edk|zlld|utddcmtt||~jV[edkzlllriu{{tt{sleuzt|uult{u{rg]mtt|zu{tt[TTbVUb[U[TT3+*kd\kd\ek]cbVlld}ztl}{tt|uttslVTLtsl|u|z{ttv{\[[dc\b[Uddcb[Ub[Ulld\[[{u{lldultllddc\tsllekllk~sleuztlritslu{{ultlddv}}|}|{u{f]cllk}lddlekmttmttdc\tt{mttedktll|}lri\[[{{tuztutslezllkd\red{ttdc\uztlldUMR:97}ljlj}}sle}d\\|ztsltzl|uv||ztlttsv{{{uzt{{lld{ttdc\{{t|lldrfk{||||}||ulldlldbVU{ttv{yleek]{ttddc||]bZtsl{zmlddutdc\aWMddcttsredtll{{tzll{{tlddutb[U}uzt}{ttsle\[[||llktts{||lrifkk|rg]ult|ullk{||llk||ztllkd\llkuztf]c{{ttslsle|ztllultVTLj]\{ttrfk|ub[UvVTL|ulld{{tdc\|uzttslsledkVu|llk{ttv{tslrg]lldVTLlrivttsllkb[Ullkttsrfk{u{llk|z|{{d\\ldd|ulriuultf]cldd|tt{ddctt{{{edklri\[bu{{ultd\\lksek]lkslri\[[{tt}}|tlllddi\Vlriwlj]\||tzlVTLJHFwlv~}|¾Ʋtts}}ttslddtll{{utultlrileku{{t||ttslriulttts}ukk]SKJj]\ldd[TT}|ztt{||zllbVUVTLbVZ{tt{tt{{t]bZyle||d\\|{{t|u}sletsltlltll|ztllek{u{{tt{{tttsttsu{{ultttstllulttt{ddcllkulttlltt{|ulttsl[TTtlltsl||ultztlkd\|ullkkk]UMR}srezll|uyle}SKJllk{ttsreVTLuuzt{{tztl\[[{tt{tt}|j]\{tt|sletllzll}}LKRuztutljedkv{|uttslridc\|u{tt|utsltsl~lksttsf]cztl]cd[TTtzl{||mtt{{u{{UUY]cdkd\uzt|lriUTS{||d\\{tt{u{yleyleyleJHFkd\red{{t{{t}JHF*)(wlüü|||}|ult|rfkjcV{{tldd{|||zultj]\lldldd{{tcbV{ttwl{{tcbVSKJ|ukd\j]\lld{tttll}kd\tsluttyg|zdc\uttll}tll{{t}f]csleuzt}||rg]b[U{u{{u{lld{tt{tttts{|||}|ldd{u{u{{tlllek{{{tt|v{}|||ztl{{tsleVTL[[Tzll}}z|}|redtsldc\]bZldd{||ek]mtt|rfkzllult}kd\tslcbV}edktll{ttuzt{{d\\VTLbVUlrib[Uldddc\dc\}}|uztl{tt{{tf]ctsl{tt|zmttVTLdc\|{{{{tt{ekdddc{{t{|||d\\uztlldtlltll||tllztlllkr]Z}}}kk]{{tFD;74,~~}|||u{{ttsl}sretts}bVUddc}lek||||u{{ttsl}|z|u[[Tj]\\[[tts|u|mttultbVU}VTLcbV[TT}rfkekd\[[uztj]\MRKultrg]sle{{t{tt{||tll||tts|||zj]\yle|||z|llk|z{u{d\\|ult{|||z}}|[TT||ztl{zmrg]d\\ekdztlwltsl}||}ut}utdc\kk]}{{t|||ultlekkk]{ttsle}|yle||[[Tek]tzltllultultutb[Ulri\[[bVZwld\\sleultztl{u{}{zmuttll}|u|tsl{{tMRK{||{||lri{||lddekdd\\f]cddc{tt}{ttcbV|u{{t|u|uVTL-1+}}uzt{{t}}llkdc\uztfsrerg]lddttsulturfk}{{t{tt{||u{{tzllddultsle}}ttsVTLrfkf]cv{|lri{||{||lld|uztlkd\ztl|u[TTdc\|utsltllbVZ||}|tslsre|z|cbVkk]{||{tt{||tsl|utts{||{ttuzt\[[|lksztl|uekd{tt||f]c}dc\{||lldmttrfkldd{tt}|zll}|ztltll||{{t{tt{{t||ukd\kk]tslv|red}|utllztlddclri|z{||uzt}{ttzllztlddcllduzt{{ttll{tt}|zllultldd{u{lldr]g{{sleztl{{uzttsl|u{|||v|{u{{u{{u{rfklri|zulttts}VZ[|zlritts{|||z]bZtslsleztl}||vdc\llk}|ut{tt|z[[T*)(tllwl}ü}}}|{tt}ztf{zmuultb[UlldVTLrg]ultzlltsltllultslef]c}|zllk{{tztlbVU}tll\UZJHF[TTtllllk[TTldd{u{f]c{tt{||sleulti\VVTLVTLkd\ztlekdcbVcbVttstlllddtllut}ldd}}ttsult||{tt|f]c{{t{{}{{|znv{u{||ult{u{|}tts|rg]{tt|jcVSKJjcV{{tf]c{zmtsltzltll\UZzll||}ultv{|u}|||}{||zllf]cdc\tsl{{|u|[[T}{||}|ek]~|slef]cmttzlltllbVZSKJ{||||{{{{t{||\UZv{{ttlekutztl{tt}VTL}{{tu{{ultult{ttuzt|z}{ttb[U|utllyle{ttutv}sreD;9*)(}||v}~sre}}|||}|zltsl}tt{v{}VTLultulttt{|f]c{||kd\}srebVUbVUult{u{\[[sleultlld||b[UtslbVUSKJFD;]bZSKJsrekd\[[Tlddd\\ztltzlttskk]sleut|u{ttvztl|||z|zlksf]ctt{fkklksUMR}tsl{{lldleku||||lldsletslb[Uztfldd{tt{{t{{tlldultcbVut|u|uult}j]\{tttts|vrg]tll{ttd\\uzt{{tuztrg]bVZlddlddtts|u}MRK|tslrfkv{UMRbVZ}}|{{tll{tt}sretts}f]cut}|{{tdc\dc\}||||ddcf]cf]c{||{{ut}zlltllredj]\|utslj]\red||ztlJHF*)(~utüütsl||ztluztztlutkd\rfklddutJHFuzt{||{||uzttzl{{t{{lrizllrg]{||lddlrijcVttsv{ultf]cSKJtll{||}|{{t{tt[[TUTSVTLj]\llklddlksttsv}{||r]Zekdddc|||ztl{||||}j]\{ttllkuzt{{|u{{{||{{lksedk{u{tsl|z|zttslks{{tkd\lksttsedk{tt{u{{{tultllddc\redredut{tttts||ttstllkd\yfdzll|uultdc\d\\{tt{u{}ldd{{tttsv|lddllk{tt}|usre{||tsllddlek|uUMRultbVZtts[[T{u{||tsl|tllult||ultbVU{{td\\[TT|tzlfkk}sre{||lri|uldd{||{||||}|{u{wl{zmtlld\\utwlv|rg]rg]FD;74,}zj]\ü|zv}||{{tslellk{{t||{tttt{{tttts{zmztl||tll||}|||zlddtts[[T{{ttzlkd\{tt{u{[TTd\\[TT}{tt{{tddc[TTd\\ekdrg]kk]bVZllkldd[TTtzllritll[[Td\\b[U{{t{tt{{ttts}|}}|{u{||u{{{{tllktt{{{|}tts}|vtt{}|{u{tll{u{{u{}||llkdc\red}zf]c}{||ut{{tUTS|utllsreyletts}|yfd{{t||sleyfl}{{tut}{{||v{{u{}v{VTLv{{edktllf]c[[Tslelddllk{zmu{{ultztlrg]{zm{{t|tll{{t|]bZtt{|zlek|}ddclekd\\kd\llkddc{tt}|uztldd\UZf]c}|v>B93+*||ü}}||ztt{u~lld{ttkd\tts{ttlldj]\tllv{f]ctsl{tt{ttrg]ddctll|}|llkiWU]bZtlluzttsl{{t{||ultlekdc\}|JHF{|||ttsrfktllJHF{||v{srellkddckd\b[Utslslekk]d\\{|||lekyleztl}ddctts}u{{uzt|zuztddc\[[|z|}\[bf]clksldd||}}}|j]\lldi\V{{tzllkd\ldd}|i\V||llktlllld{||llk}|b[UbVUutbVZ{ttsrettszll}ult||{tt}lek{{t}[[Tddcttstlledktll{{|}srecbV{{tsreu{{kk]tll|vzll|u||||ult{tt|{||{||n{u{}ult|tsld\\rfk}|{zmtll{zm}|zllyleztlkd\kd\:97*)(}u|||ztf{u{yfdut{zmulddtslv{}}}llksle{{|uldd}tzl|uddclri|FD;d\\u{{]bZllkd\\rfklddlddsrezllSKJ}tsl|zsleVTLtsldc\|lddsleVTLzlllldrg]srelddultd\\{u{||{tt|uztl||mttllk|{{|}||ddclriuzt{ttlkslekUUY}||kk]ldddc\}tllsrekd\bVZultlldv{bVZbVZlddlri~kd\v}{{|}|f]clddultldd{||llkd\\kk]{u{v{|||||{||tsl{u{VTL{zmbVUddcttslriztltllUTSulttsl|vttsrg]||tslv||kd\[[T{{tll|lek||{tt|vutztfzllsle||kd\wl:97*)(lddut}}{{tuut|u||}ttswlv{{{t|u|u}|sle{||f]crfk{{t||}zll{||d\\rg]redlddztlllkf]c}rfk[[Ttll}tt{j]\VTLkk]lldslettslridc\||tll}dc\tyg|ztllddj]\mtt{zmut{{t||f]cv{tlllddd\\}}ekd|{{tt{|z{u{tlllek{||~{{{{tllkleksle|zsle|u{ttllklriredkk]VZTzllredbVZ[[T{{t{tt}ultddc{tt|utredrfk{u{{{{||}lriztl]bZ\[[utVTL|lldlriddctsl{zm[[Tf]ctsl{tt}v{lek{||bVZ}{u{ztl{{tkd\uztuzt|z|{{||ztt{ut{||{{t{zmlldlldd\\sletll|uzllldd}|yle|}>B9&&~{tt}u{{t|||utrr]redtsl{u{tsl}ztl}|{{t}{{t{||zllsle|tll}}ult{tttllsleultllksrettskd\\[[tllf]csreztld\\ttstll}{{tVTLUTS[[Tlldztlkd\b[U{||}kk]ekduzt||kd\lddlkszll||{ttkd\u{{{{ddcek]lks|mtt|edk}||{u{}ddc{||||~cbVkk]tllkd\f]clrib[U||j]\ztf{||{u{{zm||ldd{tt|ud\\}||rfk}|utsltts{||tslkk]}ut{ttredsrej]\ttsUTStts{u{{||{tt~ult}|uztttszll{|||u~{zmztl|zllsrelri}|zekdekdslellkldd|u|u|tzl|u{zm|{tt}|vredkk]i\VD;9*)({{t|v||}u|uutztl}}yleb[U[[Tzllf]czll~{ttulttsl{u{kd\{tt|zkd\||zll|ultlldzll|v}|sledkVv{dc\dc\{tt||}lridc\kk]mttSKJ{{trfkFD;sre{{ttll{{t|[TTb[Usle}b[U{{tsre||tll{||tll}~v{||tt{lldultuztmtt{{{{{{lrilks|z{u{uztult||}ttslddlks{u{{{tvu{{{u{|}yle{||tsl{{ztlkd\d\\f]cuzt}tzl{||bVUrg]}|v{tttslkd\}|||{u{{ttrg]kd\[[Tlldtsl]bZult{tt{{sleztlztfztlut}|||uztlsle}lek|zwl}tll}ek]{||{||tsl||{||{tt||JHF}i\Vutztl}|wlredFD;*)(v|}ut~vldd{ttubVU{||tsltll{{t{||ultuztttsu}|{tt{|||u}lri}sleldd}FD;{||ult|z}lri{ttttsllkekdu{{lldb[UlriutUTStygtllsreuzt}ztlsre[TTaWM|zztlrfklld||}tll}tll|||zlkslrilek]cd||lkstt{}fkkllk{ttultleksle{{{{t{{t|z}{u{ultrfktsltt{rg]lldutUTSzllyleslekk]{{t{||lddutlekf]c{u{{u{r]g||||{|||}tllredtzlsleVTL|z{{ttllttsllk{ttv{||]bZ{{vulttsl||}tsl{{t}}mttmttu{{{{tlddlldtzlllk{ttj]\lddsle|||uztlsletslrg]JHF*)(~{{t}}|uzll}{{t}|v|z}{||srelri}}}|u|z{{}{{tyfl}slellkr]ZbVZllkred{ttddc[[Tlld}lldlld||tzltll[[Tddc{||rg]dc\b[Usresleslensre}{{ttll|lritzlzlltll}tts{{ult]cd|z{{||u{{|mttlriultuzt{{ultf]clks\[bmttultlddztldc\kk]{ttut}llkddc|sre{ttutzllztl{{{u{kd\d\\ut{u{utred{tt{||ztltllkk]\[[lri}ult}uztwl|zmtt}tt{mtt]bZ}tts}sretts{u{{||v{ztl[[T}zl}lldttscbVlldttssrerg]sle{{tutztl|ui\VzllutllJHF!¾ƣu}{{t}{tt{{tttsztl|u{|||lld}tsldc\dc\kk]tsl|ut|||}zllllk{u{{ttb[U}{{ttsl{{lribVZlritlllriVZTUTStlluztf]c}mtttslkd\||vuztyle{zm{u{JHF||||{zm|}{{||lkslksekd}|fkkdc\ulttt{|lddd\\tsl{u{tts|uVTLn}ultf]cult|zlks{{||ztl|u{{tlekttsldd{||lddrfkbVZdc\{{tu{{tll{{t{tt|ut}||z}|u{zmkd\u{{ztlrg]||llku}}|||}{ttlri{tt}|}{||sre{{t|z{{t||sletsl}{{t{{tztl[[Tu[TTsleultb[Uztl}|{tt}v{ult>B9*)(||v{v{zlltts~dc\lekylev{{{{{ldd{||{{td\\[[Tuztllkn}ulddsle|zztlu|u||tts|ztts{tt|u{{t[[T\[[|||ldd}|tts|||}|sleslejcV||kd\tzltts|u|v}{tt{||{{{{}{{tslmttmttmttmttuzt\[b\[[{||lddlekultult|rfk{ttldddc\}tsllldttsldddc\[[Tlldlld{{t{{[[TbVUkd\ttslddedkzll\UZd\\tll{||uztlriultzll\UZ{{ttyg[TTMRK\[[llk\UZ{ttult}wlkk]||ttsztldc\{{tulld||tzl|z{zmkd\|lriiq]lldtllsrebVU{zmztlztl}|utllyle}D;9*)(}wl|wl||kd\{{t{||{tt{{tu{||{{trfkrg]}}{{t{u{wl|{tt{u{d\\|uztlu|ztl|SKJttssle}bVU[[Tultllkultlks|llk|u[[Td\\tts|u{{t|u|u|u{{tf]csle||{{tsleztllldv{ztltsltlledklld{{{{|ztt{|mtt{{mttu{{{||{{llduztd\\\UZlks[[Tf]clld{u{llk{{tlddcbVultlddult||}dc\{{t{tt[TTUMR{ttb[UmwVTLrfk{u{VTLSKJ{tt{{tv{vredldd[TTtsldc\|utsle}z}ekdllkllkldd{||{{uzt}sre}|vlekllk}|zll}||tts|{{t}|ztlb[U|{tt{||{{tlddtts|uutztl||ut||wl}:97*)(||zutll{||tts||f]cultttssleb[Uvu]bZ[TT|zddcb[U|z|u|tsl}kd\{zmv{||llklddsle}ultttsb[U}cbV}||tlli\VVTLSKJkd\tll{{t|uyletll|u}|utslsle{||b[U{tttsltsldc\{u{{ttlks{{{||uzt{{mtt|mtt|z||z|{||llk{ttlek{||{{d\\bVZbVZ{u{|z}|uzlulttlluztdc\redUTSztfkk]SKJ|lekkd\f]ctllVTLmttd\\tsl|||u\[[kd\{||{ttsle}ldd{{v{}lksmtttllsleultztlultUMRlddutllkuztttszllsre|}|u}}lddztfsre||]bZred||u{{twlztlztl||tslwlJHF*)(Ƶ}u|v|u}yle}||uuztmtt{{td\\||u}{zm|u||u}|{||f]csresre}ultllksle{||ultultuztlldd\\{u{VTL]bZ{{tsre{zm}JHFSKJdc\dc\|uztf[[Ttllkd\|u||}}lldkd\ztlj]\{tttsl{{t{ttttstllddclddlekmttu{{mtt|tt{{{{{ttslkstt{|}||ttsf]c}bVZylelri|zsre{||kk]{|||uldd|zkd\rg]|vsreztlrfk|}rfkztlkk]b[U|u}zlltlltllf]c{{trfkrg]rfkuzt|z}{u{leklektlllek||ttsmttut}|vzllnllk}|ultf]c}|lddtsl{u{}}tll{||}wl}{{t[[Tdc\tlltsl}|u|||u}{tt~ztlD;9*)(uut}lldwl{tt{u{zll{{ttts}MRKsre|z}|udc\||{{tlriuut}|utsl}|||zll||||ztld\\ddcsre\UZ{{t|}|u{{tdc\j]\f]cVTLslelddttsuzt}}b[Utll|vyleztlkd\kd\wlf]ctsl}}d\\||}{ttllktts{{n{{mttlkslksultlek|mtttt{ult]cdv{bVZ{tttt{tsllld{{tzl{{tutslf]cj]\llk{{t{{tut{{tu{{tlek{zm|urfklks||kd\}|SKJf]ccbV||sreldd}slesletsl|uzllttsultlriekd|{tt||{tt{||{ttrfk||}{u{}tll|ud\\|u[[Ttsl|usrekd\lld}lldrg]u|v{kd\||r]Zsle|uredredVTLcbVFD;*)(|v{zm{{t}}{{tu|u{u{||{{taWMllk|{{tredllk{||ut{tt}tzlSKJJHFVTL{tt{zmb[U|ult{ttutldd[TTult{ttd\\slej]\kd\|zudc\slelddkd\f]ctslb[UJHF|tts{u{dc\{tt|u}llkvtts|lddtts{{ttslcbV||{{t}ttslks||{{{{VZ[]bZfkklksleklkslrimtt|\[[\UZUUY{ttldd{u{{{tcbV[[Ttllultldd{||sretsltts{zmkk]lld}||{||ud\\tll|zv{kd\b[Utzlu{{tsl|ztsl||tll}{{tkd\|vVTLlldslelri{tt{u{lksmtttt{|z|}||{||tsl{ttult}{||uztkd\||}|}bVU{ttd\\ttstsluuzttsl|{||{{tuztf]cult{zmzlluzt}ztlrg]d\\j]\tllrg]rg]}|||{{tztlUTS*)(}|u{ttrfk{{tztltll{{t{||rg]{{t{||zll|z||tts{||{{t\[[llk|u}||ztygv{ttsj]\}||u{u{bVUztl}VTL]bZlddllk\[[UMRtll[[Ttsl{||dc\{zmlrij]\tll{zmtsltlldc\{{tztl}{ttkd\VTLlldbVUb[U{{t}|}rfk}|VTLsre{{|tt{|{{llknv{||mttd\\{{fkk|ttsf]cUTSlks\[[bVZ}v|u}~sre|llk{{tttsllkd\\ztllri[[T||z}sre}}dc\tllf]c{tt}|tts{{{u{sle{{t|z}{{t{{{{t[TTtllVZT[[T||{|||bVU{u{llk|zu{{||{||\UZ{{lrizllzllsletts{ttv|z{{tlddj]\ztl{zmslesle|}ztltsl{ttSKJlldek]v||sleutsleSKJ*)(}ƨ}{zm{zmtll}|||tll{u{lld[TTlrisle}|{{t|zek]{tt}|usle{{tlddzll{tt||{ttkd\{u{{{tttstts}lldSKJ]bZuztkd\tsl}{{ttllVTLd\\[TTD;9{{tlldv{sre{||kd\ztldkVkd\|b[U{{t}ztl|{{tlrislelksmttmtt{{VZ[{{fkkmtt{u{ulttsllksd\\d\\llk|ukk]sreuztttskd\tt{\[[lldredztl{{t}llksle|utll\UZ||ult{u{{tt{||dc\jcVtslult{{t|u{zm{{ttts{tt{u{j]\d\\edkekd|{{{||tts{{}u{{{{ttts}uzt|{ttv{|{||{{t}ttslldttsult{{t}lridc\b[UcbV|llkkk]|utsl{ttutztlrg]ddc||redD;9:97wl}||}}{tt||||{tt|uuztrg]llktts{zmultb[U\[[[TT{||kd\{||{ttsled\\||uv{tslj]\dc\sled\\||kd\lek{{ddcldd\[[dc\[[Td\\f]cslesle{ttb[U[TT]bZrfklddut|bVZj]\ztlztl}|kd\|z{zmztf|z}}rfktsl{|||zkd\tt{{{lri{ttlri\[[|mtt{{]cd\[bttsf]c{u{lks{{f]cddc\UZ{|||lld{{t|kk]kk]{{tlrildd{{ttllddcult]bZ~uzt{{tb[U}f]cf]c{ttj]\{ttsresle|ulddult{{ttts||u{|||u|zultUTS{ttttsttsf]c{{{u{ztl}ut{{{||}{||lrizll}uu{|||uuzttts||{{ttsluzt|||sre{{twl{{ttslztfkd\ztl}|sre||{{ttsl{||FD;*)(vvu||redredu{u{||}{ttztl}{||}lld{{tred[TTldd{ttslelekrg]sledc\tsl|||}tllv{[[Td\\|uztltll{||}uztf]c]bZlddb[Ulddd\\{u{{{tutulddvredVTLkk]lddbVZ|usleldd}|ldd{ttllk||u|u{{t}{||sleutztl||lri|{{{{tt{]cdult{{mtt{{|tt{edkf]clksllkekdmtt{{tlks{u{lek\[[d\\ek]lldllkkd\|tslsreldd\[[d\\sle}llktslsleddclddtt{utv{{ttultldd|uVTLkd\UTSu|}{tt{||uztldd]bZtsllks{{{u{lksult[[Tlektslllkuzt|ztzl}lek}|zlld{u{||b[USKJd\\mwFD;[TTllk|ttsudc\{tt{zmek]llkcbV[[T}{{t]bZtllsre{ttjcVyle}sleSKJ*)(}|}{ttlld{ttlld||}|z{||{{t|z{{ttts{||ult|u}|v{zmtygrfk{{t}|{tttsl||zll||ztl}{ttldd[TT}{{tddc{||tsltlltsl{u{ek]lektllrfkztl{ttlddkk]kd\ddcf]ckd\b[Uekdd\\zllaWMMRK||{||lri{ttj]\{zm}{yf|zkk]}{tt}uztddc||zlksmttuztllkmttf]c\[bultekdlksult||iq]b[U{u{}{u{\[[ldd{{t{{t[TT{{tlldtsl{zmlld}dc\sleddcd\\aWMlri|{{tVTLlldtllr]gtt{}lddd\\tslutddcztlddcb[U{||[[Tlld{{t]bZ|||u{{{||\UZ\UZSKJkd\ekdtll{tt|zf]c{||lksfkktslttsb[Uf]c{||v{{u{{ttllktsltllaWM|z{tt{||ztl{ttj]\tsl||dc\dc\lri{zm{{[[Tred|u||lldtslsre{zmtsltllcbV{ttkd\ztl{{t{ttmttlddD;9:97||uzt{ttv{|{u{|u{zm|z||{ttultlri|z||z}||{zmtsldc\red{{t||{|||slered{u{{ttredlldslelddlekj]\dc\SKJslelritslb[U{||ddcuzt{{t{{tldd{{t[TT{tt{zmSKJ|utsle{{ttll{ttztlv[TTslelrilld{ttj]\}|kd\tslllkztlbVZtts}{{tdc\lkslksddc{{{{llkmttu{{ddc\[[UUYUMR{{{{uztmttlddlekdc\ddclekllkult}lrilddlriu{ttd\\lek{{t{||ztlldd|zkk]VTL{u{j]\b[U\[bd\\[TT|ub[Ured{||[TTllkVTLb[Uredb[Uj]\]cd{||j]\tllttsekd{u{{||{ttVTLlri{u{||tll{||tllkd\{||]cd|zdc\lks||ddcbVUSKJztlVTL[TTlrittscbV{||sletygtts|zrg]||||{u{lddztllri}|z}dc\ldd[[T|zttskd\[[Td\\tslb[Utzl[[T[TTkd\{||}red|||tslj]\SKJ*)(ult}{tt|uztl||{zm|wl}{{tlks}{{t{|||zztlsredc\sre{tt}|ut}{{tzllekdttslddllktll{||kk]{{t|uultulttll\[b]bZbVU[TTtslf]c{||tsltlltll}lldkk]tlld\\kd\j]\|uFD;tll{ttsleVTLb[UlddVTLztl||ttsultkd\cbVdc\{zmusletts}tll[[T]cdslelks{{{{edkddc{||u{{mtt\UZ\[bJHFVZ[lkstt{ddclks}lks[[Td\\lekllkf]ctts}VTLtslttsbVZ[[T[TTzllkk]||mttzldc\lks||VTL\UZSKJd\\lekkd\zlllddlldddcSKJVTL[TTtsl}\[[dc\tslVTLVTLlrildd\UZlldd\\{u{llkllk{ttttstllbVZlkslridc\uztmtt}lektlluztlekj]\b[Uu{{d\\{tttts[TTVTLtslVTLkk]ddc|uddc}{{t}tll||ekd|[TTdc\lld|uultttsf]c{||kk]sredc\kd\lddztlddcb[Uutlld{tt||sleJHF*)(}|uu|{tttsl{{tt{{ttsletsl{{tzllztlllk||UTSkk]dc\ekd{ttlddtslulttsltslkd\|z|zkk]{||d\\{||lddlri|utts}ttsSKJddctllult[[TVTLSKJllkJHFSKJ\UZdc\ldd|tsllldtslb[UUTS[TT]bZVTLj]\b[UVTL{tttslVTLzllztlztfldd{u{lrilddJHFb[UVTLkd\redtsltts||{ttllk{{tsllldUTSttsekd{{]cdf]cllktts{{\[bfkkVZ[}u{{lksddc|{u{{tttlledkuztlekutuzttsltslVTLtt{\[[d\\[TTekdj]\{{tlddkk]tzl[TT\[[d\\b[Umttllkllkldddc\\UZlekbVZlldtllzll}tslj]\[[Tdc\lldttslldllkuztkd\edk\UZVTLb[UJHFf]cUTSu{{ddcb[Ukd\UTSlriuzt]bZttslddMRK{ttUMR[TT{ttllk[[TlddcbV\[[{ttlldj]\[[Ttslsre||kd\ddcb[Uddctll]bZkd\|lldtlltsl||{||ult}d\\dc\ztldc\kd\tsl{u{sle|vsleddc{{tlld[TTD;9ztl||{|||{{t|zllk|z|tts{||llkd\\kd\{u{}lrilldlldztlkk]lldtsltslu{{sleedk[[TVTLrfkf]credkd\kd\]cd|zsle}lldtts{||ekdf]ctlllld|zslelldtts{tt{||tllcbVzll[TTdc\d\\{u{]bZbVU{tt\[[VTL[[Tkd\\[bb[U[TTtllslekd\|z[TTutztl\[[b[Usletsl{||tts[TT[TTlld|zd\\tsl{{t{{t{||lldtllttsd\\[[Td\\{{lrif]cfkklkslks|z{||mtttt{VZ[LKRVZ[mttmtt]cd\[[\[bd\\d\\lddlekmttedk\[[r]guztekdekdd\\lridc\{{t[TTlldd\\FD;[TTd\\kd\tslUTSlld\[[[TTkk]f]cj]\f]cf]c[TTtllf]cbVZUTSllkkd\ttslksllkd\\SKJmttUTSUMRd\\tllSKJ[TT\[br]gf]cUMRUTSztlddcslelkszlltll\UZtllVTL{||llddc\lldtt{VZTtt{}ultd\\d\\tt{mttekdlkssleVTLkd\{{tdc\dc\{{tldd[TTztl\[[dc\d\\b[Uddcd\\f]cb[UcbVlldlld{{ttslcbV[TTztlVTLkd\dc\lldtllb[Urg][TTUTSredkd\[TT:97{||}|ttsllk|tt{mtt|}{{{u{ztltts{u{{u{llk{{}{tt{ttkd\kd\dc\{u{tsldc\slelld|{{{||{|||tllttstlldc\{ttkd\{||{u{|zlld|zVZTSKJkd\lek|ztts\[[JHFf]clrildd{||sledc\ttsttsllddc\\[[JHFd\\UTSdc\ztfkd\\UZsleVTLd\\tslaWM[[Tllk{ttkd\lldlritsl||uzttts{||{{tlld{u{kk]ztf}{{tlridc\lddultekd]bZdc\llkSKJtlllksmttlksVZ[f]cllkUTSlks\[b\[btt{\[bult\[bVTL\[bJHFUUY[TTdc\UMR\[bd\\UTS[[T[[TVTLMRK\[[|ztllttsekdd\\b[USKJUTSSKJ\[[dc\lldttsllkj]\d\\leklddUMR[TT{tt\UZleklldtsld\\VTLkd\[TTuzt[[Tddcu{{{ttd\\JHFmtt[TTldddc\\UZtts{u{u{{SKJ\UZ[TTVTLUTSekdlldedkddc[TTllkddcddclridc\JHFedkttsult\[[[[Tllktslf]ccbV[TTkk][[TlldSKJSKJtlltlld\\fkkd\\sretslllkVTL{||{{t[[TVTLUTSd\\ldd[[Tdc\tllrg]]bZttskd\ldddc\d\\[TTztlJHF*)(||{{ttzl{||tll|llk|zttstll|tt{ldd}b[U{||ddcllk[[Tultlksultu{{{ttd\\JHFdc\VTLek]lld{{t{{tlddldd||sre|||lri||ddc{||{{t|u{{ddcddcedk{u{{u{tsl[[TJHF[[T\[[ddc{u{lddultkd\f]c[TTddcd\\dc\cbVlddultuztkk]b[U[TT[[TVTL\UZtllVTLb[Udc\kd\redlldVTLb[Ulldtzl{||tllekddc\lldtll{{tlddztltsl]bZlrilldlddttslld{||\[[UUY]cdedktt{mtt\[b]cd\[bUUY\[bmttlkslksUUYfkkUTS]bZUMRJHFUMR:97JHF:97UTSUTSJHFllkllkVTLSKJllk]cdcbVLKRb[Ub[U[[T\[[SKJVTL\[[dc\lriddcVTLdc\llkf]cllklddlldlddUMRUTStts\[bkd\VTLllkJHFtllbVZuztttslddddcbVU[TT[TTUTSJHFJHFddcUUYUMR\[bJHFJHF[TTdc\d\\ekd[TTUTSJHFVTL\[[]cdD;9f]clld]bZd\\VTLSKJVTLJHFllktt{|uekdUTS]bZdc\JHFkd\[TT[TTtll[[TVTL]cdb[U[[TSKJVTLdc\lldFD;[TTUTSSKJJHF[TT[TTdc\dc\b[Ulddd\\VTL\[[bVUd\\jcVkd\}JHF-1+{tt|u}{tttts{||{ttttsdc\uztllkttsu{{tts|zJHFedkleksle\[[sleek]llk\UZf]c{{tf]cedkSKJtts{ttlddlrillddc\\[[]bZ{{ttslUTSldd{u{llklksfkkllkultkd\[[TUTS]bZ[[Td\\tllUTSddctts\[[\[[dc\VZTJHFJHFJHFFD;UTSVZTVZTtllredd\\VTLVTLdc\kd\UTSd\\kk]dc\ddcUTS[TTdc\bVUcbVJHF[[T]bZtllb[UJHFd\\tllb[Umtt[TTUTS\[[VTLb[U[TTdc\VTLb[U[[Tddc[TTUTS\[[cbVVTLddcf]cf]cUTSlksllkVZ[]cdultmtt\[[edk\UZJHFLKRUMRJHFLKRUTSJHFJHF)+2:97F=CF=CJHF:97D;9d\\d\\VTLdc\VZTLKRJHFUTSJHFFD;JHFFD;UTSMSStllMRKUTS\[[UTS\[[\[[[TTf]cSKJSKJD;9JHFUTSUMRlddVZTUTSlekdc\lks\[[[TTddcF=CSKJFD;UMR:97JHF:97:97MSS:97\[[UUY\[bllkult{||JHFJHFFD;>B9>ECJHF:97JHFLKRUTS\UZ[TTUMRMRKd\\VTLJHFekdlldlddJHFF=CFD;MRKSKJSKJlldlddSKJllkUTS[[TJHFJHFD;9D;9:97:97>B9:97>EC:97D;9:97JHF[[TSKJSKJlddJHFFD;\UZJHFJHFSKJSKJSKJ*)(ztl{{t||{{t{tt{ttllkdc\lldldddc\[[TJHFedkdc\ddcmttlkstts]bZllklddtllultVTLMRKJHFUTS]bZ[[TUTSJHF\[[UTS\[[tslbVZllktsl[TT]bZ]bZFD;JHF>ECJHFJHFJHFVZ[UTSddc[[Td\\UTSVTLd\\SKJ\[[\[[UTSVZ[JHFJHFD;9dc\JHFJHFUTSSKJUTSJHFJHFd\\JHFJHFJHF:97UTSJHF:97FD;JHFVTLJHFJHFJHFdc\[[Tkd\JHFD;9JHFJHFJHFFD;FD;SKJ[TT[[Tldd\[[JHFddc\[[lldd\\[[Tddcllddc\VTLFD;JHF]cdllkddcldd\[[[TTd\\]cd\[[]cdJHFLKRJHF]cd*)($:97*)(*)(?;C:97:97*)()+2:97:97:97:97UUY3+**)(74,!*)(*)(*)(*)(*)(74,*)(*)(*)(JHF*)(:97*)(:97*)(74,3+**)(*)(3+**)(*)(7-2*)(:97*)(*)(*)(:97*)(,55*)(*)(*)(*)(*)(*)(*)(:97&&%&*)(>EC-1+%&FD;)+2LKRLKRUTS?;CJHF*)($*)(*)(,55*)(*)(F=C*)(*)(*)(*)(*)(74,:97-1+*)(*)(*)(:97:97JHF*)(74,-1+*)(*)(*)(74,3+**)(*)(&&*)(*)(*)(!*)(*)(*)(*)(*)(*)(*)(*)(:97*)(*)(:97*)(*)(D;9:97*)(-1+VTLSKJFD;\UZ[[TJHFSKJJHFLKRJHFSKJSKJ3+*:97:97JHFJHF74,:97LKRUTSMRKMRKJHF:97*)(:97*)(:973+*:97*)(:97:97JHFLKR>ECJHF,55:977-2*)(-1+74,:9774,-1+3+**)(*)()+2*)(*)(*)()+2:97JHF:97,55*)(*)(*)()+2*)(*)(?;C*)(74,:97*)(:977-2*)(JHF*)(&&*)(*)(3+*:97*)(3+**)(*)(*)(*)(74,3+*&&&&3+**)(*)(&&-1+*)(*)(*)(SKJ*)(*)(:97*)(D;9:97:9774,74,*)(*)(>EC*)(:97*)(*)(*)(*)(*)(*)(74,*)(-1+,55,55:97)+2*)(,55:97:97:97LKRJHF?;CUUYf]c\[b\[b\[[[TTSKJUMRJHFllkUTSllkJHFMRKVTLUTSJHFF=CVTLJHFFD;JHFJHFUTSJHFJHF>ECJHF>ECJHFJHFJHF:97LKR:97F=CJHF:97D;9:97:97:97:97FD;:97:97:97JHFF=CLKRJHF\[b\[[MRKMRKdc\]cdLKRek]UTS\[bMSSMRKJHF\UZJHFJHFVZTMRKJHFMRKJHFJHFJHF:97:97:97:97JHF>B9JHFMRKJHF:97D;9UMRVTLJHFFD;VTL[[TD;9JHFFD;>B9:97:97>B9D;9FD;JHFJHF>B9D;9:97JHFD;9FD;UTSSKJD;9FD;SKJD;9SKJJHF[TT[TTJHFJHFVTLVTL:97[[Tdc\VTLllkbVZf]cek]>B9VZ[\UZ>EC\[[VZ[UUY\[[\[bLKRVZTfkk]cd\[[[TTUTS>B9MRKMSSJHFSKJddc[TTVTLVZ[UUY\UZUMR\[[MRKllkVTLJHF:97SKJ[[TVZTJHFJHFVTL\[bJHFMSS[TTLKRJHF:97JHFD;9:97JHF:97JHF\[bf]cJHF:97VTLJHFJHF>EC:97>B9JHFSKJ:97:97SKJJHFJHFJHFJHFFD;SKJD;9MRKJHF74,JHF:97:97JHFFD;UMRD;9SKJbVUFD;MRKb[UJHF:97UMRMRKMSSLKRFD;:97FD;JHFekd:97JHFUMR]bZJHFUTS:97JHF\[[LKR\[bLKRMSSJHFLKRMSSOS`OS`JHF|ztlv{tsl}Ĥv}ult}wlztl}[[T\UZ¿¾Ƶ}Ʀü||}||lks)+2?;CLKRdc\ultd\\7-2>/Att{\[[f]c]bZ!:97%lrilridc\ddc:97SKJlddlldSKJ|:97*)(JHF[[TLKRJHF\[[JHFSKJVTLldd{u{f]ckd\]cdddcred{zmSKJVTL3+*:97%JHF\UZlld7-274,%&$VZTuzttll[[TUTSMSSVZTVTLVTLtlldc\tll[[Tddc[[TJHFJHFUMRekdddcUTS74,@/7 74,73FD;VTLRP:tslredbVUVTLD;9MRKFD;FD;D;9C8.]bZ&&&&3+*FD;D;93+*3)D;9dc\VTL3)FD;%&&0FD;SKJD;9D;9VTLdc\[[TVTLjcV||SKJ>R.VTLJHFGSu]cd|z|zlrityglldsreD;9SKJsre{{t|u{ttlddf]cMRK}{tttllek]f]c[[T]cdUMRD;9UUY"%VTLFD;JHF\[bf]cMRKfkktsllri[[T ,55-1+>B9VTLUMRD;9VTLVTLlldSKJ\[[sre{||VTLd\\{ttSKJfkkJHFD;9SKJsleVTLcbV>B9VTLVTLyledc\3+*"FD;FD;d\\D;9Q?@SKJ >B9*)(:97*)(]bZ7-2SKJ3+*dc\zllUTScbVJHFlldtslJHFlldf]cJHF\[[LKR%&-1+,55{{VZ[llkUMRlks]bZJHFF=CLKRf]clddlek\UZf]cMSSSKJf]c>ECf]c74,[[T]bZVTLttstll|]bZedk{u{[TT{ttUTSLKR\[bUMRJHFVZTUTSJHFJHFVTLdc\lldultVTLtlldc\uzt{ttSKJSKJSKJ74,UTSf]cf]cJHFkk]JHFD;974,*)(>B9*)(JHF3+*fkkultUTSJHF\UZUMRVZ[[TTd\\lriowd\\uzt]bZtsl\UZLKRultuzttts\[[lddFD;-1+FD;>B9%)*)("*)(FD;SKJFD;j]\UMR[[TFD;SKJ:97C8.D;9D;9SKJFD;JHFFD;JHFtllUMR:97SKJb[UVTLFD;JHFVTLD;9F=CPF=JHFD;9D;9SKJJHFVTLJHFvu|u|vlricbVJHFtsl\[bSKJ7-2[TTuzt|lldllklrib[UJHFb[Uultult[[Tlek{{tlldSKJ\[b{{{{tj]\tllultekdSKJSKJ\UZD;9ldd\[[[[TekdF=CVZ[JHFdc\uztultlri:97]cdfkkMRKJHFttsddc\[bJHF[[Tdc\]bZlriUTSddcVTLSKJUTSf]clri[TTztlb[UVTLVTLlldVTLVTLlddd\\cbVSKJMRKVTLkd\{ttb[UUMR\UZFD;*)(:97[[TFD;[TT:97>EC:97[[TJHFFD;sle[[TMRKVZTSKJVZT\[[>EC\[[UUYUUY>EC>ECJHFJHFUUY]cdJHF\UZ]cdlksddc>ECedkJHFddcj]\UTS\UZ\[[edkbVZf]c\[b[TT:97D;9[[TMRKb[Uek]VZTUUYJHFUUYVTL]cdd\\f]c\[b\[bD;9lriMSSSKJd\\[[T[TTsle\UZ\[[UTSb[Ullk\[bSKJtll\[[SKJSKJ*)(UMRUMRSKJJHF&&3+*:97JHF74,:97JHFLKRSKJf]c]cdf]c]cdedkVTLb[UVZTmtt[[T[[T]bZ[[TUTSu{{ddc{{t{u{lksf]c]bZ]bZVTLlri&&&&SKJaWM[TT[[TVTL[TTb[UFD;3+*FD;FD;VTL74,D;9VTLSKJ[TTd\\[TTD;9SKJJHFdc\JHFJHF[[T[TTJHFbVUUTSaWM[TTVTLtllllkSKJtsl{{t{zm{u{kk]]bZ|zMRKdc\VTLJHF%UMR{||ttstts\[[|tzlrfklddult{||ekdlddldddc\ddcb[Umtttt{ldddc\{ttultlriUMRUUY|dc\lekmttVTL\[[F=CMRKVTLfkk{u{{ttMSSMRK\[b:97ekdb[Udc\ult\[[:97dc\JHF[TTMRKddcu{{dc\j]\d\\[TTllkSKJkd\j]\d\\tll[[TlddmttVTLlldVTLJHFFD;D;9SKJJHF[TTddcD;9D;9*)(FD;b[U:97SKJsle:97SKJVTLddcVTLlld{||VZTddc{||llkF=CultlrimttJHF]cd>ECLKR:97MSS\[bMSS]cdVTL\[bddc>ECSKJ\[b\[[{||}JHFddcbVUulttts\[[FD;:97VTL3+*JHFVTL:97d\\:97]bZdc\ekdddcUMRLKRD;9[[T[[TJHFf]cbVZkk]tlldc\zllSKJb[Ukk]edkf]c{u{lek]bZUTStt{f]clddUMRUTSSKJJHFVZTFD;VTL:97FD;FD;lddJHFv{fkkVZ[VZ[\[[slelldlkslriJHF[[Tkk]\UZdc\VZT{ttVTLlks]bZ[[TJHFJHF&& &&3)[TTSKJbVUkd\f]csleSKJ:97FD;&&FD;PF=FD;VTL[[T[TT[TTb[Ured:97[TT[[TVTLFD;VTLJHF[TTVTLf]cVTLSKJVTLD;9lldbVZJHF{zm}{ttlddMRKmttiq]zl|zUMRVZTJHFSKJ|tt{d\\lkstts[TTJHF{{tlrid\\[TT[TT]bZ[TTddclldlddlldSKJJHFedkUUYJHFlekJHFUMR[TT\[[{zmUTS\[bMSSVTL]cd{{UTSekdSKJLKRddcSKJllkJHF[[TFD;]bZlek]bZek]\UZVZ[UMRkd\lddztluzt[TTb[Ulekd\\{u{FD;VTLmttmttllkSKJMRK74,D;9VTLVTLb[USKJbVZ[TT&&PF=VTLVTL\UZek]>B9D;9tsl\[[ekdkk]mttdc\llk{ttllkSKJ\UZ{{llk\[b]cd>ECLKR:97LKR{{|z\[bf]ctt{MSS\[bVZ[LKRttslldj]\iWUUUYldd[TTf]cf]cJHFJHFJHFFD;JHF[TTtlldc\FD;JHFbVZlldlldddcJHFUMRSKJSKJSKJJHFSKJ{ttSKJkd\ulttll[TTSKJ{zm\[[ult{ttj]\cbV]cd\[bJHFf]cv\UZkk]jcVVTLMRKVTLsreUMRFD;UTSlekllkUMRUTS]cd{u{{{tddcu{{]bZuzt[TTsred\\b[UVTLVTL{ttVTLf]cFD;74,VTLVTL>B9 :97*)([[TD;9SKJVTLkd\d\\VTLredb[UPF=FD;sreVTLjcVek]UMRldd[TTUMRlddSKJkd\b[UFD;D;9SKJdc\JHFtll[[TSKJ74,SKJlldf]cLKRuslev{JHFVTLsreFD;ZbNlldf]cmttUMR{{ekdttsttstll{|||{||ultsleek]llkdc\ddctlltllddcd\\\[[mtttt{\UZUTSJHFb[U\[[{{JHFUMRVZ[UTStslu{{{||\UZ\[b[TT]cd>B9FD;f]ctt{:97\[[VTLdc\[[TlritslMRKFD;[TT[[Tredtts{zmdc\UTSd\\SKJSKJD;9VTL]bZrfkttsFD;!D;9VTLJHF\[[SKJUMRVTLJHFSKJj]\d\\D;9i\VJHFD;9ztlUTSlek[[TekdVZTekdlddtsllekd\\]cd{{tbVZJHF\[b>ECLKR]cdlkstsl{{mtt{{f]cJHFUTSultlddVTLUMRf]c\UZf]cv{lekUTS]cd>B9MRKVTLVZT{{tlekfkktlltts{||]bZF=C74,SKJddc|lldlekf]cdc\zlltll|ubVUb[Ulekd\\tllultddcSKJSKJf]cUMRldd\UZSKJD;9JHF[[TVTLSKJVTLVTLJHF}}{{llk]cd[TTd\\sleultleku{{|tslf]cVTLFD;[[Td\\UMRD;974,MSSVTLFD;%>B974,MRKJHFj]\kd\FD;UMRcbVjcVkd\ztfcbVC8.VTLFD;VTLek]VTL[TTkd\PF=JHFVTLjcV{zmd\\PF=FD;SKJ[TTSKJbVUVTLcbV]bZtslek]JHFzllf]clri]bZztl|g\rq^è|~tllultuztddcf]c{u{{tt{{tuztutllultfkkf]cSKJv{dc\{u{ddc}JHF{{lrid\\|z\[[UTSUUYlksJHFddcD;9edkVTL:97lld||{||ttslldldd[TTUTSj]\b[UVTLSKJ:97{u{lddSKJrg]b[Ullkllk{{t{{D;9JHFMRKVTLUTSuzt[TTddcD;9:97sle[TTdc\SKJHR>SKJrfktslmttJHFdc\ttslrilri|z|lek{{t~MSSmtt^fsfkktt{mtt{{\[b{||[[T\[bultkd\\[bVZTmttlek~mtt{{mtt{u{JHF[[Tdc\|llktlltsluzt{u{ultllkJHFUMR]cdcbVVZTddcF=Cb[U||tlltlllddlld{{tdc\mtttll}zlldc\d\\SKJ[TTlekrfkbVZwlaWM74,JHFlriD;9ddctllekdttszllu{{u{{VTL{zmb[U{{u{{tllutll]bZ]bZztlcbVultUMRF=CSKJiq]MRK3+**)( *)(JHFredsleb[Ub[Ukk]cbVtslVTLFD;ZbNdc\jcVztfFD;]bZbVUtslb[UVTL[TTtsl}VTLZbNkd\rg]j]\{tt|vcbVFD;tll|z>B9SKJ}}]cdjcVmttkk]ekdultǜË{{{u{{||}ztl{{|uttsllk\[[b[U\[b]cd|z{u{\UZ]bZlkslld}{||llkVZTMRKF=C>ECrfk[TTMRKttsJHFlddllk|mtttllj]\redUMRJHFSKJcbVVTLFD;ek]dc\j]\lldJHFlekttsuzt]bZSKJ]bZult|u[TTUTS]cdVTL[[TsleVTLD;9aWMVTLtll{{tuzttsl{||lri|zzlllksOS`]bZlks]cdtts\[b~\[bddcUTS{||||{ttddcedkzllf]c{{fkkUMRttsJHFllkVTLlddztl{ttttsdc\lri]bZddcttsVZ[JHFrfkf]cllk[[TSKJ}lddrfkjcVslekk]lld|||SKJ{{UTSv{\[b[TTb[Uuzt[[T\UZkjVJHFD;9VTLllkbVZ{{ddc\[[\[[|lldddcrfktzl{||b[UFD;d\\VTL{ttd\\UTSFD;\[[FD;&&%74,>B9uzt{tt{yfztl{zmb[UaWMSKJVTLJHFVTLVTLVTL|zkk]VTLkd\lldbVUSKJ[TTkk]sleaWMVTLkd\SKJj]\tllutd\\ulektslVZ[SKJzllv}aWMtts]bZUTS|}}]bZdc\|d\\ztl|tts{zmj]\f]c{tt}\[[\[bf]cf]c}|||mtttyg{||UUYtt{ttsllkUMRUMRnv\[[}ddctt{{{t{{t\[[lddUMRredkd\lldaWMb[Urfklddsletllldddc\lldvUTSJHFuztv{tllkd\||LKRJHF]bZb[UuMRKUTSkk]JHFbVUdc\{{sleult|ztts{{t{{tulttts]cdMSS>ECMSSlddmttf]c}ult{{t]bZdc\f]cSKJf]c[TTleklrif]ctts]cdD;9MRKFD;[[TSKJbVU[[T{ttlld|\[bekdlritslUMRlldttsbVUtts}|||ulldiq]{tt||lkslektll|vFD;JHF\[[dc\ultlri}llk{||tts{{{{b[UztflldddcUUYiq]zlluddctsl]bZf]cultf]ckk]\[bC8.D;9]bZJHF!FD; 74,VZTtllwllddwl[TTSKJrg]C8.dc\sreaWMaWMPF=JHFFD;{ttSKJSKJ[TTVTLek]i\VSKJVTLVTLSKJ|ukd\VTLsrellktsl\UZ3+*}||zrr]tzlrg]ekd|zlldvut!VTL{yfu{{|rfk[TTlri|uj]\|zLKR{||tt{|FD;}||lks}ultlri{||lrif]cuztedklksf]ctllttsllkUUYVTLdc\dc\SKJ[TTd\\llk{||||SKJsle\UZf]cylemwrg]ekdddc}VZ[JHFVTL{{tslekk]tll\[[ekdd\\VTLb[U{ttSKJkk]kd\{u{|uldd{zm{ttu|z{ttlldultyltzlddcMSS\[bMSSUUYddc\[bMSSlks{{mtt\UZlld{{tsl{tt||f]c]bZ~ultfkkztfMRKMRKtt{SKJr]ZVTLj]\sle{{tlkskk]ttsdc\JHF]cdlritll{tt||ztllldtts}|f]cf]culti\Vfkk]bZultkk]SKJ>B9VTL|tsl{{mtt]bZdc\{zm\[b|ztll|tt{f]clri}|tllek]JHFsleJHFaWMJHF*)(:97!JHFbVZd\\j]\sle|ubVUVTLsleaWMztfztfHI/VTLFD;jcVVTLVTLSKJSKJJHFkjV}VTLd\\d\\bVUSKJztl[TTkd\VTLult{tt>EC:97{||vvu|v{{||}*)(&&nddc|}||VTLD;9tll|u{{||SKJtzl{zm\[[ztf}{||VTL[TTb[U{{tztl[TTSKJUTSMRKf]cUMRllklddultlekddcztld\\VTLwl\[[rfkkd\}|{||b[Ukd\red{u{iq]|u[TT|tslekd[TTJHFD;9[[Td\\|usle{||JHFVZTdc\kk]VTLVTLVTLjcVd\\{{t]bZ{{t{zm||z}||lek{{tsl{u{{u{>EC>EC]cd\[[\[bmtt\[b{{ultFD;d\\lkslld[TTlekUMR|{u{ult~mtt[[TVTLllkSKJztlredlld[[TtsluztVZTJHFFD;lri}f]cbVZztftzlred~{zmsleFD;sletsl{u{ddcJHFUTSSKJf]crfk\[[d\\JHFJHFlldMRK|ult{{tll{u{{{ekdsletslmtt}|||}|z|zzl||lks}UMR\UZlekb[U\UZJHFVZT?;C3+*:97SKJ|u}ztlrg]r]ZcbVd\\SKJi\VjcVcbVcbVVTLVTLaWMztl[TT[TTsrejcVredb[Utllred{ttredrg]cbV[[T|\[[:97{u{Ɣ]bZ{{|lks}|dc\iWUred||tslredcbVf]cfkklri}|lri]bZldd\UZj]\lddllduttslekSKJUTS\[[{u{rfkbVZJHF[[Tllduztwld\\[[T\[[tll|u||{{tlldf]cutb[UUMRztlbVZ}JHF[TT\[[uztdc\|u}\[[srelddkjVnVTLaWMj]\VZTllkd\\ekd}{u{{u{[[T}{u{f]cMSSn{{~ttstt{\UZJHF\[[|z|zultlekf]cvddcekdJHFmtt{tt}|{tt{||SKJkd\|ztzluztkd\j]\F=C\UZSKJ{||{u{kd\uttlltllult{u{ztlwl\[[{zmuztl[TT\[b\[[\[[llklri}UTS\[[tll}|mttiq]FD;]bZut}ddcVTLddckd\{tt\UZtsl||tyg|f]cUMR\[bd\\|VTLUTS>B9JHFUUY3)JHFj]\|u|uslecbVdc\jcV}aWMSKJb[Udc\rg]nrg]d\\rg]lldb[UztfaWMSKJlldd\\||VTLdc\j]\¿VZ[JHFtslu{{]bZ}~^~Y3+*}|zVTLiWUyle|z}|slesle|}\UZ]bZ|ztzl{{llkmttj]\dc\{{ttsltts\UZttsJHFSKJd\\lriult{u{{tt||UMRd\\ut{tt}lddldd[TTut}ultkd\lddttstllUTSSKJUTSddcb[Ulri|z}lrisresreJHFldd|{zm\[b{u{f]clrilri{||uzt{{{{uzt}\[bJHFVTLfkk|z{{tult}lriwl{u{tsltygmttlriVTLmw~sle|zbVU{zmVTLf]cbVZldd}|v{zllf]cSKJutult}zllllkcbVkd\{||b[U}}SKJSKJllk]bZekdd\\f]cFD;VTLaWMcbVj]\ddc{u{\[b~d\\ekdFD;|z}|}}tt{D;9lksJHF:C+MSSJHF MRKttsi\Vlld{{tkd\f]crr]rr]ultzllkd\VTLrg]VTLrg]j]\|uj]\FD;sletllu\[[{yf[TTUMRaWM}|VTL|u|u¾UUYJHFnVTL}JHF{{LKRr]g|zkk]kk]|{||d\\lld{||{tttsl}{||]bZ{{redtts|ldd{{lek]bZbVZlks|{{tllk|||z|u{tti\Vredd\\|j]\\[[tsl}[[T||lks\UZtt{slev}|z|uf]cuztek]ztlkk]tslSKJ\[[{zmztl}{zmuztfkktt{{{tts[TTUTSlld[TTtts|mtt]bZtt{ekdtslllk}mttd\\UMRekdtlltllleku{{MRK]bZ|kd\|zkd\wlcbV|ztslekdlddttslldyleultzll{ttutSKJzllttssle{tttslldd|{ttultlriuztVTLJHF[[TUTSFD;JHFkk]rg]|ztsl|z|z{tt{{td\\tt{fkkVTLredtts[TT\UZ:97SKJVTLFD;:97%:97\[[dc\llkztlb[UjcVd\\kjVd\\aWMdc\VTLPF=SKJylelddVTLSKJVTLdc\{zmrg]{yfrg]bVZjV[zllwl{{t|u||\[[74,ldd}rr]b[U}j]\lj}:97SKJztlnjwl||llk~{||v{kk]{{||{zm}{ttmtt[[Tf]cldd}{u{tllmttllk}tts{{tsl|VTLut|z{||rg]}{||sleVZTFD;red|vztfsle\[btsltts{ttldd[[Ttll||u\UZultlldkd\cbVztlj]\bVUlriuzttsl|}{tt{{JHFiq]llk[[T{u{{{|mtt{{ttsekdVTLddc|ttsj]\~ddc{ttf]c{||]bZMRKmttu{{|z}{||tslllk|utsltts{tt\UZ{tt|bVUllkredrg]}ut|v{ttutbVUd\\VTLtllttslks}}¾Ɯ|f]c{ttdkVkk]jV[llkf]c{zmfkkVTLzldkV}|UTSekd:97r]gUTS:97ultedkJHFD;9dc\,553+*[[TD;9JHF[TTUTS|u}{{t||zll{zmutrg]rg]kd\SKJVTLVTL[[TVTLVTLldd[TTVTLsreusreiq]VTLsleutred||lldwlztl|\[b:97wl{tt}|}zlJHFjcV.1SKJŲultf]clldv{||v{|tll|u|z|wl{ttrfk}ultlritsl}tzllrilksSKJf]c{tt}UTS|zred{||v{tslutb[Uztl{||[[Tzllkd\i\Vldd}ultuzt||tllb[USKJ[[Tllkv{yleldd~[[TMRKkk]d\\SKJkk]j]\}{{tult}|tslu{{uzt{||v{{u{{{|LKR\UZlddllk{{{{lksnvmttUTSVTL]bZtt{llktll}}|tslMRK]bZ]bZiq]]cdtzl[[Tsre{zm{{t||ztts||rg]f]c|v{dc\llkSKJv{{tt}llkztl|ztslztf}j]\rfk}sle\[[ultekd{{{{lrizlJHFtzltslyle|b[Uuztlrilrilld|ztt{]cdlrisreztlf]c{{tll*)(SKJkd\VTL3+**)(D;93+*JHFJHF{{tztl}ztfVTLSKJjcVVTLSKJb[UVTLkk]jcVwlj]\kd\i\V[[Tkk]u{{ttslZbNzllr]Zzllyle[TTkd\{{tLKRLKRf]c}}tt{j]\JHFUTSldd]bZ|u|z{{tred[TTslemttmttuzt{{t|z{{t|{{{{t}{||{||ultlld\UZllk{||lddb[Ud\\v{uztutlri{||dc\jcV{{llk||{tt\[[kd\{ttb[U|tsl||sleSKJr]glldf]c\UZVTL}|{{tVTL{ttlksSKJtsl[[TJHF{{tlrimttuztuzt|z|ultllk{{{{lks{{}|edk{{|{||sleddcddclld|f]c{tttslVTLVZ[tzltsl{ttddc||z}ut|mwUTS{{tslelekv{}}ttsutsre\[[b[U{tt}{{tslelksd\\ldduztmtt}[TT|zttsJHFz}llk|{{\UZek][[T||tlllks|mttSKJzllekd\[b?;CFD;"[TTslei\VsleutVTLrr]bVUPF=VTLjcVd\\lldVTLsrelddi\VVTLSKJwlzl}|lrirg]b[U{ttbVUut|v|ukk]|zVZTUTSult}zrg]uj]\j]\bVUMRKSKJ{ttutztl{{t|z}|usleu{{{||{ttu{zm{tt|{||}{ttlri|uv{d\\lek\[[]bZ[TTf]c}uztbVZ||wldc\lddd\\{zmtlltsl{ttj]\ztfkk]SKJ}|{tt{ttJHF[TTd\\ultekdJHF[[TSKJ\UZdc\dc\SKJVTLultult|uu{{{u{||z{tt\[b\UZultlksu{{{u{kjVu{{\UZJHFj]\]bZ]cd\UZ{tt}tzldc\{{t{||sre|z|uredf]cSKJllkf]cVTLJHFSKJbVU~ylebVZFD;kd\{yfd\\{zmzll|rfku{{d\\r]g{{tf]cJHFultf]c]bZ]bZek]{{t\[[{{{{llkf]cslett{edk{{tldd|u|jcV{||ekd\[[VZT[TTF=CFD;74,lldf]ctllwl|utVTL[[TVTLb[UVTLb[Ulrikk]bVZddcSKJsle{ttVTL{zmu|ztsllldlddtllv{rr]wlztf{{twlfkkMRKtts}|tzl}jcVVTL|zF=C?;C}tslsle||z}u]bZ|{{t||rfk{u{tsllddekd||d\\}lldllkbVUzll|z[[Tsreultulddtslwl|u{{ttslf]cekdPF=bVU}j]\[[T}lddtt{f]c{tt:97lldUMRultekd]cdVTLbVUbVZfkk|ztltslSKJ{tttsllri|u{{lrifkklkstt{JHFVZ[g\rmtt\[b{{tt{d\\[[TVTLVTL{zmcbVtts{u{bVU{u{uztVZTttsuztuztlddf]c}[TTtslMRK[[T{{v{d\\||tslf]cutrg]VTLkd\{{tlek[[T}tygllkljVTL[TT\[[|zldd|dc\lriedkekd]cd{{\UZ[[T}|uzt{{tmttttslriVTLslelldr]ZD;93+*|zkd\{yfFD;JHFSKJjcVMRK|u|dc\utkk]SKJtsl]bZbVUkjVsre[[TtllD;9aWMslesreultj]\sreusreredttsutultwlu{{t]cdMRK\[[{ttldd]bZ]bZzllwl|}||SKJFD;}u{tttll{{t}|tll|||zred{||cbV]bZ{u{ztl\UZ}|z}{||tsldc\{tt||}slekd\ultsleztlult|vtll{ttllktllredUMRtslVTLtts{tt{ttekd]bZaWMredllk|kd\u|u{||ultlek{{ddc]cdf]ctsl{{lks{{j]\VTLFD;[[Tldd|ultllk{||lri|{{t{{t{|||zd\\tzl{{t|zu}[[T3+*lektllyfltsld\\ldd}|ut{ttwl{u{VTLcbV}||[TTVTLVZTuttsl{u{{yfmtt\[[{u{kjV}|tzl|lkslldkd\llku{{|ztt{VTLusleJHFbVUUTS:97UTSD;9VTLiq]JHF%PF=b[Ulekrg]}|z|||utslkk]kjVVTLdc\llkdc\JHFb[Ukd\[[Tb[U{ttwlwlvtsl{zmred|vsle}}\[[JHF}ultdc\dc\kd\VTL}{{[[Tdc\b[Ukd\lri||}tzluzt|zsretllr]gzllri|u}}|zttsVZT}|{{tsl[[T|u}||llktll|tsl}}lddredaWMtllcbVJHF[TTult{u{j]\UTSllkztl|tzlkd\ult{{tztltslkk]|u{||lkscbVmtt}lksJHFuztmtt|ulttt{{||mtt\[[{zmSKJMRKlekultult[TTlritsl|ztsllri{tt||zdc\b[Uedkrfkred[TT}}v{[TTkk]|uutwv{lld||SKJd\\tll{||j]\mtt}tsl{zmztl|z}f]c]bZu{{{tt||ztlredu{{tslu|z|UMR7-2SKJFD;MRKLKRtt{3+*73JHF[[TutsledkV[TTPF=VTLFD;bVZu|u{zmtsl]bZ{||i\VztlSKJedkwl|zr]Zljzll|vlj|u}|v{[TT:97tsluuzt\[[}|lld]cd~f]c[TTb[Uyletzl{{ztl[TTbVU|{{tddclrisreVTLtllultkd\u|z{zm}lritzl{tt{{ttslkk]}redtslutztllri{zmaWMujcVd\\SKJVTLkd\{u{\[[lri{{tf]cSKJ{{[TTrfktts||lriyfllek{{tult{ttsresre{zm}sretll{||lrikk]{||{{tultf]cVTLVZ[|z]cdmttllk}ttsdc\MRKjcVtslztlultf]ctslult}dc\|zVTLttsult|||uztliq]lriSKJu{{UMR|zSKJf]c}{||}f]csre{u{ldd}ultuzt\UZVTLlrilld{u{ddcek]lddkk]b[Usle}\[b{zmztl{|||z}]bZu}|zttsmttlks[[TVTLFD;74,UTS3):97iq]dc\|z{{tVTL|ucbV[TTVTL|zsle\[[VTL|uztl}|edktllwl|utsllldd\\d\\}|ztl||u{zmuv{UTS*)(ztfVTL|vlriVTLllkr]Zb[U:973+*rfkyfl|ubVUVTLFD;red|ultult{{ttslv{lrilksuzttt{}zedkaWMek]|uztfzll|tll{ttwlkd\rg]sle}|ztllrir]gSKJf]cb[Uekd|u{ttd\\UTSulttslsle|kd\uztlkskd\SKJlld|zlld{{tzllldlld}ddcf]clksJHF]bZmtt\[[tt{}{{u{{bVZFD;tslddclld|uu{{lks{{t|{{tuztekdUTS~ztltt{uzt{{tztl}kjVuztultjV[|vjV[v||utf]c{{tcbV|{||ztfultb[UttstllddcMRKlriVTLFD;lld|llk{u{llkmttllktt{}lriekd]cdf]cbVUVTL>B9FD;:97FD;&&C8.{{t}kk]ultsleulttslJHFVTLVTLsre]bZVTLbVZlldlddcbVlld}wlttskk]||||}|wlbVU|usrei\V|u}>B9:97jV[bVZu{{i\Vekdllkkd\aWMVTLJHF|tts{u{sle\[[tzlr]gtslldd|z||||lri|z|SKJ}{|||zkk]tsl|}VZ[|{zm}ztflld{zm{||}SKJb[U|[TTredzllztlldduylelj{u{tll||llktllultb[U{{JHFtsl{||lriuv{]bZ}|}u{{ttswlsle|ulld}ztl}|udc\ekdrfk{{mttF=C>EC]bZf]cdc\\[bVTLVTLUTS|ui\VF=Clldiq]dc\[[T||{||uuztuzttsl]bZredult|rg]f]c[TT|v{}|z|uv{}|{zm||redbVUUTS{u{lld|||lri|zkd\d\\kk]u{{ult\UZtts\UZtt{u{{{||lrilld>EC%FD;74,FD;SKJVZT3+*&&C8.yle|z|||z}JHFJHFlri]bZVTL:97VTL{u{tzl}lddrfkllk{zmlri|VTLrfk}|v{u{}utztfMRK*)(ut|z}{zmJHF|zllkuztlekttsi\VD;9D;9}{{cbV[TTedk||b[Ulrikk]ddclldVTLekdSKJj]\F=Cj]\{{sle]bZlld{zmrg]ddcf]cj]\j]\ddcldd}tzlztlsle}ut{||~fkk}|tslmttf]ctslUMRSKJlksslef]clddddc{{tslttslriuzttslzl{||utsre||uztVTLtllultddcedkekdLKRu{{lkstts{tt{{j]\MRKVZTrfklektsluzt}ttstsllkstts|lld{||ldd~}mtt{{lek||tts||wlb[U\UZtllrfklddv{|z}j]\|uSKJ{{JHFddcredulttt{ult{zmultlddutlldllk]bZ:97aWM3+*C8.Q?@F=C%&&&tlllri{zmVTL||VTL|ztl{u{JHFVTLlldJHF\UZ[TTtsllddtlld\\tts[[Tsre[[TVTLkd\kd\}rg]}sleutMSS:97tsl|wlekdJHF|ztt{uztdc\|rg]74,bVUUTS{||ddcekdlritsl}slellkVZ[{tt\UZ{|||VTLSKJ]bZFD;[TT|zmttrg]ttsd\\rg]}|{ttkk]tsllldtslv{{zmkd\lddmtt}}{u{f]cultUMRztlultj]\}kd\llk||lri{||ttsf]c[[Tsre{tt{||ttstsl{tt{||}lek{ttuztMSSmtt{u{ek]{u{{u{f]ckd\lddd\\SKJtslf]cdc\{{t[[Ttllf]c\[[u{{mtt{||ekd|vkd\|u{ttVTL[[TVZTlri|u}|{u{tsl{u{{tt|u|zllkultlddslej]\{u{j]\}tzl}UMR[[Tj]\{ttultf]c\UZslerg]f]c{ttvfkkf]ctsl\UZ}{u{{{:97lldmttF=CFD;>B9FD;|zj]\|z|zwlsletzlaWMrfk[[T[TTlri{zm\UZlddcbVtsllldSKJttsttsVTL[[Ttllsre[[Td\\{zmrg]lldrg]||v{zmJHF3+*{{trr][TT||llk{{t|uC8.JHF{{tuzt{{t}lksdkVlld|\[[|ztltzl|zlri}{u{utult{{ttslkd\jcV||usler]gyledc\d\\|ulld{{tsletllrfklddllkyleekd{u{edktzl{zmlekf]c{{VTLrfk]bZ|z[TT{u{tzlfkk{{tredlriv{lld[[Ttslzll|z{{t}lek{||{{{{{u{ttsttsfkkd\\\[[zll{u{||||]cd||ut|tslJHFmtt{{tuulttt{kd\{zmsre{u{\UZlekult|lrirg]iq]||ttsldd[TTult||lldredlldv{||kk]u{{VTLb[U\[bSKJ{{r]gUMRuVTL]bZJHF\[b{|||udc\kk]ultrg]\UZtsltzlddclddu{{tts{{tVTLredUTSUTS]bZdc\]bZrg]SKJrg]{yfkd\i\VSKJsrelddSKJ:97{zm]bZttslriukd\dc\rg]PF=bVUv{ztl}tsl||ut{||ddcb[Uttslddkd\lrilritzlutts~d\\dc\lddjcVVTL{{t{ttztltsl|ztl{{t}|}rg]mw{zm{zmredrg]v{lddredultv{fkkd\\kk]|lek\[[kd\}tll|zek]uzt}uztlri|ufkk|{tttsl|{ttldd|ulttllb[Ukk]|fkk|z{tt[[Tslelri|z{||{{tVZTdc\\UZ||llk}||ekdttstts{u{{{tttsztluztv{tlld\\sre{ttd\\}{{tldd[TTlldbVUtllutllktzl|ubVZlekllkSKJlri[TTttsd\\{zm||tllbVZkd\}]cdu{{:97{{JHFD;9|]bZ:97dc\{||rg]wlekdtslztlllkultsretts}|mtt{{{tt|z{||||d\\slesrett{}b[Ub[UcbVrg]cbVjcVwlrg]ddc*)(zllu{{lldsleUTScbV{zmHI/ultultredf]c{zmtts{{tultultdc\{||tts}||cbVtt{{{ttsutvddc||f]cUTSkk]lldVTL{{t||ud\\ztlsre||vbVUutlrilldVTLVTLd\\kd\b[U]bZ{{JHFd\\ultek]tsl||}lri]bZdc\lek]cduzt{{kd\b[UUTSult}slelekek]tsl{{tred{{t{zmj]\lkscbV{{t|zultkd\lekUTS{{ekd{{{||{||tllek]tt{}{||lldlek{{tsl||zmttf]c]cdddcztl|u|zuzt{{f]clks|{u{zllultfkktlllldsle|u{{||lrildd|ubVUttsultztf}tllrfk{{tcbV{||mtt|UTS]bZUMRD;9\[bekdzllVTL{ttedkSKJ>B9f]c{zmredVTL}}b[U\[[{{fkk{||lks{{[[Tllkdc\dc\u{{}dc\lri{zmljsle~[TT:97uztttsj]\f]cVTLbVU{{t{ttFD;JHFyflzllmtttsldc\d\\kk]lks}llk{|||z|{||uztultlritts{ttult{||sle}{zmslesreVTLtllsrei\Vwlultlldztllldtllkd\VTLSKJ|}lektslzlllriVTLd\\{ttultuzt\[[VTLrfkttsttsuztkd\b[Ulri}{zmrfkJHFJHF74,b[U{{tVTLllktslsrelriutsl|zultbVU{u{ekdmttfkk}{{u{{f]c}JHFcbVllk}{||{||lld}||z}|{{u{{JHF]bZredyllksllksreztf|z{{t{u{f]cd\\lldsle|z\[[tllztlred{tt}tllek]bVUtslv{{}|ultekdlekylelldtzl{||slemttuztMRKVTLJHFFD;FD;tzlD;9lldsre]cdJHFJHFddcaWMrg]VTLtsl|edklddlek{{llkUTSddc{tttzlult{||llkult}|{{tSKJi\V{zm{||}VTL:97v[TTjcVkk]kk]VTLbVU%UTStsl|{{tlrid\\lksuztldd{||}zlekddc\||\UZultkd\v{VTLddcleklldultkd\rg]|u{{tlddlrid\\}wlred\[[sref]c|uVTLSKJVTL|uultredfkkd\\|dc\lldlektlllld[[Tv{f]c{ttlrid\\zlllriultztl\[buztddclldrfkuztcbVllk}{||ldd}|z||}mttlks|tsl]bZ|tts}tts\UZtts]bZultlldlks|u||tlllddllk}fkklld\[blldtt{d\\dc\}|v|uedk{||[[T{{t|r]g}|{{|zrg]llk|u}||rfktt{{u{zllkd\}|tt{sretll|\UZddcek]|z\[b>B9\[[ddc\UZVTLJHFC8.JHFFD;ddcylecbVztllriztlllkddclek{ttttsllkllkttsddclek{tt|tslsrerfkcbVv|v|v|uVZ[JHF|u{{t}||{{~lldtllkk]vsleD;9UMRultsle{{tuztu{{ultutldd[[Tddctts}b[Ullk|ztslllklldlldrg]cbV|uVTLj]\{{tztlztlredd\\u{ttFD;cbV{{tultztlSKJ]bZMRKkk]}u{{tsl|zu{{}tts}ylef]c]cdlridc\{tt{zmultlld{||tllllk{u{[[Tdc\]cdlkslks{{tt{lksubVZldd\[[{tt\[[]cdut}tll}|lksċkk]ttsuztllk{{t{||edkJHFutuztlekv{~tlltsllri|||ultj]\|utts{ttldd||b[Uslelri{||||||{{tslemttjV[tslllkmttSKJMRK]cdJHFD;9JHFSKJD;9fkkaWMedkv{ddcrg]{zmlld{zmtts{u{bVU|ztll}|lddtts}lldtslrg]b[U|ztl||v}rg]UUYLKRv}|[TT{ttuzt|ui\Vrg]FD;VTL[TT{||dc\|z||tts]bZ\UZ}|tt{dc\}}jcVzlllrilksekdd\\lkstsl}srerfksre{{tutjV[}{||u||tzlek]cbVmtt[[TlekSKJlld|zut|z[TTtsl|slelldFD;sre|||z{{t|u|v{}{ttultuzt|MSSmttu{{ttsllklkstt{{||}lekuztuddculttts{{lddĄ|zfkktslztl|uzttlllekdc\||VTL}|||{ttttsu{{||wllks|zkk]}sle~v{redrfkntslcbVztlu{||||UTSFD;ZbN:97:97SKJ[TTcbVsreSKJVTL[[T{u{[TTsleultwlcbVdc\{ttlekztlnvmtt}tllf]clddcbVdc\kk]}||uwl|u\UZ>ECztfrg]iq][[T}llkztlkd\ttsredFD;{tt{tt||zekd{{|||mtttll{{tekdkk]tt{utekd{{ttt{}|{{tjcV|||wl{{t\[[d\\lld{||iq]rfkvdc\d\\[TT\[[ttsllk|v{f]csle{u{|lldSKJd\\tll|uztfllduzt{{t|ztlbVZddctsllld}|z{{ddclks}ddc\[[{||tt{{{{tt||lkstt{{{t{u{lriztlrfkf]czllztltsl}ultldd|z||dc\b[Ukd\{zmtsl}|||}lriSKJrfkultf]c}lks|u}}|||}{zm}|zttsb[Ullk\[bFD;%UMR[TTtzlJHFVTLVTLlri}|kd\}|llkttsllkddcllk|ult{{{u{u{{lksult{||u{tt|uv{|vUMRJHF{{tj]\|uttsb[Ub[Ured|v|u{ttztlD;9FD;{{sle|zllk[TT|zv|mtt|z|{{t{||{||lkskd\f]c{u{{tt}{ttrg]|uldd{u{}|tllkk]tsl[[TVTL|z~wtlllritsld\\JHF|tsl||{tttts\[bekdllktsl|ulritlllek|zdc\lldttsd\\bVUtlltts[[T[TT{{ttsVTL{u{lridc\}||||lddf]c{{t{{mttfkklldmttuzttt{lksVZ[{||ztlVZT|llkult\[bv{||{{u{{|||f]csretllllkkd\{||d\\llkulttts]bZlld[[TSKJultv{{||{||tzli\V{tt}fkk\UZ{u{tll||redvuztdc\{||ekdj]\tlllddVTLMRK[[T>B9\[[kd\tsl\[[MRK*)(u{{{||redj]\ttsekd[TT[TTddcedk\[[tts|ztts|lekldd}~vtll\[[,55|jcVzl]bZttsztl|utFD;sref]cVTLd\\lekttsӛ|z{{tf]cult|{ttd\\}tzl}tll|redu{{zllkd\wl|}i\Vw}{zm|||lldbVUttsb[U|tygredzllv{\UZ[[Tkk]{{lkskd\rr]llduztmw||d\\ddcultzll}|ylesle|ubVU{||SKJ}|[[Tult}||zllllkttsutuzt\UZMSSMSS|UTSUTS\[[ult\[b|{||{||ultedkddcv{{{t{||{||mttutt{llk{|||zf]ccbVtllmtt|z\UZv{jV[sle[[Tkd\{||ttstts{tt|uztlkd\ttskd\r]gtslsleut||||zut|ztts|lrimttut|{ttek]JHFJHFFD;JHF{||MSSMRK}JHF|zdc\UTSyfllekf]cmttredllktts{tttll|v{zm}{tt}MRK:97{tt|usreSKJsrezll{{t|u|ubVZsrekk]SKJrfk}}lks|zedkUTS|||lritllddcrfkf]cult{u{{{t|zddcf]c|ulri|zrfk{{t{tttslzlluzll|ttsb[Ullkdc\uVTLd\\f]cddcekdf]cf]c|}tsl{ttv{tt}lldSKJtllbVZztf}|ultdkV|zllv{{{tv{ttred{{t}ult{|||ultllk>ECMSSUTSllkddc{{mttfkk{tt{||ekd{||f]clksddctlltll{{tultult}Ц|uuztsre||{{t||{{t{{t{tt{||ttsztl{ttkd\|ult{||lld||}{{|ulddult|ztzlztluztl{ttyfllddtll{u{VTL\[[FD;F=CUMRd\\[[TZbNedkUTS|u{{t{||rfk||z|ttstsl}lriu{{]cd{{t{{tkk]{{tuttll{zmllk7-2}cbVkd\wl|tzlyfd{||SKJPF=kd\|z{{]bZztld\\|ztsl}vd\\lldf]c{{rfktlllkstts{{}tslMRKlks{tt{zmtll{|||[TTredkd\}uddc||||u{{lldbVZ[[Tek]\[[{u{leklek}|zultsleekdtllkd\redllksleuztcbVlldFD;lekj]\ztl|v{tt|||}ult||i\Vredrfkult{ttultlrifkklld|z]cdmttultuztult^^qf]c||}fkk}||uztf]c{|||f]ctlltslddclri}}{||{tttt{ultlddzlluzttzl{u{v|}ddclldlld|ut|utslekd\ult|kd\{{twl|ulriztllek|}tll}lld}|kd\VZTVTL:97UMR{zmekdUTSFD;MRK]bZ|zsle{{t|z{{tztl{{tllkd\\sle|ttskk]llklddlektslztl{tt{zmv{}||}VTL*)(tzlljcbV|zzlltzlkd\sre}|74,D;9{{ttll}{||}ultjV[yfd|z|}~||tsl}}{{|tt{[[Tddcek]sletts|{zmultsle\[[kd\tslVTL|{{tlddlddulttllJHFultredtsl{{bVZmttlriv|mttkd\kd\dc\|z}{{ttslUTS{{t{ttljtlltll{u{ttsultredlddkd\{ttult{||edkultJHFmtt\[bfkk{tt|zult|{||vUTSdc\llk|vv{u{{mtt{{|{{}v{{tt[[T|u|||}}|z}|{zm||{{tmttttszll|uztd\\{{ttslztf|ztsl}}tslsle}{u{kd\d\\}ekdrfkJHF||bVUlekb[USKJJHFFD;MRKSKJVTLJHF|\UZ|f]c||u}|llkekd||lri{||kd\MRKred{|||ztts||ultu{{{||{||kd\|u}}{{tsle|u}JHF-1+|zrg]kk]jcVvb[Ub[UVTL3+*ttsVTL}tts|zmtttt{}llktt{{tttslf]clkstsl{{||vultttsdc\f]cut||redi\Vkd\zllVTLldd{||[[Tllk||ttssredc\bVUttsSKJ}ultllklriredztltsl}d\\ztl{ttdc\d\\|uztl}|cbVkk]kd\||}|wlkd\ult{{ultlldfkk|JHF\[btlluzt{{}|{{t{u{ddctll{||lri{tt||z||}edk|zslelek{||tsl}}{{t{{t{{t|zdc\rfk}{||llkult|{{tslett{{{|}|bVZlldlekztluztkd\D;9VTLFD;[TTsleUTSf]c&&\[b|u}~sle|}}lldztlttsttsutlld|v{yletsl|:9774,|u{{t|urr]rg]tslyle{u{||VTLSKJ}}|}tt{lriuztult|z|||dc\d\\[[TUTSrfkldd|}j]\b[U{{tkk]{tt|kk]uzt|zttsf]c{{tsletsl}d\\v{|z{{ult{||}uzt{||jcV\[b||{u{ultut{{ttll}|}{u{f]c}lri|lri]cd\[[ekdtt{{{tsl{u{{||||ekdtll~llkwlultwlult|z}|ultult{tt{{t{tt||sletsldc\{||lek{{t{{t}|tllmwmttd\\mttztl{u{{{t|redlldtll}|rg]uzttygC8.dc\[TTldd\[bmtt\[bkd\rfk{{t[[T|ttsv{{{tslellk|ztlutüSKJ:97kd\kjV}ztlkd\}d\\tsl|zuzt}{zm[TT{zmuztu|b[U{||{u{{{{{t{||tts\[[ek]|u{{ulksult{{t{{uu{{ut}||b[Usre||sre}tt{|||uult{ttsretzld\\lrir]Z|zuttts{{t{{{ttek]tslkd\d\\tlltlllddf]c|llk}|||lddsre}{{|]bZ{||{u{|z|}mtt{|||zttstt{}tllultldduf]cttstzl|z}ut{||ldd|{tt{{t{zmuzt{u{||{tttts}lddldd{{t[TTllk|u|}u{{~ztf{{tslekk]D;9ult{{|zmttUUYd\\fkkzll|uuzt}{u{\[[~ddc]bZ[[Tddctsltslb[U|{||v{ztl[[T74,{zm}}|z{zm|zllduzt|||zztlldd[TTddc|{u{{u{}}VZ[u{{|ldduztdc\lkslriult{tttsluzt{{d\\}}ult}zll{ttldd}{{t{{lddtsl{||u||kd\|uultj]\tllllkrfk||{{t|{ttlld|zrfkj]\v{mtt}lekrg]}ztltslldd{tt{{}reduztkd\b[Utts{||{{|{u{~mttlks[[T{||llkdc\rfkmtttt{|}f]c~tsl{{tt{{zm}|u{||v{}|u}lld|lldututttsut~mw{tt|ddc|lks{u{|z}||d\\sred\\|z|vtts\[b>B9f]cJHFtll{||uztkd\tsl{{}|z}{||lld{{t\UZmtt|llktslSKJVTLkk]kk]{{t}|tllVZT-1+|||ukd\tzlVTL[TTllk}ulrilks{{t|zlks|sre[[TUTSUUY}zll||lri|cbVslettslrikk]lddlkstts||u[[Tttsekdlddtt{[TTztltts{u{ut|zuutll{u{lddkk]vlddredbVUtlllld}tt{||||z|b[Utts{{t{u{sleSKJd\\d\\}sleldd[TTddcek]utllk{u{{{t[TTkd\|slelrimttlek|||{{{{{||llk{|||z|{||||{u{}{{}|zult{||{{|zlld}{||}|{u{{u{||tsl|||{zmd\\f]csle{||}{u{uztbVU|zkd\tsl|z]bZtll}}sletzl{{lddtzltt{SKJJHFFD;llk|ztsl|ztt{sleztl{u{kd\ekd{u{[[TbVUtts|ztsltt{lldlrib[UaWMcbVdc\tsl}tsl|vJHF3+*}|uwltsltslsletlllri|u{{sle{||ddclri\[[ttsf]cUTSzll~{u{sre||mtt|zf]cttssleddctsl:97ek]VTL[[Tttslri{|||{||v|||z{u{zllv{}ult|uztlultsreyfdsleredd\\kd\bVUttssre|]cddc\{||ttsredredUMRd\\|ud\\yle~|u{tt}{u{ttsreduzt}tll{u{\[b]cdyllks||}llk{{|}}||ztsllld|uult|z\[b}{tt|zsleult|uv{}tsl}{zmsle||u{u{utlld{{tult||}||tts|udc\tt{zll|zj]\[[T}|SKJ}SKJVTL[TTlrimttddcwl{{tu{{tt{||{u{v{b[Utsl{{}lldlek|ultttstslv{{zmtsl{ttJHF*)(}uzt||f]c|udc\|ulritllUTS|ulri}SKJvlldekd\[[UMR{tt}lks}{{tredlldSKJ{||tsl~uztlri||z||ult||zllztl}dc\|}rg]|zd\\tlltsl{ttrg]ultSKJ{|||{{tsre{{t}||tsld\\mtt{ttsleldddkVbVU{||{||mttuztllk{{}lld{||[[TbVU\[bd\\\[bedk|]bZu{{|ztts|u{u{|}{{zll{u{|zleklld[[Tlld{{||zztlutVZT}}{tt[TTkd\ek]}}|}}|ttstsl||{u{}||||}|||||ubVU||rg]ztl|ult[TT{{tslelrif]c{{ldd{|||z{{t{||d\\f]ckd\VZTtts{u{{ttv{lksVTL*)(sre|lriztl|uVTL{{t}{tt[[T|zb[U{tt]cdut||}|}zl}vsle[TTUTScbV|udc\{||u}u{{v{}tsl}tllut|zek]zll{zmv{{tuzttll|v}bVUztlslered}ldd}sle|llddc\{ttllkd\\{ttkd\tll|zj]\}}{tt}llkllk||v{}tll{{ttstslmttf]c{{mttuzt{{|z|{ttVZ[{tt}uztv{~||tll{||ddcv{}dc\{||rfk}}ztl}tslztf{{t{ttkd\sle|u|zult}ċ|j]\}red|utsl{||utlldtzl{{tSKJutVTL{{t~f]cJHFlritts}ultj]\}llktsllks|{zm{{t}tsl~\[b)+2}|}dkV|u}sreVTLsle|ulrimttztl|\[[lrizll|uuztVTLlld}lrif]ctsllri{{{{{u{tllsle}{u{}sle{ttj]\}ldd{zm|u||sledc\|vj]\]bZtll{{t{zm{u{|ukd\ttsedktlllddsleztf{u{||v{tttsldc\v{|u{u{uedk{u{ttslldult{{t{|||zuzt||||zlksu{{{zmlek}tt{}ultlks|{|||tts}{{ultyfl|usre}yfdztl|u|u{tt|z|zrfklri{ttult|{tt{{tuzt}lldztfVTLSKJsleuzt[TT:97f]cmtt\[[lri{{tmtt}{u{||}ek]tlltt{[TTu}JHF*)(lriztliq]lld{u{VTLtsld\\|uzt||uztu{{u{{tllulttts{||rfkldd\[[{{t{tttt{u{{|zultred||{{tllb[U{||tts{zmslei\V}{ttutddcddckd\|ud\\}tll||zllUTStll|zusle{u{tts}}{||{ttf]ctllwllldsle|||z{u{ultttstts{tt||||lks||lriu{{||VZT]cdu{{{{]bZ}{u{tlllri}|sle|ulttts{{tJHFztl{{t}ult~tll}|}ljlri{zm}|zllkd\|z||UTS{tt{||tll\[[}|{tt{u{|z]cdztlVTLSKJ}MRKSKJuztd\\mtt|tt{|}}ttslkstlltsl{{t|ullk||tts|MSS*)(cbV}{{t|cbVdc\sreztlekdldd|u|zJHF|[TTred[[T}~{zmllk{{tut}|{{lks}|z}wlv{yflf]clld{|||uddcdc\uztb[U||{||}|tllkd\lekut{tt}tt{|lektllztlrg]tts{u{lldv{{{tddcVTL||ult|sleiq]]bZlri}\[[v|sle||{tt{{tu{{u{{fkk}mtt{{\[btsl{{tkd\lekultddc{u{UMRuztuztu{{tllk{u{iq]tll}{{}{tttsl|ttsuzt}|||b[Utsluzt{u{||ult}{ttedkSKJslett{u}slecbVrr]SKJdkVMRKf]ctzlmwekd}ldd}tts}{||tll|z{{ttslztl}ult[TT*)({{tlks{zm{tt||{{tuzttslyle{{t|zultuzt{||f]c{ttmtttlltzlttssle]bZ}lri\[[\[[uzttt{tts{tt|uztttslddb[U|zddc{{tlriztl}ztlttsztllddb[U|uslekd\{{t}|z{||{{j]\|VTLtll|z{u{ttsllk{{ttllztl|z}tlledku{{ddc|z|ekdmttmtt||tllztlztlultulttts}v{|}|{{t{zm{{ldd||~|u|udc\|||u||}}u{{}}{||||tlltts|lddedklldztlkd\|ukk]b[U{tt~mtt}tts{||llkVZ[{tt||mwmttuzt{||||}ddc||[[T{u{{zm{{}}|LKR)+2ud\\}|usleuzttt{VZ[VTL}\UZ|u|u{{|zlriuztcbV|u|}|tsl\[[|zu{{|ulksu{{tzl|z|ztl{u{{{tlrittsvtslsleylelrirg]ztl|uult}ztlcbVf]cd\\|u{zm}|{u{lldtslddc|zu|tsl{||d\\sle|u{||sre|ud\\|vkk]tlltsluzt}sre}|||{u{{{|tts|ztl}{||}tt{sre}ddctslult{{}tll|z|z|u}}yle{||llk}f]credlddldd|zuultdc\ztl|zVTL{u{lek{{tv{llku{{v{lek}v{|{tt|llk}}kk]ultf]c[TTJHF:97sre|{tt|[[Tb[U||lldtlllrilld[[T|z}tzl{||mtt{{t~ult||u||}tsl|dc\\UZ\[[{{ddcztlVZ[ztl}}|z}lriddc}{{tsre}{|||z{ttdc\tts|lldkk]ztlSKJi\V[[T{{ek]||{ttzll{ttj]\|zllutztlllk{tt{|||ztl}zllllkdc\lldultUTS|ub[Usle}sre||{{t|z}{{t{||\[[{u{{|||]cd|{|||{{t{u{{zm}zllred|{{t|tzl{||{{||{ttwllri|||uvutlri{u{{tt{||{||{||ult}|||{tt{zmyle|uzt]bZ|zu{{ult]cdf]c|ultdc\|lekredsrev{||{|||zbVUrfk{{tlld|uldd{ttzllut:97JHF{{t|sle|||||u|ekdlritsl|||tll|VZT{{t||}{||b[U|sre}lekttslri\[[lkssleVZ[{u{{tt{{t||lri{tttllVZ[|||f]c|{||sretsllddsre{{tsre{{td\\{||lldd\\|v||b[Ukd\lddtsllldb[UUMRtllred[TTtsl{||}{||{ttut|ukd\tt{uztldd{tttt{fkkmtt{ttu{{{{ulddtt{{|||utslvrfk{||{u{tts{|||vvv{{{t{{{{t{{ttzlzll||lld}||\[[||ttsMRKztl|lkslks}bVZult}}ut{u{{u{SKJlrifkkred|u|}||utlddJHF:97rg]|z|tzllri}tll}{{t]bZVTL||llktts|d\\tt{d\\\[[yle{tttlllksttslldVTLleku{{edkd\\UTSult{u{slelrilldu||}{ttztlldd|zttsv{lld}j]\jcVkd\VTLtzl~ult{zm|u[TTjcVult{u{{{tdc\}bVUldddc\{{ztl|utslrg]}||}{{tlddztlkd\sle{|||zult||{u{ttslriedkUMRtll{{t{u{}|rfk}{{t}ultiWUzllrg]utztf}|ztl|ukd\|u}u{{ttsmttllk{||ulttsluzt}|zultuztzlllddttsVTL[[Tsref]cJHFultultzll{tttll{u{|z||{{tsledc\|zw{{ddc||tsl{||ztltll|vlddultldduD;9,55|UTS{||lld\[[{u{tll|zuztult|u{ttv{lkslks]cdddc{{tcbV~d\\wlf]c||utzl[[Tmttlld\[bttstt{lrittstsl|ztl|zlldc\{||sleVZTuztlri|tts{tt}|MRKwl{{tsletllkd\tslsle{u{lriwltt{}tlltlllldutb[Uredllk||}{tt{{t}}|ulttzlf]c{{tsled\\|u{u{\[[]cd}tts}{||edk{u{kd\|z}}kk]ttsut[[Tztl|}{u{{{t}|b[Uztl|uek]}~utztf{||{||tllulttt{tsl||usreuu{{lld|JHFdc\tsl[[TUMRMSSUMRultlks{{t{{t{ttldd{||llkuzt{{ttts{ttlld[TTv{ut}lldldd~:97*)(|}ztlu{{|d\\}|u|tts{{tUTSttsredldd{u{llkekdtt{{{tlld{||ttstllv{mttdc\||ekdlrikd\{ttlri|tts}|ztll}tzl}{u{LKRd\\rr]f]cd\\ddcf]cutdc\kk]ztltt{srekd\[TT[TTj]\ultsle}ut}|tslult{{|||uulttsl}{yf|uzluzttllrg]|tsl{u{{ttvdc\{tt{{{u{{{{ttred}ztl|u{u{|u|rfkllk|u|ttsutzllrg]}jcVsrev{red}ztlkd\}VTLtslv{kk]lriedktll{{t{{mttd\\VZT||||[TTJHFf]c{{f]ctslutlri|{||uzt}|u|wlult{||ut}JHF*)(|||mttztl|uut{{tlri{||d\\ldd]bZ}}|z|z|uuztlrillddc\{{tztlrfkkk]|[TT{||tts{||{ttlldllkmw\UZ{zm{u{||v{tslsreztfwlkk]ddcdc\ultzll{ttv{{{tkd\dc\d\\d\\[[Tkd\rfktslVTLuttslb[U{ttulttllztltllut|zlrif]c}{zm}d\\f]clri{|||zlldtt{{{|||}|tts}uztsle}ult}v{}}|zlldc\dc\{||||mtttllv{{tt}|}|kk]slev{utztf}|zsreSKJllk{||kk]ldd|}|z{{lekttslrilddlriv{ttf]clri}|{u{}||~ztl}{{ttts|z{u{{u{}|||}:97*)(}{tt}|}||{||llkkd\{u{tts\[[zl{|||u{{tslerfk{{tdc\}ek]f]c||v{zll{tt{u{[TT{{tllkzll{ttllklribVUultf]cdc\{{tVTL|||lri{zmkk]|lddtll}VTLred}f]c|zsle||tllddc{zmbVUudc\[[T{{t||}ztlttsultttsfkkllk|z\[bttsmttlrittsultutult|u{{tttstll{{tredf]c}|\UZ|ztsldc\{||ult{{tv{ztl}zllb[Utzl}dc\}wl{zm{{tuzt{tttzl{tt}{{tuztu{{}tsl{ttfkk}|{||sle]cdtts|u|z|edkf]cult}}||u||vlddultultredwlJHF)+2}ultv{slelldlek[TTlksv{|}uztu{{{u{}||umtt[TT|zlek{||{||lldultddctslslejV[{{trfklekv{f]c||lddd\\d\\b[Ullkrg]{{tkd\|}|ttstts||slen|u}lddlddtllkd\utrg]f]cztl|u}b[Ullddc\||}{u{llk{||tsl|u{ttddc}{u{ddctt{{{ttt{UTSv{lek|zddcd\\kd\ztl¾ƣ}ult|vuzt}}{||{ttd\\||sresretslv{}{{t||lld|z|ldd}uzt||{u{tts|]bZ|u|z|u\[b\[bbVUkk]|tsllld{u{}|dc\{zmzll\[b*)(zll[[T{tt|uddc{tt||ult{{t|u}edk{||tt{|uztl|zulttzl||ztltts]cd|z|u{{llklddtllmtt|}tts{u{}tllUMRllkttstll{ttmwSKJ[[Td\\cbV|uyle|ulld}ttssle}{u{zllrfkf]ctsl{tt{tt{zm}|||kd\llk||zzlltsl{zm|{tttlltsl|{{t{||{u{lriv{ult{|||||ü{zm{{tf]c||}{{tlri|v{lekf]cwl{|||{{tsre|zddc{{ttsl}llk\[[}ztl}}fkkultllksle|z{||VTL\UZ}lddedkUMRf]c{{tult{||utttslddllk~uzttsl~|z}j]\|tt{f]c*)(tll|umtt{u{}|{zmtslf]c|zlrikd\[TTtt{|ulri}dc\}{tttts{{t|||utt{~{{VTLv{|z|}}utdc\kd\\[[ut||{{t|ulriv|ttsttsllk|zj]\{u{i\Vsre}||VTLylellkztfmwlddtsl{zm|}{u{vutullksre}d\\kk]}ut{ttut{||ekdtsl}|{||{{t{{{u{{{t|tllv{u{ekd}|kk]ttsrfkv{||zlllriut}{{t{u{tsl{{tu{{ddcttsu{||{{t{u{tlllek{{|d\\ult{zmultlkslks{u{rfkdc\}lri{{t}{{tut{tt|llk{zm}||tts{zm{{ttllrfk}{ttsre||{yfztlJHF?;C}tzlulttll[[T\[[ult||tll|||z||lriekdlldu{{ult|ukk][TT{ttkd\ddc|u{{t||tllek]ddcw[[Tllkd\\f]c{u{llkutlrittstllultsle{ttj]\{||ddcsleztl[TTredlddzll||\[[v{{||{{t{ttlldu{{{||lektsl||ztltsl|z|{{ulri|llddc\{tt|ztfult||lks{{t|{u{tllllkdc\|zulttll}ult|lldlritll||kk]uttts{||rg]||}}|||{||}ukk]v|ldd||~]bZult|slellk}|z}{u{|z]bZ}|JHFlksult||tll}{{wlvslettsut{||ttsztl|uztl{{tek]:97*)(tlltslekdult}|ultkd\mtt||u{{kd\{u{lddekd{{lekVTL{{{|||lldtll|z||tslult|ddc||}{{t\UZllk{u{}ultj]\r]g{||||{u{j]\}tsl|v}ult{yftzlutbVUllkzllf]c||uttts\UZ{{tztl|||lld{{tzltts{{tttsut{||d\\ztfzllult||{u{lksllkztl{{t{{tllkv{{{utkd\lld{{ttzl|u{{t{u{dc\ut{{tjcV{u{lekmttuzttzllrimtt\UZmtt{ttztltt{tll|UUYUMR\[bultuzttll}{||lksulttt{lddsretsl||tll{u{utv{}{{t|z||lldVTL74,tt{||v{[[T]bZlekztllri{{ult{||llkultkd\sleut{{t||}{||b[Umttultf]clddttsuztSKJ[TTultultllki\V}{ttj]\||dc\}{{tVTLutSKJtzlb[U{ttSKJ{ttkd\bVU[TT}{ttuztzllkk]tll{||lddbVUutkk]lritts}|z{ttrfk{tt}ttstll{{{ttkd\ultttslldsle}|}u{{tzl}edkv|redut|}{||{zm}}{{t||z|zllk|zddc||{u{u}tt{lri}[TTf]clek{||lld|zmtttt{{{t||tt{{u{redd\\}{u{tslztlulttllut}}{tttzlmtt{zmJHF:97{{t}dc\ztlztlllkdc\|cbVzlultllk{||ult}v||}tt{{tttt{lriztl{||tll|VZT|ztt{fkkllk||[TTJHFf]c\[[lldultf]cf]c\UZllkultlekyfllek}{zm}wlSKJd\\JHF{{t|zsre{{t||red{{t|usre{||}|cbVtllzll{ttztluttllllk||{tttzlVTLtll]bZkd\u|lld{tt|v{}|{|||tt{{ttmttultzll}lddlddddc||tts}u|uredu{{ztl~}||{ttb[Ukd\}kd\|}|{{ttts{{tlritsllriz}tslultztlzll}||{ttztl||z\[[lld{u{uzt{tttll|{zm}|ulttll{zm{{ttllJHF*)(ultcbV|ztts]bZred{ttj]\tsl|kk]ultf]ckd\bVUdc\d\\|z}|}|zll{{t{{llkuztowlkstt{u{{UMRd\\lddv{UMRj]\ultmwtsledkUTS||||tt{tll{{t[[T{ttredztllldlri}tzl{{td\\u|u||u{||ldd{tt[TTd\\FD;rr]{tt{tttlltsllldd\\ztl{{tztltzl{{t|zztlrfk{u{{{ztllddj]\mtt{ttlektt{\[bllk|z|||tll{||{||u}ģf]c{{tf]cldd{tt}tll}cbVddc{u{||ztltts|}|ztl{{tu{{lddlrimtt]cd]cd}edkj]\|uredultuzt}|dc\tlllri||ztt{u{{{{t|||}tsl}|z}|umtt{u{{zmztlddcztlult{ttztl||kd\|uultf]c{{||>EC:97tslSKJ{{tVTLwl}|{u{d\\rg]|z}mtt{{tbVZ{u{sre||{||zll|z{u{uztulttll{{tldd}{tt|zUTSult\[blrilldf]ctllmwtsllekJHFuzt{tt[[T{||kk]utSKJredv{llk|zvd\\tslultedk}||b[Uztl}kjV|utll{{t{ttdc\||{||lldu}}tts{tt{{t}|{|||{||ttslektt{{tt{||}{{tv{tsltsl{tt}{tttts{zm{tt{{t{tt\UZred{u{uzt}{ttbVU{|||]bZultult|zultdc\llkkd\tlledkttsultfkklks\[blekllk{{kk]ekdtts}{||{u{uzt{{tdc\|z{{tztfllk:977-2}llk{u{|{u{tzllld|zlldu{{ttstt{lriult}]bZkd\{tt||tlllld}|z}rfk|z|{||llktt{lksf]c{u{SKJ}{ttlldtll{ttv{|z|zuzt[TT||llkwlrfkVTLsle||slettslldtts|zsle||aWMSKJFD;ztlultu{{[TTslelldkd\|utslttsuzttllb[Utyg{{ztlsrekk]{{tddcsle|ztts}{tttt{{||ddc{||{{tts~}{{tf]cmwwl|uuztbVUlldddctsl{ttsle|uult{||rg]|}lri{||mtt|ztt{ddc{||rfk}ztlzll||ldd|v{uztVTLultSKJtsl[[Ttzl{||{||{tt{{ult|{{t{u{}|||tsl{u{|u{tt|uzt>B9*)(zll|||{{tllklddbVUd\\lddek]UTSlri[[T{{tslult{{td\\}u{{cbVbVZ}sleb[U{||zll{||}tsl{ttu|zuzt||{{\[bJHFJHF\[[f]cd\\\UZb[Ud\\ttsd\\VTL}{zmtsl{|||u{{t|f]c]bZslelddddclld|ztzl|utllaWMsre{{{zmj]\tll||tslztlf]cb[U|z{||}dc\|zllek]tslut{tt|lriv}tlliq]tsld\\{||{{t|z{{}}{{{||}{u{||}{{}}sle~|||u{{t|||z\[[v{}ztl{||tsllldj]\ttstzl{||wl}lld||lldmttlks|lksuzt{{ttts}{{t||lrir]glldmtt|zlddv{tt{{{|~{{t{{tdc\VTLtllVTL]bZJHFJHF|z|]bZSKJd\\ultddcd\\b[U||zlekttssleultuzt{{t{{||zllkldd|ztts{u{ldd}|z|zMRKddcult]bZlddultf]cmtttsl[TTultd\\lddu{{}tllj]\f]c|ukd\{||{u{[TT}|{u{sreztl{zmcbV||tzltzlultkd\{||llkzllutultkd\VTLsle|zdc\||ztlsresrekk]tslutslelddulttlllddllkSKJiq]tsl}{tt{{{||llk{{|z||tts{{tkd\||{||}ult|zuzttsl|{{t|u}ldddc\ldd|utt{tt{tsl||{{t{{|ttsut}sleut{||ekd|ztsl}ztl{u{llk||}v{{{t{||{ttj]\tts}|zttsddcSKJ*)({||dc\lddtllVTLf]c{u{uztttstslu{{lriu{{f]cu{{lld||||dc\b[Ullkuzttzlddcu{{d\\ddcJHFVZTSKJv{tt{[TTlks||tsld\\[TTddc|utts{||red{ttd\\sled\\}\[[zlbVZ}|||||{||v{rg]rfkkd\|kd\{{tslesrelldred|zsletslztl{tt|u}|}{{t|u{tttsl|sle|v{tsl{tttts||{u{ttstt{mttv{llk{tt}ztl}|z}¾ƣ~}{tt{||ttsut{||}}}ult|lri|||zult|dc\{u{}|u{zm{tt}{ttttsu{{j]\uzttslv{}uztbVU||ztl{{t{tt{{tut{ttllk|u{{t|z\[[dc\:97&&UTSd\\d\\u{{ztl|{{t|z|mttsle{{tlldsletts{ttekdekdsrelrif]c{{mttsle{zmzll||lddlektlledkult{{t\[[|f]cttslddtslkd\sleSKJ\[[leklldtts{u{tll{{t}ztlrfkttssleVTLtllsleztf{u{uzt}f]csredc\}sre{u{{zm{||}|lldkd\{tttlld\\sre{{t||ttstll{u{mtt{tt{{{{{tt{{f]c~ttstts}|tsllriǔtsltsl}|ult|u{u{{{t{u{tts}{{llk|||z{{|mtt\[[||mttf]cd\\|z|uttllmtttll|mttztl{ttu{{tts}|lrilektts}|{||{tt{{t|uuztutv{lks{||{{JHF:97*)([[TSKJJHF\[[lri{||tsl{ttlri|z}u{{kd\v|zf]cf]cVTLek]kk]ultd\\VTL}{||f]ctt{edklddedkuztVTLmttldd||kd\lddzlllks|||{||{u{||lddtlld\\u{{|f]c[TTtll|||u{zmj]\zllj]\{{ttll{{tSKJ|z}|ldd}{ttuldd|z{{{tt{{t{{sle{||uzttts{u{||{{{tt{u{tsltslllktt{lek|vtt{v{}||}|{||{{|{ttv{}zllmtt|JHFlldlks{ttsleldddc\}tts{u{lldllk{||tts|zlek{{ult|uztlv{|utzl|vtlluztttsllklld{{tSKJ*)(lkslldVTLUTSsref]ctllbVZtzllldmtt|z{{t||zlld{||\[[}{||tll|zultlld{||mttdc\MSS{{}lriztlsrezllttslddztl{||llkf]cllkultVTLsre{zmzll|f]ctsl{||{u{dc\SKJultlldnf]c{||}v}ult{|||tts{zm{tt{||{tt{tttsl}|kd\sleulttll|{{t}utllkllkttsllk{u{ddc|u|||z{{{u{}|z}]cd|uztkd\{tttsl{tt|lek{tt}tzl|tll}|redUMRtt{UTS}}}|tlllri{u{u{{tt{uzttts|tslv||}kk]|ldd{u{{||JHF3+*||UTSdc\}|ut[TT{||lkstsl|z||z|z}lri{{|z{||||ekdrfkkd\utts||mtt>B9JHFlks|tsl\UZ{{\UZfkkVTLult|ud\\\[[ultek]llkbVUj]\tzlztlslekd\ult}ldd{tt{u{tt{b[USKJiWU{u{{zmVTLrg]sreedk||{tttts}|zlltll||rg]ztl||ztlbVUlddu{{}kd\lldtsltllsle{{t{ttllkedk{ttttslldedk{u{tt{llklks|sre}Ӕ|zu{u{{{v{lrif]cdc\|uwsretts{ttultvtllult|z{{tv{ldd{tt{||{{lkslek|u{{{{t}{{tult|zllktslmtt|llklddlek{{{{t|v{||vkd\redulttsldc\sle}lekJHF{{tlldkd\UMRUTSlksSKJUTS]bZ||lritslkk]tslllk{tt{||||}|ut|zv|z|ztslllkj]\|z{u{tt{\[[|zllduztkk]||tt{lek{u{dc\f]cuzt|ucbVu{{tzlddc|dc\sle|VTLb[Ulri{zmvek]lldsle{||llkd\\JHFttsb[UbVUztl{zmtzl}SKJ]bZfkk|ztll[[Ttslult}|}llkyle|utll||v{ztld\\{||yletlllriwlj]\uztldduztult{{{u{{{lekmttddc{||{||Ĩ|zu{{tsl||tsl}tll}tts{{t||[[T{|||ztll}mtt|fkkv{|ztlllrilddw|{{u{{lrillk{{tlksylelks{{tsl|lksv{{{}ztlztlbVZ}ztld\\}{u{}srelekedkJHF:97llklldj]\lek[[Ttslldd{||lekdc\dc\{ttb[Ulkstsl|u}}|{{sle{u{tts}lld}lddmtt|mtttll{{slef]cJHFlks|b[UJHF{{tD;9u{{|tts{||b[U]bZ[TT||dc\||ttstsllldllkztl{{lekbVZf]c||v{}|||ztfrg]VTLd\\lldllkttsf]cu|z|u}lld|utll}zllrg]j]\{{td\\|zztltt{uztv{lldlldmtt}{u{|mttllk\[[{{|z|{{lks||{{tuzt{u{||ultddcslerfk{u{{tt{{ttzl]bZmttlri{tt{tt\[[mtt{{}tt{fkk{{t}ztluzt{{uedk}{u{lriultn|{{lriut{{fkk|u{tttzl{{tv{{u{tsllddcbVSKJlddf]cJHF*)(\[[[TTSKJdc\}[TT{{tlddSKJtsliq]b[U{{tek]slelldlrittsultlld]bZddcttsf]cttsu{{ultUMR|ulddult}|z{ttyfl{|||utsltt{edkSKJlksuzt{{tJHFtll\[[kk]||lld}{zm{ttddcb[U{||zl{||b[Ud\\VTLf]c\[[b[UUMRj]\|u{tt|uredsre|{||uztkd\kd\}{{t|tsl{u{lritlllld{ttzllyle|tslttslldekd{{yl]cdultuztult{{{||tt{uztlrimtt||ċ}{{{u{{{|}{tt}||}{tt}|zmttddctzl{{ultf]c||UUYldd|rfkmttf]cd\\edk{u{||||lld|umttf]c}ttslri||llk|ttsred{{t}{{t|tll\[[{{tkd\ek]fkkFD;3+*VTLb[Ulrisreldd||[TTJHFd\\\[[||sre{zm|ztlutztlztllldult|uzt{u{uztult||tt{llklektlld\\[TT\[[[[TbVUztlb[Uttsf]cf]c{||}[[TVZT|ztzl|z{tt{u{{zmrg]ztfkd\dc\{{tultlrikk][TTtts|dc\ek]\[[mwiWUzlltsllldldd|lri|tslut}|srekk]kd\ekdv{bVZdc\}tygb[U||redlldlekult|ztts{{t{{t}{{{{]cd{{tt{{|||z{{tt{{{}|{||edkUUY{{tt{ultuztult{||{{tldd}{{tredztltsltts{tt{u{}tslu{{lksmtt}]cdttsut{{|zrfk|utt{{u{lksttstllultttsf]czllri{u{uttts|]cd{u{{{tllkSKJ*)(|zd\\\UZ[[TJHFultddc|zsleut|zv{ultlldzll|zkd\{{tv{}kk]f]czllddcnultulttt{kd\{{f]cult\[b{||\[[llktt{dkV]bZ{u{|zslesleztlekdlri{||[TT{zmslewl}}|{||wl||dc\~wl}n}kk]tsllriv|ztsl}}ztlcbV|zd\\utult}edk{{ttlltslb[Utlltll||mtt{{tuztkk]lld{{tlks{{}{{{{tt{||tll{{t{{mtt|{{}ztl{u{}ttstsl{tt|||z{||ztlultnv{||lri[[T{||{{f]c[[T{{tlritsltt{|u}|z{{||{||{||sle{u{{u{j]\j]\v{{{t}tll|uztuzt{||D;9*)(f]cVTLlriu{{sre{u{ztlVTLttsddc[TTuztlritzluztlriult|z{tt{{t{||d\\llklri|ttsv{{tt||ultult}uztJHF[[Tutlritlldc\tt{]bZkd\tsl{u{redslelddtsl}sle\[[{{tbVU{{tztfrfklddsre~r]g{|||{u{lri|lek[TTb[Utsl[[Tsledc\tllrg]|z|u{tt{u{kd\{zm[TT||ztltt{uztlri}tt{}{{||edk{{{{|}ќ}tzl{{lks{u{}tts{u{llkv{{u{tll{u{tll|{ttultllkttsu{{|{u{lks~edklks{{lksb[Uyle|{ttut|||ztt{|tlltts{{ttslu}}||{tt||tts{||{tttslfkkMRK*)(leksre]bZ{ttlddkd\d\\UTSUMR{{tuztmttdc\{zmvtllldd|SKJu{{|||uukk]\[blksedklddbVU{tt{zm{{{u{{u{tll|tzl|[[TbVUlriFD;ttsredkd\b[Ud\\{zmVTL|[TTllk||{||b[U{tt}|sle||kd\lldn{{tlld{|||}lri|ttsb[Uek]ztlrg]uztf[TTttsvzllkd\llkuztddc|u{tttt{tsl|ttsfkk}{u{{{{{}||}mtt|ttsęttsrfk{u{zll{||wl|zuztlkslri|zttsf]clekekd|z|lkslriultlksdc\tsl|}UUY{{}kd\sleult{{t{{||{u{{{{||f]crfk}|lriztltt{~|ddc}||{u{ttsultddc{ttultsre\[[||JHF*)(llklldkd\llduddcd\\UTS{u{ddcttszllddc{zmtll{||tts|u}lkssretsllrij]\j]\{||lek}}{||[[Tf]c|zzllkd\ttstsllri>EC|z{u{uztztl}{{t{{tslebVZu{{ldd{{tlld|zlriVTLVTLultkd\||j]\||]cdv{VTLdc\dc\tzl{ttuztyle{{tllkut||}llktsltllztl{{tek]sle|ut}ldd|lld}{||mtt{{{{lks|tt{{||{{|}}|zttslksnvmtt|z{{}|}mttztlult{u{|||{{t||llkddctts|v{lks{u{{{t{u{{{ultlksUMR|lri|z]bZUMRd\\b[Ullk|z{zm}ldd}|{ttsrev{||llkd\\{ttsre|}{{kd\ldd|||v}|ddc\[[d\\[TT\UZ[[T}74,74,lddVTLb[Uuztdc\ddc{u{u{{dc\d\\tsl]bZddcredlritllsle|ekd|leklekultu{{b[Utlllri{{tt{SKJUTS{u{{tttsllldtt{ylttsztltll|kk]\[[ddc}}ulttts}|zj]\|uztlu{{tll|ttsd\\fkk{ttult{|||{zm|lksdc\}|ztf{u{ttsutult[TTek]||ztl{ttkd\ztl{tt{zm|uultldduzt{{|{{tuztllkultf]c|nvfkk{||{{u{{|||}tts||{{mttdc\{{|{ttultzlltllllkttsu{{ekd}tzl}lldttsf]crfk\UZd\\\UZ|ztsluzt]cd|lks[[T{u{|uzt{tttts{||{tt}{u{bVU|v{|||uult}|zult{||}kd\|u|lrif]c|tt{JHF3+*bVZllkj]\tll]cdlld]cdult{{tUTS[[TlriVTL|ulksd\\j]\ttslddlddlddutd\\uztttsedklek{u{|v{|{{tslellkVZTlri|zzlddcttstll|u{{sreb[U{tt}sled\\tts{ttldd\[bldd{zmtt{vtzlf]cdc\lri|ukk]{yfd\\llkf]c{{t}tlltll{u{utj]\zll|sle{{tv{{{tsl{{|||z||lks{||red}{ttultă|lddtt{sleuzt|fkk}}lld{||{{{u{MSSf]cUTSf]cmtt{{|u{{edkedktsl||}}wl{||ult}bVU[[T}tts]bZ}|{||v{{tttsl{tt[[Ttsl}|slev||ultuztuzt|tllUUYddc\[[:97&&red{zmJHFVTLMRKu\[[[TTVTLJHFVTLtslsle[TTllddc\i\Vtslttslri\[bddc||ult{tt|||}{{lksSKJedk{{}lldsle]cdbVZUTSVTLdkVfkkFD;aWM]bZVTLSKJ||uztlrilddldd}tts{ttddctll||redf]c}zlld\\tzl{ttuztdkVVTL}JHFredf]cult{||tll{u{lek{tt{|||utll||ldd|z}ttsut{ttf]c|u{|||z}||v{}lks{u{|tt{}{||{{v{ult|rfk}|u{||{{}{tt{{||zd\\{{]bZ}lld}|{{JHFulttt{tzl{||{tt||lldldd||||zsre|{yff]c|}{{lriVTLek]}llkcbVldd[[Ttlledk\[buztztl[TTUTSedk:97&&\[[SKJVTLzlVZTek]FD;ultd\\|zlldsreslekd\jcV|llklld\[[}uzt{tttsl{||tllf]ctlllldut\[[ultSKJ{{{zm[[TVZTlddJHFu{{lddVTLtlllldd\\tsltslv{ztllrillkttsj]\lriUTSb[Uldd}ldd}ultzllf]ckd\lritzluztwllddtts|utreddc\uttts{{||}wl{{t{{tddctlllri}redddc{{tztltsluzt|u{{}{{{{u{{{{{{{{edk~|||tt{lrimttekd{u{rfklks\[buztu{{f]c[TT}ult{|||zttsult}|zb[Utts{||{tt}}|u|zldd\[[|u]bZkk]sle}ldd{||{{t{tt||ztlllek{||JHFJHF3+*edkek]lldb[Udc\lld\UZVTLVTL[TTlddlld{{ttllldd|}yle{||{{t|{u{{u{{{fkkr]Z{{s_qrfklekllduztv{uldd|MRK]bZVZ[llklldutekdddcztl]bZUMRztfdc\}JHF\[[f]c|}{||j]\tllkd\d\\||{ttttslks|}}|lldllkultlddlld{ttv{rg]{tt{ttlldf]c{{ttllllklddred|{{tu{{mtt{{lks{{{||lrisreu{{||z|zulttts}}}u{{ztl{{tttsj]\uzt|ubVZmttVZ[|ztts{{|uf]ctllekdUTSlks~[[T{{tlks{{ttll|lddtt{}ultedktt{{{t|u||{||lldlksultb[Ulld{{t[[Trfkult|lldekd[TTtslddcFD;*)(ultddcSKJD;9JHFcbVf]cSKJ[TTldd\[[tsl[[Trfk}|lld{zmuzt{{tlri{tt\[[{{f]c{||}ult}bVZbVU{{tult]bZultldd[[Tlddlld[TT|ub[Ulld|u{ttek]ddcddcVTLSKJFD;kk]ult{{tddcuztVTLtllbVZ{||[TTtsllddlritll}|{{t||bVUttsredredzll{{t|z{{tztl||zutkd\ztledk|zllduzt|{{}}}|{{{{|f]ctt{ult{||mtt~{{}|}||{tt{{d\\{||f]cv{r]g{{wl{|||z]cd|z|z{{|z{||f]ctsl||lld~||{{lld||}||tsllddrfk}ldd{u{|tt{||lri}{||{||d\\kd\tsl\UZlddultu{{uzt|z}|f]cVZT\UZUMRlddVTLFD;FD;[[Tut[TTfkk}[TT[[Tlek[[TztfVTLcbVdc\tslfkk|zmttek]||tzl{{tttstt{ddc}VTL\UZ|lriedkdc\|zztlttstllekdSKJttskk]|uztlldSKJ|utsltlld\\f]ckjV|SKJb[Uztluztulttsl|zsle{tt}lks[[Tkd\red|kk]u{{lddllk{{sledc\f]c}ulttllztl||llk{||{{}mtt}|{{nv}ult{{}|{{}|||tzl||zult||lks{tt{||ow|{ttsle|ultredekd|z]cd|mtttslmttedkuztcbV\[[|||f]c}|v{[TT{{tll}{{d\\}}{{t{||ddcddcrfktsluztddcultllkdc\|uUMR}tsl{||tsld\\ttsddcu{{{u{{ttlekVZTddcD;9*)(dc\VTLFD;D;9ek]kk]bVUult{{tlksd\\lrilriVTLlks|uj]\cbVlldVZTuztMRKu{{{ttlriu{{u{ttmtttts|mttf]ctslult}|ulttts]bZ{ttultztl{{tztl]bZ{zmlri\UZ}{u{}|d\\uzt}|}|sre}f]cv{{tlddSKJddcvek]VTL[TTdc\llkddc\[b||tsllldredUTSlldkd\redVTL{||[[TFD;llklddtsltsl{{f]cfkktsl||llkultlrifkkmtt||{{mk}|{{lks{tt||zlri|{u{}{{t||z]cdlks}{ttlek{{{u{mtt{||VTL|z]bZtslultdc\|v{{ult{u{||tsllek}{u{{tt}{u{slev{f]c{{t}||lriztledk{{|sle{u{d\\{||mtttslultdc\|z{{kd\ldd\[[tt{\[[SKJ&&j]\}f]cVTLJHF]bZzlltll]bZllklldtzlsleuztultVTLtll]bZ[[Tu{{tzlllk|z|z{{td\\{||ekdlld{{f]cedklldbVUlddult[[Ttt{SKJ{ttlddu{{lriUTSdc\rfk|tsl{{ttslzll|z||{ttttslldddcMRKf]clkstslekd|{{ldddc\{u{FD;Q?@ult}dc\||z{{t~mttlldult}|z{zmf]cuzt}{||UTSylerfk{ttdc\sle{||VTLtzlbVUlddllkdc\ldd||ztfllkldd}u{{mtttt{uztnvedklkstt{lks}}|u{{||{{u{{ultyltts\[[lkstslllklri{{{||{{ldd|zlks}mttlrirfk\UZd\\\[b{{tslmttlkslks{tt{tt|}||{||{{ultult{{|z|z{{t{{|||z||{||}{{tddc{tt{{kd\lri|lld{ttttsztlfkk]cdllkbVU-1+ldd{{tF=CsletllSKJ{zmzllldd\UZslelldddcd\\r]Z}}|JHF{zmfkku{{}lriuzt}|tt{kd\{||VZTlksllk[TT|uzt}lddtlllriUUYVZTVZTUTS{{tslettskd\VTLkd\tsl[[T\UZ|vkd\|{{tsle||SKJf]csre{tt{{ult|rg]}lddtslbVUlriv{d\\UTSslekk]||{{t}|{ttttsek]{||ztlttslddjV[\[[\UZ{ttult|{{{||fkk{{nv{||u{{{{}{{{{yl{{tts~tzllldlrimtttllztl}zll|{{bVZ|{tt{{[[Ttll|z[[Ttts|z]cduzt{{t{{UMR|d\\{zm}|sleldd}{u{{u{}|zddc{||{{ult|zkd\red}|tzlsle[[T|z]bZb[U[TT\[[UTSf]cFD;*)(f]c|uSKJ]bZlddJHFddclldddc\[[~tzlekd{||ulttzlu{{llklldtt{ekdlkszlltt{uztu}|tsltllVTL{ttztluztVTLlri|{tt]bZJHFb[U]cd]bZmtt{tt{zm[[Tlld{u{sreult{||]bZttslld[TTcbVVTLb[U[TT{zmi\VbVZtll}sletlledkUMRek]kk]VTLlddUTSutultkd\{||cbV{tt|ztllbVZuzttsl{|||lldvtsllksbVZ{||ulttll{{ultmttfkk{{lksmtt|~ekd}||{{{{ldd{{}|zztl{u{{||{{utf]clriUUYmttUTSdc\]cdtts{{ekdleklekttstzlwl~lks|{{tsl{{~u{{}}||u{||tt{fkk}|ultlri{{t|u}}||ztltslVTL{ttultfkkUTSMRK*)({tti\Vkd\FD;bVUPF=dc\UMRdc\sle}tsl{u{ttstlljcV|utyg|u{{d\\mttekd}}|}uzt||zb[Uddctll}}\[[{zmj]\[TTtllttsu{{lrillktllztld\\v{|ztlVTLttstzl{{{||[[Tb[U{{t}\[[VTLJHFlddiq]d\\VTLlld]bZSKJJHF||||f]c}}ddcd\\tll|ulld{u{|mtttsl{||mtt|mwtts[TTtll|z|ddcMSSleklks|}|{{{{nv{u{{{}|zNjlks\[b{tt]bZult{{t}ttsult{||{{{{tJHF\[[LKRMRKVTL\[bJHFu{{u{{red~|zttsv||ttstt{ult}||ekdddcedkldd{zmmttultdc\|llk{{sledc\{tt]bZ]bZVZTb[U*)(f]ckk]}|FD;UMR{tt[[TVTLSKJVTLj]\VTL{u{||tlllldkk]ztltslmtt\UZ{u{{{{||{{tutekdbVZUMR{u{{|||ulek{{uzt{{tekdJHFUMRldd|z|vf]c{||ztl{ttVZ[~{{ttll{tt[[Tkd\}FD;VZTd\\lddb[UtlllldlddJHFultekdudc\tsl||dc\{{tkk]{tt|ultredtt{|ztsl{{tzllLKRmtt}bVU{{lriuztmtt{{tt{}|{||{{|{{|Ѩ{{|}|zfkkf]clkszllvÚlldred|||lld|{tt{u{{||uzt|z{tttt{JHF~}zlluztlriVZTlrillk}|llk{u{|uztl}ult|}f]clld}{{ldd|llkttsekdvtll||{ttleksletll||JHF{||zllkd\JHFUTSlekutfkk\[[ddc}JHFSKJbVZkk]b[UPF=3+*FD;[TTD;9JHFlddtsldc\{ttdc\ut{u{{||||ttslddddcult[TT|è~iq]tllb[UddcUUYf]c{tt|zddc{u{dc\v{tslultrg]|zekd[TTlks{||lek||b[U[[TUTS{ttrfksreslej]\ttsUUYuzttllVTLleksreutwl\[b|ddcultlld||\[[{{{{t{{tlksredult{||tllmttrg]ttstt{{u{ult{u{{{u{{{{ǔtzlu{{ylMSSuzt{{t}}}tts||z\[bu{{{{t|[TTmtt\[[{{UTSult|zlddllk{{llk|uv{ttstt{ultztlv{|\UZ}rfkldd||llkmtt}mttu{{ulttts|v{{zllSKJd\\lriu{{ek]|zsleztl[TTVZTllk:97*)(u{{SKJJHFSKJ3+*SKJD;9F=Cf]crfkVTL|{tt~ddcsrejcVlldlldedk[TTmttulriek]lri|ztl{tt}|u{{[TTd\\VTL{{tultu{{u{{ttsfkkUMRb[Ulld{tt\UZ}VTLv{ult||redlksi\V[[Ttyglddult|uuf]c|ztlltslVZ[tzl[[T{u{ult|u|tts{{t{u{VTLlri{u{ddcultkd\u{{mtt{{||{{|{{t}~|\[[tt{{||}|ddc}}}UTSVTLb[Ulriuzttt{lri[TTultultult{{tlllrilks|zlksutf]c{{ult}tts{||{tt~||v{tzllkssreUTSddcnVZ[lks||ldd|||uzt{{{u{}{||sle[TT\[b]bZsletslVTLekdztlu[TTu{{llkUMR*)(\[[rg]bVUVTLVTLkd\tts|rfk~tzl|||[TTtt{kd\VTL{{tsl|uf]c[[T{{ttsmttek]{{tuztlriVTLlekttsslettsuztkk]r]Z}|kd\f]cJHFddcfkkf]cUMR{u{lldult[TT[TTrfk{{td\\|ultlks|u|tlllldkd\{u{|zuttslb[Uddctsluzt|u}v{{tlltts{||ttsutzll}{{ldd{u{}llk|u|}{{{{}|mtt}|ddcttsult|z|lkslks{{uuzttllmtt\[bmttmtttt{ultlks[TTuztVTLddcfkk{tt~lddyl{{ttslri{{|ztlult|z}|{{t{u{{u{tts{||lritt{ddcu{{\UZtsl{tt}ult}}{tt{{tt{llk{||ddcf]crfk||}|tslbVUf]c|u\UZ{zm|tts[[Ttsld\\|{||MRK:97{ttdc\D;9SKJVTLVTLf]c\UZbVZv{uzt{||slekd\ekdlkstzl}uztlrifkk||tts||\[[ekdtll\[[\[[mttv{ttVTLdc\rfklddtll{u{|tts|UTS{{tv{tllbVUVTL\[bttsult\[bllk}{{ttllddc|UTS|zVTL|zultrfkult}i\V|{{ttt{utlriztllriu{{lddlj|{||{tt{u{}}ldd}{{t}|uttskd\tts}tts|zlks{{|z|edklri||}||æ}lriultttsd\\{||f]c|tt{}u{{lks|mttlld[TTekd|||{{{{tekdek]ddckd\ult{u{ttsldd|tlllek|zuzt|sre{u{[TTtslultult{{t|||z}tt{lksmtt{{{{llk{{ttstsl{{t}rfkVTLtllVTL]bZ{||||tllf]c[[TddcMSS*)(tslb[U[[TaWMJHFSKJuztVTL[TTultddcdc\{zmlldcbVUTScbV}|\UZ{ttult}u{{tll|ttsztl{{tdc\tt{{tt{{tekd\[[srekd\||v{u{r]g|zddclkslldyld\\ttstlltll[[T[[T}|{ttlri|zVTLrfktllsreldd{ttUTSkd\UTS]bZu{{uzttlllld{{sle\[[|uztf]c|ttsddclek|{u{ttsttskd\edklld{||{{\[b|{{tt{{{{{lks}\UZ]cdldd|z|tt{||lriedk\UZttsttsmtt]bZlri|u{{\[[|zkd\lddu||SKJtt{u{{ultulttt{|{|||ult]bZ}UUY]cdldd{{{{t|zlek{{|lks|zuztulttt{tts}ut||dc\|urfkv{{||{tt|z]bZUTSsle[TTllkUTStt{LKRD;9lldkd\[TTVTLPF=VTLVTLf]cultf]cddc{{tdc\{u{kd\lrilldtslkd\VZTred{u{uztu{{|lddldd{tt]bZMSSlddkd\|{u{lks|zdc\}ldd}}lriUUY|z{{:97lksult|zult{{td\\mtt{{tllkrfk[[Tdc\}|}|{||u{{tsle||lek||}tll{{t|z|u{{tlld|zuztldd}lks|]bZUTS{u{{||tts{||mtt\[b||Ù|~|{u{{{||u{{ekd|tllmttd\\lksrfk}{{rfku{{llkekdlddztltt{ekd{{t}|tll|z|zmttrfk||fkk{||ddcultultrfk{{}{{}[[T{u{u{||edktzlult{tt|{{tts{{u{{|lld}|{{tddc|uJHFJHFlddttsult{{tlritsl[TTllkdc\ddcFD;:97UTS]bZd\\VTLSKJrg]lriyle{{tekdlrilldkk]]bZedktsluzt{||edk}{u{|{tttsl|lld{tt|mtt{{t{||[[Ttts\[[|z{{\[[ekdUTSf]cUTS|v[[Tlks{ttlks[[T}SKJr]gSKJUMRkd\}b[UultekdllkaWM}||{{}{u{zlluzt}|zlddtsllddlek||{ttuzt||uztllktt{|z{{{{tmtt|lks|Ī{{{{{{tts{{~ċ\[[tllf]cekd||}u{{tt{{u{{{tts{u{lrittstt{mtt{{mttlekrfku{{\[[|ztldc\lldkd\|lldu{{d\\||ult{{tllF=C}}z~}{tt|}{{llk|zuzt{u{|mtt|}llk{{|rg]VTLFD;[TTUTSekdlddztlllkllkdc\[[TUMRztlUTS:97:97sreb[UlddSKJsreD;9lddSKJldd{||lldsrezllf]csleutuultlld{tt||]bZlri||tsl|ut[[T[[T[[Ttsltsl{{tldd}ttstts~uzt|MSS\[[[TT]bZ[TTi\V|{u{{{t||{ttsrej]\leklddcbVrg]{{t{tttlltyg|uttslldmttdc\UTSf]cut|z{tt|u{||{||ddcultedk{{|zlks|}|||^fsх{{{{{{|ult}tsllksu{{mttmttlksddc{||}mttlkslrimtt}|lritsllri|{{tsre{{tredlld]bZ\[bUMR{{{{redv{}{u{||uzttsl|]bZ||tlltt{mttv{uzt}lksmttuztekdllktlltzlek][[Tlldslettsv{|ddcekdtslztlultdc\,55||FD;74,{{tlrif]c{zmlriFD;\[[VTL{|||zsle|zttsjV[tslrg]tslslej]\sle||lekllk{{ttzlllddc\|{||ek]b[U{ttlrivlri\[[ekduzt|utt{{{lri|kd\UTS\UZdc\[TTlldbVU{{t\[[lldVZTultyle}cbVkk]lri{zmzll[TTsreztlf]c]bZ|UTSlri]bZztl{||tsl||d\\{ttmtt{u{tt{}]cdtts{{lks||}{tt}|}{{|}}{{|zultmttttsuzt}edk|zmttUTS\[b]bZdc\tsl{{nv]cdd\\\[[|z{u{tllj]\|ldddc\|mtt|z}v{lks}v{{wltt{ylv{}ut}llktllulttt{~tzl}|}nvddcmttlksd\\lrilddd\\ekd{tt{{tddc{||}{tttzltts{zmj]\\UZUTSUTSJHF74,lridkVSKJVTLJHFbVZVTLbVUtllu{{d\\srelksztlkk]tslztlddclri{tt||ztlfkk{||tzl}]bZmtt{u{llk|zFD;MSSlrilri]bZ{{tlllkslddllkddctll\[bultuzt\[b}tsl}lks]bZUMR||b[Uultrg]LKR{ttkk]UTSlddVTL[TTUMRlriu{u{lld{||{tt|kd\tzl\[bek]tt{{{u{{|mttÙ}}{{|zulttt{tt{UTSultlksu{{}|lksekd]bZ]bZtsl}|mk\[b\[[kk]|zultztltlllri|zddcultttsek]]cdMRK}UMRv{~{{ultv{llk|zmttmttf]c|ek]\[bultllktts|{{}{{lksVZTJHF{ttultUTSu{{tlllld{{tedk||sletsl{||kk]SKJSKJaWM|ekd*)(kd\kk]bVUVTL:97D;9\UZbVUllk]bZtsl}f]ckd\mttcbVldd\[[ztlztllldmttcbV|dc\b[Ulld|]bZ]cdekdJHFu{{MRKVZ[llkkd\edk{||{{|lddldd{{lks|zllktslztlutUMRjcVj]\lddbVZ{|||z|uf]crfkrg]\[[ldddc\{||mtt|z{{t[TT\[[\[btsltts|||{||lek|redlldmttu{{uzt{u{{{lkstsl}{{u{{{{fkkmttu{{|mttmtt}~{||~~{u{|nv{u{|{|||u{{|ttsult{u{mtt}|mttfkk|mtt|z|ultmttleklldllk{||VTL}UTS[TTlldVTL{||utJHFtllJHFtslkd\lkstslu}JHFleksle}ttsuztlri\[blksu{{tsl\[b}f]c||~tt{{|||tts{tt{||mtt|uztlldf]clrilld{{tztl]cd\[[redVTL[[T|zrg]FD;[[Tdc\SKJ:97*)(UTSVTLaWMVTLSKJJHFf]ckk]llkSKJlrikd\zllrfkd\\lrilriVTL}yle|ubVUmtt{zm{{tkd\tts{{t{tt||z||lddlrilksekdmtttzlult||{{lrimtt}tt{|zredrg]lrifkk{{tlddsle|utsllri}|}|D;9||lldulttt{[[Tlddttslrid\\b[UJHFd\\lldtt{{ttuztkd\{{f]ctsl{{t{u{{ttult{{mtt||{{tt{]bZ]cd{{mttmttmtt{{nvmtt{{|lks{{}lrif]c{u{[TTedklekuztlks]bZlrimttmttmtt~u{{mtt{{{u{||ztllkk]lddb[U||{{tultlekdc\MRKllkrfkf]cf]cUMRtll{{||ultuzt||}mttlksVTL\[[u{{tslultttsult{{{{edk}mttVZ[tts{{uzt\[[tlltsl\[btts[TTztlVZTkd\VTLb[UyleUTS[TTJHF>ECSKJVTLJHF74,[TTrfk}b[U}f]cllklld{||UMR\[[VZTi\V]bZlriekdVTL|ztll|zfkktzlfkk[[Trg]ekd{{tll||{u{g\rUTSedkkd\u{{mttmttSKJult|z{u{ddcd\\{u{lddsleldd|z]cdred|cbVd\\f]c|zmttd\\\[[utttsu{{uztuztttsult|z{{t|||lri}mtt|zlkskd\{{Å|{{lks|}{{{{uzttsl|llktt{|z[[Tmttu{{|||u{{lek|lkslrimttu{{lld|z}lrib[Uekdr]g\[[VTLf]c}{||f]cmttult|{u{f]c||tyg{tt}lekrfk{tt}|z|z{||llkllk{u{tts{{{{lksttstll}uzt{{\[[d\\ek]d\\edkllklddtsllri[[TVTLb[Uultlddu{{UMR*)(aWMVTLd\\VTL[[TD;9[TTb[U{u{]bZ{{tttsztlSKJlld||tsltsluztddc|u{zmekdkd\ddc\[[lldttstygb[U}sle\[[|zlri|uzt]cdlri{{|z]bZf]c{{lrimttb[Ud\\\[[||lldlld{{lldtslsleekd|zldddc\tslj]\VTLv{u{{MRKVZT|uztsre}|z|z{||||{{ttsl|{{ultmttVZTtt{{{|}}}}~|lri|z}ultult|{{lldu{{uzttsl}|nv{{mtt{u{ttsekd}lddddckd\uzt{{SKJttsUMRdc\D;9{ttMRKsle{{}{{tll{{t}lrid\\kd\{tt|}}{{t{u{}|u{{mttu{{tlllks|{{f]c{||{tt{{{{lrilkstsl{ttlld{{tmttultkd\rfk{{]bZkk]tllVTLUTS]bZ]bZ:97}VTLtzli\VJHFi\VUMRVTL\[[\[[mttnv|uzttll}|bVUultlld]bZedk|sre{ttkd\bVUf]c}|z[TTtll[[Tllkd\\||}u{{edkVTL\[b\[bVTLdc\{||||ztlttsred]bZek]cbVllk]cdedkd\\lld]bZkk]tslUTS[[Tedk{||lriddcu{{mttsrei\V{||uzt{||{{{{UTS||||ttstt{tt{}tll|u{{}{{Ümtt]cd|~{||lri]cdu{{]cd~|u{{mtt}mtt{u{cbV]cdf]cSKJttstllztlddcttsekdlrilksSKJ]cd|[TTlriddc[[T{u{lksylttszll{|||ztsl{{{{|{tt}tt{lri|]bZmtttt{tllddcuztbVU\[[tsl|zsrecbVyfdlddred[[TJHF*)(kd\VTLek]VTLMRKD;9{{t[TTlddJHFVTL\[[tt{{u{{||zll}ekd|tts}tsllekkd\VZT\[[{ttSKJ{{tzll|u|ztsltlluzt{tt}u||\[bcbVnfkkbVZSKJzlttstllkd\}VTL|zlek[TTtsld\\]bZult[TTUMRultrfklri]bZUMR|lriVZT{tt{{|z|ztslult||[[Tfkkuzt}tts{||{{mtt{{nv|{{u{{f]c{u{}uztedk]cd|zVZ[mtt]cdddcuztfkklkslksUTSSKJtsl{{t]cd{{tuzt|ztts||fkktt{lrif]ctts[TT[[TVTL{u{ttsmtttzl{tt||}{u{{u{{||u{{{{lkslksttsf]c]cdlks|\[b|ttstsl{tt|tll{||uztlld|z[[TVTLJHFlld[[T]bZultUTS*)(dc\[[TJHFaWMD;9D;9jV[FD;JHF\[[b[Uf]cultd\\lek}tt{ultiq][[T}zl|ek]u{{}uttzl|}rg]j]\}zlllddek]mtt{{tttslri{u{|tll{{||lldMRKSKJF=C{{trfkr]ZtllbVU]bZekdsle{tttlluekdtlltllv{ult{u{\[[ultfkk>B9tll|cbVekdu{{||{{|ttszlllddmtttslttstt{{{ttts|{ttmttlriuzt|\[b}}{{~u{{lkskd\f]c|z|mttVZTnv|llku{{ult}f]c{|||zllk|z{{t]bZsle||dc\||\[[{tt\[b[TT}tzl|VTLek]JHF{u{{{{ttuzttsl}~tll|ztl|]bZ{|||u{{{{{ttu{{mtt]cd{{||b[Uekd{ttfkkZbN|z\UZekdSKJVTLldd[[Tdc\VTL:97*)(slejcVD;93+*JHF74,JHF[TTult}|ulldttsult||ult[[TttsUTS[[Tek]ddc{{|z|uultultultlksuzt\UZlritslek]{u{tsllri]cd?;C{tt[[Tsle{tt|ulriJHFddcdc\ddcd\\tlluVTL[TTttsd\\ultttsb[Uult[TTUMR[TTlri{||ttsekdfkk}|}}tllllkēmttuztztl{|||zu{{tslmtt{{|}|}}ã|vlks]cduztmttu{{{{tts|fkkmtt|{{edk]bZlks}|}rfk{{ttsl]bZ[[TUTS~u{{|uekd[[Tdc\u{{VZ[lrilekuztuzttsllrilriultd\\|tt{mwtslVTL{{{||}tslllklriult{{}tt{lks]bZ{{{u{{||f]cdc\SKJtsl|llk[TT[[TztlVTLsrett{d\\JHF*)(j]\cbVJHFSKJF=CF=C[[T[[TbVU}{{t||{u{tlllekllktll{zmdc\kd\{{t{{tlri]bZwl}||red|}sleSKJlektll~}\[bultleklritsld\\{ttddcv{mtttllb[Ud\\kd\b[UbVZdc\lddF=Cf]clekmttf]cmttttsu{{lri}|lldtsl{u{fkkuztf]c|{ttlld{{|{{}}|tt{{{tÜlkslek~mttlddmttUTS|mtt|ztt{{||{{lks{{ttllkk]uztVZTddclekbVZtslkd\lksVTL]bZtlluzt[TTtll]bZekdu{{{{{{|zlri{{{u{lld{u{v{ekd{{tzll||}|{{tts}f]cmttf]clri{{mtt]bZedkmtttt{dc\]cdu{{ttsllk{tt|zztl]cdlek[[T{{trg]VTL[[TSKJldd\[[*)(sleJHFbVZJHFJHFVTLVTLkd\[TT{{t||ttsrfk{{{{ttslllklrillkttsu{{f]c}}{{tek]lksfkk}ttstzld\\uzt]cdultttsd\\UUY|||zddcdc\UMRdc\mttrg]leklddlri{ttjcV[TTj]\ek][TT{tt}|llk{ttv{}|ztt{\[[]cd\[[||{||{||tsl|ztt{{||ekd}|zsle|ekd]bZ|zdc\}||{{{{{||{{|ultČlks]cdlksmttlri\[bmttmttult{{t{{{{t}tts{{t]bZ[[T|zuztllkf]c{{]bZek]tsl\[[JHFmttmtt|{||ddcztl[[T\[[}lld{{tllduzt}lkslld\[[tsl}uzt|{{lks{||VZ[{{||leklddlri{{[[T{{tsl{{t]bZ|{u{{zmedkddc[[Tdc\VTLztl\UZlddLKR*)(ztf{{t{ttUMRVTLj]\|zrg]v{f]ckd\tts{u{fkkv{tt{slekd\dc\ttsuztlks{u{tt{{||{tt\UZ|uf]ckk]{{t{{\[buzttslmttlkstsl{||SKJ\[[[TT|[[Tdc\tllkd\lkskd\uttzl|u{zmtsld\\kk]lld{{ultf]c||ult]cdlkslks{||lek}uċekd{||ult{{|ztts{||{||{ttlks}||}|{{|{u{\[bѣř{||u{{|mtt\[[tts}|mtt]cdfkkddc|ultlriv{||d\\[TTkd\kd\fkksre\UZJHFmtttts{{VTLb[Uutmtt\[b\[b|{||u{{|[[Tlld}}{{|u{tt{u{|{tt{ttmttunvmttmtttslvultmtttt{||uztu{{ultmttUUYult{{t{||]bZsle\[[UTS[[Tllkdc\VTLVTLVTLd\\jV[SKJ\[b74,red]bZlddekd[TTSKJ]bZSKJf]cb[Utslddcztl{{rfkvultdc\kk]{{tkk]dc\ult{{t|ud\\}[TTtzllri[[Tekdtsltlltts|z|zfkk}u{{{||uzt]cdJHFlksdc\[[TtllSKJtsl|zmtttllVTLsretll|{zmf]cllk{{t{ttUTSztl{ttllkf]ctllf]cSKJJHFultu{{JHFtt{}{tt{u{mttvdc\leklldkk]{||edk{{t||ult{{mtttts|ztt{uzt{{mk{{{{}lekd\\|}f]clks|z|z{{tfkkVZ[|{{^fs]cdmtt\[bult{{f]c||tslddcJHF|uutf]cult\[[lkstt{{ttultnv\[[]bZekd]bZJHFddcultkk]|{||tll||tslult\[[|SKJf]c|{||tslmttlks{{mtttslultyl\UZtsluztultuzt||ddcd\\kd\UTStslVTL[TTlld]bZrg]d\\LKR*)(bVUVTL74,JHFJHFf]clldUMR{tt|z|uztb[U}{u{ztl{{tkk]b[U[[T{{tdc\v{ut{{{tt{{tlricbV|zlek||tts{tttslult{u{{u{tts|zmttUTS\[bUMRd\\ekdVTL[[TbVZult{{srered[TTbVUf]cSKJsletsl{zmu{{}[TTSKJ||bVZlddllk{u{SKJf]clkstt{MSS{u{||uddclkstslult{{t{||{{{{\[btt{{{mtt}}lksmk~tts{{t}ttsu{{|tsl]cdu{{{ttlks]cdUTS}nvmttVZ[\[b\[b|}\[[|}|{{{u{MRK{{f]cllkkd\{{lkslksmtt|z^fs\[[mttu{{{{t|zVTLtsltslVTLfkk{{ultuj]\u{{|f]cultLKR}lddtts}lekuzt{u{|lksmttlri|lriuztlekultd\\dc\UMRek]sle[TT]bZSKJ\[b[TTMSS-1+VTL[TTPF=UTSddc\[[lldutred|z|z||u{{{ttbVZlek{zmj]\VTLmttdc\tzl|{||lek}{{t{{t\[[}UMR}tt{|z{{fkk{{|zwlVTLtsl[TTlksvSKJ|zddc{||}lddj]\tts|vJHF[TT|urfk{{tultslettstll{ttMSSf]cult\[bldd{ttultf]clek|z{||||}lld|uzt{||mttedk|z|{{mttuztllkult||zf]cf]c{{}mtt]cd\[[ldd|mtt{{VZ[lks{{lksmtt{{lek\[blks{u{{ttSKJ{u{tll{u{VZ[tt{llkddclddrfk|{{tt{edk|mtt]cd]cdlld{||{ttult{{]cd{{t{ttu{{u{{|z[TTtt{{{|u{{ekd{{t{||tllfkk{u{VZT|{||ddc|ultldd{tt|zekdddcUMRztlfkkSKJVTLdc\D;9JHFlldVTLlddJHF,55sled\\:97JHFredbVUlri{u{tllUTSVTLlriultf]cultult]bZ{{tsl]bZ|uf]clekultdc\llkVTLVZTlek{{UTSd\\{||tt{}ult{{tJHFf]cult{ttsleztlrfkredrr]sletts{||{{rfk{zm\UZJHFddc{{\UZLKR}{u{ldd|zmtt||lksut|u{||{tt[[Tmkuztlks{{Č}~mtt{{t{{t{{}]cd{||{{ult{{{{ttstt{{||]cdtts]cd|znmttlkslksultu{{}}}uztg\r}edk||f]c|{{|lks\[blksnv|z{{}|tlltsltslulttt{}mtt~mttfkk}ttsfkkttsu{{{{{{\[[mttmttUMRllk}mttuztUTSfkkUTSSKJ|ztsl[TTSKJ[[Trg]aWMlrilddcbVultLKR,55wl[TT\UZddcJHFtll[[Tultllk]bZtzl{ttult[TTtsl||SKJmtt|zttsek]lddllkd\\{||d\\mttJHFVZTbVZlksmtt|}}{{u{{lks{ttsle[[TUMR?;Cf]cSKJ}lekttstt{f]c|UMRkk]ztl}|VTLuztf]c||VTLlddldd[[Tekdd\\mttlks\[b{|||lksldd{{tts}|zu{{{{||||}tll}||tll{{{{љu{{b[Ulld{{||ult~|z|mttlkslddmtt|{{nv]cd|\[b|zlek\UZlkslek~}}lks}lks{||{{LKR{{\[b~|mttd\\lri}{{t||lks{u{|tllf]cfkklriu{{ultu{{{{|||mttlkslkslks]cddc\\[[dc\[TTultddcsre{ttlrikd\ztlVTLMSS:97tzl}ultSKJVTLVZTVTL[TT[[Tf]cutllkdc\lekb[Utts}tt{|||mtt|zuztlld|f]clksultult|zddc{ttJHFtsl|u|u{{|ttstt{}tlld\\iq]lriUMR|d\\llktlllri\UZ[TTsle}\[[ult}ztl\[[||]cdJHF[TTVZTVTL\[[ekdSKJ^fsmttSKJdc\lddult}|}{||uztllklldtll{||{{tzlltts\[b}ultu{{ulttt{lek{u{}{u{|v{}|lri{{|}mttlektt{v[TT{{t{{t{{tztl]bZ{{||tts{||JHFVZ[lksnMSSmttmtt{||fkk\[[|ldd}|nvultdc\tt{edkUUY{||{{mtt]cd\[b^fsmttmttmttf]cmtttslekduztUTS|utleklrid\\f]ccbVlddSKJlldUMRr]ZVTLOS`)+2|llkFD;[[TSKJFD;SKJVZTUMRJHFJHFtsllldredSKJ{||UTS\[bekd|z|tts{||mtt{||lri]cdvuztztl[TTztltts\[btsl{{{u{UTS|]bZ{{JHFddcult}|\[[d\\srelri{tt}|rfksrebVZdc\edksleddcu{{\[[ekdf]c\UZ|d\\|z[[T\[[\[bd\\{{td\\||lritts}{tt||||ttsUUY{{}Æ~uzttt{~{tt{||{tt}lks]cdlriddcult|uzt|Ìddcultult[TTtllekdiq]]bZekdkd\{{\[[ekdf]c{u{lksmtttt{||nek]|lksuztmtt{{lks{{~tll}|{{lksddc{u{{{tult|mtt|{{lksfkk\[b]cd\[b]cdfkkddcuzt]cdlri|z{||[TTb[Ukd\sleb[UyleyfdllkJHFaWMlriOS`*)(tts}{ttd\\sre{{tb[UVTL74,JHFFD;UTSVZTkd\redjV[{u{ekdmtt{{tult{{t|zu{{lkslri\UZuzt}[TTlri]cdddc{||UTStt{|tts{u{|uztultUTSlddztl|zek]{{:97f]c\[[{ttlld{u{|z{ttrfk{ttsref]cUMR[[TlriJHF||\[b{{ult]bZult}||mttekdtt{{||{||}{{t}u{{|{{ultmk}~ult|tll}|lks{ttVZ[{{]cdmttUUYultylf]cf]cwlddcJHF[[T|edkulttt{edkmtt}]cdMRK{{|OS`lri]bZLKR{{lksuztyl}edkttslekmttfkk{|||\[[f]c\[b]cd{{lks|}||lksVZTf]ckd\b[Uf]c[[Trg]red{{tekd]bZtslJHF,55mttlldbVUFD;b[Uzlekd[[TekdlriSKJlld}{u{{u{d\\UTSlks|zlrimttu{{mttllk\[[llk\[[ldd{tt{||lri{{ulttsl{{mtt|{||}}ult{{ttsdc\{{t{{t[[TlksJHFJHFd\\|z{{|utsl[TTrfkVTLrfkdc\FD;sleekd[TTkk]|lld}{u{JHF{{\[[UUY]bZ{u{SKJllkzlllek{||||}lldlri}ldd|z{{llklkslekmtt{{|{{ode-0.14/drawstuff/textures/sky.ppm0000644000000000000000000014005312635011627016125 0ustar rootrootP6 # Created by Paint Shop Pro 128 128 255 }}~~}}y{}}z~|zz~zz|~{y~~~~|{x|yz}~xvuwzzzzyw~{zz}wuttyzyxw{~~zy~||{xwvwvwz~|{~}}~|zwyxx|~~|{||zz~~~}y}~}z{~||}}~~||||yw|{{|wtz}||~~vsuz}xwvw}~~zxwz}}|{{}|}|z|~|wuux{{~zxvuw||}}}||yv||~z|||~~|{y~}}z{|~~|yz}~}||x{|}|}z}~ode-0.14/drawstuff/textures/wood.ppm0000644000000000000000000060005312635011627016270 0ustar rootrootP6 # Created by Paint Shop Pro 256 256 255 ǿżŰ̻ÿǻʻǻŻÿ¸øŸۼƿ̼ÿÿʻõƼɿǾøشſ·ɻþǼƾŻǼʿƿÿǿٳſ̺ɿǼɿ»Ƽǿпƿпǵص̸Ǽǿ¾ſѾ׼ʾǸ¿ŵƻɿƿ̼¾׿Ƽ°»ºɺغǸۼſƿžؿ̼ƾ¿μſžÿúƸ¿¾žÿɻͿŸɿÿ»οüʿſ¿»ξǼſ¿μǸ¿¾ƾ׼δ¼ǻͻüп»ſŻžǼþÿþǿ¿ǿ¾þÿ¿¾úƿ¼̾źſº¼ƿѻŷ÷þþ׾ŷƵüſ¿¾ƸɵƼ¸ÿƺʵǼǻ¿ƾƼɺžžżƾƿſƾ÷ÿ̷ǻþ̿úƿÿԻżξþɸûпž̺Żí¾ǼʾʻŻñɼͿλпƻ¿ŻѼտúǾÿżԼԿʸѺǿÿſ̼;ͿռżԼƸǾſʼŵ¿ǺǺƾǿÿóοƾ»üѿǿƾÿƷҼƾü׻źþûѸܾҿûǿÿ·຺ƿÿ¾¸߾»żƻƸ߻þſҸмݺп̼Ƽ¼ſ¾;վÿٺԵλŵƾ¼¿ǷǸ¾»ܴѻǼúüʺ¼ưźžб׼Ƿ¼¾Ŵƾ¾ܵٿƼʼż´¾ƿº׾຺¾¾Ϳ;º̴¾ƺûɸžҸҿ;ƿǾ㸸Ե̸Żſ¸¼ÿ걱ƻ۾Ʊſ¼о»ǸµǷ߸ƿ¿Ǿؼ¿Ѻ¿¾ξûú侾ѵ¼¿ͺƿ¸Ƹ¾ƻǼվ¼üÿƴ۳һǼݾ¼ػƺɸ¿రưǸƸøſ·¼žõ¼ƿʿԾ÷·̼ƿ¿ƺ¿ƾ¸·̿Ʒ;ʼøſҾŵźҺǼͻþǿžտ±ŷɸžƿٳʼ̼ο¾¿÷þɸþſԷߴɼûþû÷żƸǺÿ¼ÿ¿»Я¾ſɼǻÿ¿üγɿƿɻǿÿɼż̼ſұǿ¿»ǺƵ¿ٸſɾſ¸ɾſǿºþغƾ̿¾¿λ¿¿Ǵƾſǵɼ»θƸ¿»ŵǾƿǿɻɺž¾żÿ¿úþµɺ¼¾ŵǻ¿ÿ¿Ǽɾ¼ÿƿ¿ſº¿ʺ¼źô俿ƺºŵžð¿Կúɻÿɿٻ»źƾξǾƻ⺺üξƻûǿƿÿǻÿ¾úµݵþǸ¿ǿ¼Ŵÿ¾ʨ¼¾ջƼƿÿɺþø¼¿ÿΰμ¾¿θѸ»º»¿´¿»ǿͼɼο¼ž¿üŷǸǼλ¿ÿŸ°Ƽ¾ø¿μ¿¿¾þɾžƿÿôŸ¼¿ż¼ÿ¿ƿſʼƿž¾ɸź¿ú¿ü¾û¿̿ʾ¾ø¾¿¾µǼſ¼µǼµƾƿÿ÷¿ƿƿ÷Żÿɺǿú÷¿¼ŷƿ¿ɼѾ¿¾üʿ¾üԱͿž¿Լ¼»¾ر¿÷Ÿüп¾ɿ̵þ¿Ǽҿ¿ʿ¸¿¿ɻɸþºҾ¿ż»Ǿпž¿¾¿ܿ̾·ÿƷǼɼ¿øƿþɻ¾㾾̼¼óɺú۷¼ñ뾾ɺǸ۷þɾ¾ų̺;¼̿謬ǾƼǿʺɿſżٺ¿ƿƼҾþżž̵¿ÿûʴݻǼ̼ü¿üƻƸݵÿǺ¾¸õƴٵɾ͸¾ͻƿپƻƾ»ƻƺ̼÷ѳǿ¾ſƸ¼һſƻ͸þѻʾξóοüƺͿ»۱̾Űеüʾíº¿ɾ㷷¾¾ƴ÷Ƽŭ¸ºŵ߷ɿƵ߼Ǹɼɵ¬ƿܷ̾´ݸºõ̻¿ŵ´üɷܺÿ;õžþƵƷƸαÿɻɷÿÿǸ¿»Ÿŭΰ¾Ŵʿþ໻ƿʸþǺſɾǷ͸ü̿Ƴ¿ⳳƿþþǴ俿ÿƺú´źźúǩÿźпʻ¾¾ſ¿ʼпʻ¿úÿкÿûþ¸ѻ;¸Żѱü۷ƿǿƿ´Իͺô¿ұÿþ¿̾ɸǿǺżͼºƴƸǿ߾ÿͻ³żûɾƳſ´ſհǺ״ſ̺¿¾ǿ¾̼ɿû³ÿץШǻƿøŻµ̻ɻôǿצɬúǾкþмѿŵ¾ըűþǾƻžźлƿѿǿêſõɱž̼¸ÿɻƿɾ׿ŭ¼μ¿̴¿¿οƻƼ¿ѺůǻоǬ̿¿ɻÿǿ̿ƻð¾ʼɵÿǻ¾Ϳþÿżűž¼ɾƯʿżôǰſüʿƯ躺Ǿ¯¸ÿüʼ绻žõ»Ŵͷɿ¼Ϳ̾ǿƺҿ¾λ¿»ЬɭʺǾ̿¾׾Ծ¿þ¸ҬƸƿ¿ƿׯŻɻž¼տ¾üҿٵ¸ÿ¿­翿DZ¼ʸܻÿŻÿ÷⼼ž¯¾ܼɷ¿ɸ¬»պǿ۷̿ǻǺñǺƸͿÿþ۱¼طÿǼǻۼѾ»Ǽ̯µ̷¿¿õʻ¿Ǽÿº̱¼ÿ¼ʿ¿Һ¿ʿͿǾʵŷǾƿ¼ú׻оſͰʼ¿ÿüظмʻͿ;еξ̾¼о¼Ǿ¿¿ǵƼʿοƿŻ¿;͵ۼŸտƺԸż̿ذƺſɾγŷݸ꿿ſɿ۵¼մоʼ󿿿ۼ¾ѿʿ¼¾үѻþվſǴǷоſƾ羾ʺʿ¾¿θƦοǾ྾ѾػǼŻ̼ûҨþͿûԾԴҺ¾߿СɾŻ»ÿº׻հһʻؼټШüǾɻƻǻݼ׺ŵü¿Һ¿ʨ¿ټźƿþغƵ̼ƺÿɾԻίɿǰǾžʼǺǺǿʿʸʼԩվƷ»ƻ྾ɿ̼ƾŷ̺似ŷ̿ſɳԸ̾»Ǿݵ¿ߵͿ»ø¾ҺƼŷǿŵǾ¾ܿǸɼǺſŴôξͿο¿̵ƸǾƿҾҿ뼼Һʴɿ¿þÿͷξóݻ۷̷ǿɻƺǸ¼Ǿƴ¾۸ε¿ÿþ̾ŻɷصʰǼиɻƺ̺ͬþûŸ±ƻƻͼ¢Ѵƿʸ㾾ƿ»̼üǸ¿̿ɰ»׻θ¸¼ŸкɼʰʿƯºƿԷǸշʱ·ͪ¿ǻƸþܸҴ¾¿лµͿ侾¾üſûҴл·»л俿ÿ¿þƻ׸ǷʿԿüþպ¾¾һͿԻ»»¿¿ɻƾžſżз̸Լ¼λ°¾÷տͿξŸ»оλúۿÿͿܸƾɰƳ¸Ƶ»ѾɼŸŵ⺺¿»ſվ¼ұƼ¼¿̷ƻ¿ݷþø㻻վ»ǵ¾ø¸ʸͿÿ׵ſٱѺƿǷžʰ¿̷ɻƺο¿̺üͼ·ǰ¾ԾƼDZÿƿƺ׵ÿԾſгԿ·þ׿õ¿źÿճɺſþű³»ü¾Ѻñп¿ɼ͵Ƽÿκ³Ƹû¿з·ſѺҺǾʿѷǴż»һ̼źԪžż¿¾һµõƾžþλ±þԯǼǻþѼҼ¼ÿǿμƾ¾Ԭÿ¿¿¿űʴ̾ƿſûܭɻѾ¿ѵǿúüƿ¿կпżƼƸ̻úƾ¾ñʻſ¼ðκºǺµҵ÷Ʒſÿʷ÷Ǹ̴ƾǾ¿¾ûþξ»Ϳܿ̿;ƿ¿ɾŸ״Ǿʵиſdzʼɼǵ׿»ÿξͼ̾Ѹʻż¿¿ѻƼ̾¿ſ¼¾̺øμεžſ̿ŻͻͼžżÿʻººþοøҼž»žͻɿű¾¿ž¾̿̿ۿŸżݼƺ͵¿ʿƴ¾ɳʹѸǸسǾǷ»¿ż¸ó̸¿ѿŻ绻ɿžǻʿ¸¿ʿú¸ŸžǾպ¼ƿǿ¿ɸ¿̼ƾѻƼþſүܾʾ̺ǿûԷƻԾ¼¼żƻÿɿø״ÿƷǭƿſ¿׼¿¿ƿ¿Ǿʺͼÿſżյþƿ¿ŵżһƿռξ»οžüбƾʿÿüκ¿Ƹ¼Żƿ¾ǿθŻûǵ¼ɳºǿ߾¼þüſ·μɻþѭѼɾʵþ·ǿž¿αͿɺ¼žŵžƿſ¼ÿƾǾ̷ʿοúɯ¾ÿҺؿǼǿſ⼼¼þôǷÿǾдźѾÿþüżſǾſɺſüа¿ſѿ;ÿǾÿƾ»¿иܴ̻»¿¾ʷƾſźºž¿ûºüǺóþſþŵºż¸ƿǼѴ³̾ÿþ»ôп¾žþǸüʵ¿¿̸þ̸¾üʼƻƵƸſƸ¿ôÿþžûмǻʿ;̻žɷƿƿ¿ʾøþɸƯ»ѸʻŻɵ»ſɼ±ǿλҼð̺Ƹžɻɼÿοÿ°¿žپ׼þɿ»۾žŻûƾƾ¿Ǽغ͸һǿ¿ۼú¾ʾ»ÿǿ·¸¾¾ԿżǷͻŷþ¿λ¸»ûÿÿξǿ̻ſ¾ô»Ƽɺɿ¾ƻƿ̿¾ɻ¾мɼǺؼ̼ɷɾÿɸŵÿ̾ſøźδ̷¸ûžƾױſ¾¾ɺʴɯɾǾ̴Ƽµ̷¼ƸÿƱ¼ƾÿɻƼ۴Ժ̼¿ɳƸͻ¿иźżû±ǵμ·¼¾¿¿ǾƼ¿ɻú¸͸ſô³Ʊǿûžûƻ¾¿»ɼʻԷŵ·ǼżüÿԿŻƿ±ƻɻǿŷξſ̿¾̸ͻҷøɼ»ʿ¿Ÿüٿſɼ¼Żͺ¿ż¸λƵƿʿŰƾ¾͸ƸɼžŴú׷żüʿҷ÷ŷǾͱɾ¿̷Ƹóż»ƺԸƿŵżƼηžʹоʿѼǴξøñǿ¿ѿɾ´¼żô¿ʺûƺƸп̺Ѱðűɿɴ¿͵õú»¸̺»ž¾Хƿǻ׾ʵ¾Ʊ̾¿ǼʿüǿDZ¼Żʷ¿þžûүǼɴ¿ƿο¾Ǫ¼µÿʾºƾǸ¼Կ¿ɺúɼͺɾѾǻþŪ´û¿ǾžøջóżǭƿʸǾͿþʿſ;ɿǾÿ¿ƺƼʿ¿̷ʻüؾ̱ƺɸ߿þ¬̿þ»Ǿíƻվ¾ʿÿ۾мͻɼ̺úſ÷°Ǽ¿þ»ŸͰµʺ¿пźº̾ʼ¿ǿ¿¬оʷʼ·ͼǿúεɿƾоÿż»þ̺ͿпøûƸžʾþʾտʸũտſðҸǼ¸žпƺÿüɺѿ;þƾλÿŸ·¾̿ƻþſξ»վ·¿ÿ⻻ſ¬ø¼̺̿ѿɼÿɻƾǾ»ⳳ¿ʻ¼κ¼þ̾з͸οſ´人ºðºƸ̸ûѴпºûżܿž㷷ǿ¼ʴ¾Ƽɺθ;ɾʷδξ̻Ǽʾ侾зƿɺγصѿаʸ̺¼̿໻͵žÿźſÿҷ̻ǿ¾þ似㿿̴̿¿ú̾ʾɷºɿƻøµ侾ʴɼüͿഴξǼ;ǿ°ɾƸ㾾ѿ̾ǻžѳ̺ɿ͸ǿƾƿǺǴſ÷Ǽ¼ߴοԺ¸ɿǿǿκ¾ʹÿûž糳Ǽü´ºŷ¾׿¾ź¾ɺؿ̱ode-0.14/include/0000775000000000000000000000000012635012023012322 5ustar rootrootode-0.14/include/Makefile.am0000644000000000000000000000003012635011627014356 0ustar rootrootSUBDIRS = ode drawstuff ode-0.14/include/drawstuff/0000775000000000000000000000000012635012023014327 5ustar rootrootode-0.14/include/drawstuff/Makefile.am0000644000000000000000000000005012635011627016365 0ustar rootrootnoinst_HEADERS = drawstuff.h version.h ode-0.14/include/drawstuff/drawstuff.h0000644000000000000000000002340612635011627016521 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /** @defgroup drawstuff DrawStuff DrawStuff is a library for rendering simple 3D objects in a virtual environment, for the purposes of demonstrating the features of ODE. It is provided for demonstration purposes and is not intended for production use. @section Notes In the virtual world, the z axis is "up" and z=0 is the floor. The user is able to click+drag in the main window to move the camera: * left button - pan and tilt. * right button - forward and sideways. * left + right button (or middle button) - sideways and up. */ #ifndef __DRAWSTUFF_H__ #define __DRAWSTUFF_H__ /* Define a DLL export symbol for those platforms that need it */ #if defined(ODE_PLATFORM_WINDOWS) #if defined(DS_DLL) #define DS_API __declspec(dllexport) #elif !defined(DS_LIB) #define DS_DLL_API __declspec(dllimport) #endif #endif #if !defined(DS_API) #define DS_API #endif #ifdef __cplusplus extern "C" { #endif #include /* texture numbers */ enum DS_TEXTURE_NUMBER { DS_NONE = 0, /* uses the current color instead of a texture */ DS_WOOD, DS_CHECKERED, DS_GROUND, DS_SKY }; /* draw modes */ #define DS_POLYFILL 0 #define DS_WIREFRAME 1 /** * @struct dsFunctions * @brief Set of functions to be used as callbacks by the simulation loop. * @ingroup drawstuff */ typedef struct dsFunctions { int version; /* put DS_VERSION here */ /* version 1 data */ void (*start)(); /* called before sim loop starts */ void (*step) (int pause); /* called before every frame */ void (*command) (int cmd); /* called if a command key is pressed */ void (*stop)(); /* called after sim loop exits */ /* version 2 data */ const char *path_to_textures; /* if nonzero, path to texture files */ } dsFunctions; /** * @brief Does the complete simulation. * @ingroup drawstuff * This function starts running the simulation, and only exits when the simulation is done. * Function pointers should be provided for the callbacks. * @param argv supports flags like '-notex' '-noshadow' '-pause' * @param fn Callback functions. */ DS_API void dsSimulationLoop (int argc, char **argv, int window_width, int window_height, struct dsFunctions *fn); /** * @brief exit with error message. * @ingroup drawstuff * This function displays an error message then exit. * @param msg format strin, like printf, without the newline character. */ DS_API void dsError (const char *msg, ...); /** * @brief exit with error message and core dump. * @ingroup drawstuff * this functions tries to dump core or start the debugger. * @param msg format strin, like printf, without the newline character. */ DS_API void dsDebug (const char *msg, ...); /** * @brief print log message * @ingroup drawstuff * @param msg format string, like printf, without the \n. */ DS_API void dsPrint (const char *msg, ...); /** * @brief Sets the viewpoint * @ingroup drawstuff * @param xyz camera position. * @param hpr contains heading, pitch and roll numbers in degrees. heading=0 * points along the x axis, pitch=0 is looking towards the horizon, and * roll 0 is "unrotated". */ DS_API void dsSetViewpoint (float xyz[3], float hpr[3]); /** * @brief Gets the viewpoint * @ingroup drawstuff * @param xyz position * @param hpr heading,pitch,roll. */ DS_API void dsGetViewpoint (float xyz[3], float hpr[3]); /** * @brief Stop the simulation loop. * @ingroup drawstuff * Calling this from within dsSimulationLoop() * will cause it to exit and return to the caller. it is the same as if the * user used the exit command. using this outside the loop will have no * effect. */ DS_API void dsStop(); /** * @brief Get the elapsed time (on wall-clock) * @ingroup drawstuff * It returns the nr of seconds since the last call to this function. */ DS_API double dsElapsedTime(); /** * @brief Toggle the rendering of textures. * @ingroup drawstuff * It changes the way objects are drawn. these changes will apply to all further * dsDrawXXX() functions. * @param the texture number must be a DS_xxx texture constant. * The current texture is colored according to the current color. * At the start of each frame, the texture is reset to none and the color is * reset to white. */ DS_API void dsSetTexture (int texture_number); /** * @brief Set the color with which geometry is drawn. * @ingroup drawstuff * @param red Red component from 0 to 1 * @param green Green component from 0 to 1 * @param blue Blue component from 0 to 1 */ DS_API void dsSetColor (float red, float green, float blue); /** * @brief Set the color and transparency with which geometry is drawn. * @ingroup drawstuff * @param alpha Note that alpha transparency is a misnomer: it is alpha opacity. * 1.0 means fully opaque, and 0.0 means fully transparent. */ DS_API void dsSetColorAlpha (float red, float green, float blue, float alpha); /** * @brief Draw a box. * @ingroup drawstuff * @param pos is the x,y,z of the center of the object. * @param R is a 3x3 rotation matrix for the object, stored by row like this: * [ R11 R12 R13 0 ] * [ R21 R22 R23 0 ] * [ R31 R32 R33 0 ] * @param sides[] is an array of x,y,z side lengths. */ DS_API void dsDrawBox (const float pos[3], const float R[12], const float sides[3]); /** * @brief Draw a sphere. * @ingroup drawstuff * @param pos Position of center. * @param R orientation. * @param radius */ DS_API void dsDrawSphere (const float pos[3], const float R[12], float radius); /** * @brief Draw a triangle. * @ingroup drawstuff * @param pos Position of center * @param R orientation * @param v0 first vertex * @param v1 second * @param v2 third vertex * @param solid set to 0 for wireframe */ DS_API void dsDrawTriangle (const float pos[3], const float R[12], const float *v0, const float *v1, const float *v2, int solid); /** * @brief Draw a z-aligned cylinder * @ingroup drawstuff */ DS_API void dsDrawCylinder (const float pos[3], const float R[12], float length, float radius); /** * @brief Draw a z-aligned capsule * @ingroup drawstuff */ DS_API void dsDrawCapsule (const float pos[3], const float R[12], float length, float radius); /** * @brief Draw a line. * @ingroup drawstuff */ DS_API void dsDrawLine (const float pos1[3], const float pos2[3]); /** * @brief Draw a convex shape. * @ingroup drawstuff */ DS_API void dsDrawConvex(const float pos[3], const float R[12], const float *_planes, unsigned int _planecount, const float *_points, unsigned int _pointcount, const unsigned int *_polygons); /* these drawing functions are identical to the ones above, except they take * double arrays for `pos' and `R'. */ DS_API void dsDrawBoxD (const double pos[3], const double R[12], const double sides[3]); DS_API void dsDrawSphereD (const double pos[3], const double R[12], const float radius); DS_API void dsDrawTriangleD (const double pos[3], const double R[12], const double *v0, const double *v1, const double *v2, int solid); DS_API void dsDrawCylinderD (const double pos[3], const double R[12], float length, float radius); DS_API void dsDrawCapsuleD (const double pos[3], const double R[12], float length, float radius); DS_API void dsDrawLineD (const double pos1[3], const double pos2[3]); DS_API void dsDrawConvexD(const double pos[3], const double R[12], const double *_planes, unsigned int _planecount, const double *_points, unsigned int _pointcount, const unsigned int *_polygons); /** * @brief Set the quality with which curved objects are rendered. * @ingroup drawstuff * Higher numbers are higher quality, but slower to draw. * This must be set before the first objects are drawn to be effective. * Default sphere quality is 1, default capsule quality is 3. */ DS_API void dsSetSphereQuality (int n); /* default = 1 */ DS_API void dsSetCapsuleQuality (int n); /* default = 3 */ /** * @brief Set Drawmode 0=Polygon Fill,1=Wireframe). * Use the DS_POLYFILL and DS_WIREFRAME macros. * @ingroup drawstuff */ DS_API void dsSetDrawMode(int mode); /* Backwards compatible API */ #define dsDrawCappedCylinder dsDrawCapsule #define dsDrawCappedCylinderD dsDrawCapsuleD #define dsSetCappedCylinderQuality dsSetCapsuleQuality /* closing bracket for extern "C" */ #ifdef __cplusplus } #endif #endif ode-0.14/include/drawstuff/version.h0000644000000000000000000000326012635011627016175 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef __VERSION_H #define __VERSION_H /* high byte is major version, low byte is minor version */ #define DS_VERSION 0x0002 #endif ode-0.14/include/ode/0000775000000000000000000000000012635012023013071 5ustar rootrootode-0.14/include/ode/Makefile.am0000644000000000000000000000113012635011627015127 0ustar rootrootlibode_la_includedir = $(includedir)/ode libode_la_include_HEADERS = \ collision.h \ collision_space.h \ collision_trimesh.h \ common.h \ compatibility.h \ contact.h \ error.h \ export-dif.h \ mass.h \ matrix.h \ memory.h \ misc.h \ objects.h \ ode.h \ odeconfig.h \ odecpp.h \ odecpp_collision.h \ odeinit.h \ odemath.h \ odemath_legacy.h \ rotation.h \ threading.h \ threading_impl.h \ timer.h EXTRA_DIST = README precision.h.in version.h.in dist_libode_la_include_HEADERS = precision.h version.h ode-0.14/include/ode/README0000644000000000000000000000062512635011627013763 0ustar rootroot this is the public C interface to the ODE library. all these files should be includable from C, i.e. they should not use any C++ features. everything should be protected with #ifdef __cplusplus extern "C" { #endif ... #ifdef __cplusplus } #endif the only exceptions are the odecpp.h and odecpp_collisioh.h files, which define a C++ wrapper for the C interface. remember to keep this in sync! ode-0.14/include/ode/collision.h0000644000000000000000000014721012635011627015251 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_COLLISION_H_ #define _ODE_COLLISION_H_ #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @defgroup collide Collision Detection * * ODE has two main components: a dynamics simulation engine and a collision * detection engine. The collision engine is given information about the * shape of each body. At each time step it figures out which bodies touch * each other and passes the resulting contact point information to the user. * The user in turn creates contact joints between bodies. * * Using ODE's collision detection is optional - an alternative collision * detection system can be used as long as it can supply the right kinds of * contact information. */ /* ************************************************************************ */ /* general functions */ /** * @brief Destroy a geom, removing it from any space. * * Destroy a geom, removing it from any space it is in first. This one * function destroys a geom of any type, but to create a geom you must call * a creation function for that type. * * When a space is destroyed, if its cleanup mode is 1 (the default) then all * the geoms in that space are automatically destroyed as well. * * @param geom the geom to be destroyed. * @ingroup collide */ ODE_API void dGeomDestroy (dGeomID geom); /** * @brief Set the user-defined data pointer stored in the geom. * * @param geom the geom to hold the data * @param data the data pointer to be stored * @ingroup collide */ ODE_API void dGeomSetData (dGeomID geom, void* data); /** * @brief Get the user-defined data pointer stored in the geom. * * @param geom the geom containing the data * @ingroup collide */ ODE_API void *dGeomGetData (dGeomID geom); /** * @brief Set the body associated with a placeable geom. * * Setting a body on a geom automatically combines the position vector and * rotation matrix of the body and geom, so that setting the position or * orientation of one will set the value for both objects. Setting a body * ID of zero gives the geom its own position and rotation, independent * from any body. If the geom was previously connected to a body then its * new independent position/rotation is set to the current position/rotation * of the body. * * Calling these functions on a non-placeable geom results in a runtime * error in the debug build of ODE. * * @param geom the geom to connect * @param body the body to attach to the geom * @ingroup collide */ ODE_API void dGeomSetBody (dGeomID geom, dBodyID body); /** * @brief Get the body associated with a placeable geom. * @param geom the geom to query. * @sa dGeomSetBody * @ingroup collide */ ODE_API dBodyID dGeomGetBody (dGeomID geom); /** * @brief Set the position vector of a placeable geom. * * If the geom is attached to a body, the body's position will also be changed. * Calling this function on a non-placeable geom results in a runtime error in * the debug build of ODE. * * @param geom the geom to set. * @param x the new X coordinate. * @param y the new Y coordinate. * @param z the new Z coordinate. * @sa dBodySetPosition * @ingroup collide */ ODE_API void dGeomSetPosition (dGeomID geom, dReal x, dReal y, dReal z); /** * @brief Set the rotation matrix of a placeable geom. * * If the geom is attached to a body, the body's rotation will also be changed. * Calling this function on a non-placeable geom results in a runtime error in * the debug build of ODE. * * @param geom the geom to set. * @param R the new rotation matrix. * @sa dBodySetRotation * @ingroup collide */ ODE_API void dGeomSetRotation (dGeomID geom, const dMatrix3 R); /** * @brief Set the rotation of a placeable geom. * * If the geom is attached to a body, the body's rotation will also be changed. * * Calling this function on a non-placeable geom results in a runtime error in * the debug build of ODE. * * @param geom the geom to set. * @param Q the new rotation. * @sa dBodySetQuaternion * @ingroup collide */ ODE_API void dGeomSetQuaternion (dGeomID geom, const dQuaternion Q); /** * @brief Get the position vector of a placeable geom. * * If the geom is attached to a body, the body's position will be returned. * * Calling this function on a non-placeable geom results in a runtime error in * the debug build of ODE. * * @param geom the geom to query. * @returns A pointer to the geom's position vector. * @remarks The returned value is a pointer to the geom's internal * data structure. It is valid until any changes are made * to the geom. * @sa dBodyGetPosition * @ingroup collide */ ODE_API const dReal * dGeomGetPosition (dGeomID geom); /** * @brief Copy the position of a geom into a vector. * @ingroup collide * @param geom the geom to query * @param pos a copy of the geom position * @sa dGeomGetPosition */ ODE_API void dGeomCopyPosition (dGeomID geom, dVector3 pos); /** * @brief Get the rotation matrix of a placeable geom. * * If the geom is attached to a body, the body's rotation will be returned. * * Calling this function on a non-placeable geom results in a runtime error in * the debug build of ODE. * * @param geom the geom to query. * @returns A pointer to the geom's rotation matrix. * @remarks The returned value is a pointer to the geom's internal * data structure. It is valid until any changes are made * to the geom. * @sa dBodyGetRotation * @ingroup collide */ ODE_API const dReal * dGeomGetRotation (dGeomID geom); /** * @brief Get the rotation matrix of a placeable geom. * * If the geom is attached to a body, the body's rotation will be returned. * * Calling this function on a non-placeable geom results in a runtime error in * the debug build of ODE. * * @param geom the geom to query. * @param R a copy of the geom rotation * @sa dGeomGetRotation * @ingroup collide */ ODE_API void dGeomCopyRotation(dGeomID geom, dMatrix3 R); /** * @brief Get the rotation quaternion of a placeable geom. * * If the geom is attached to a body, the body's quaternion will be returned. * * Calling this function on a non-placeable geom results in a runtime error in * the debug build of ODE. * * @param geom the geom to query. * @param result a copy of the rotation quaternion. * @sa dBodyGetQuaternion * @ingroup collide */ ODE_API void dGeomGetQuaternion (dGeomID geom, dQuaternion result); /** * @brief Return the axis-aligned bounding box. * * Return in aabb an axis aligned bounding box that surrounds the given geom. * The aabb array has elements (minx, maxx, miny, maxy, minz, maxz). If the * geom is a space, a bounding box that surrounds all contained geoms is * returned. * * This function may return a pre-computed cached bounding box, if it can * determine that the geom has not moved since the last time the bounding * box was computed. * * @param geom the geom to query * @param aabb the returned bounding box * @ingroup collide */ ODE_API void dGeomGetAABB (dGeomID geom, dReal aabb[6]); /** * @brief Determing if a geom is a space. * @param geom the geom to query * @returns Non-zero if the geom is a space, zero otherwise. * @ingroup collide */ ODE_API int dGeomIsSpace (dGeomID geom); /** * @brief Query for the space containing a particular geom. * @param geom the geom to query * @returns The space that contains the geom, or NULL if the geom is * not contained by a space. * @ingroup collide */ ODE_API dSpaceID dGeomGetSpace (dGeomID); /** * @brief Given a geom, this returns its class. * * The ODE classes are: * @li dSphereClass * @li dBoxClass * @li dCylinderClass * @li dPlaneClass * @li dRayClass * @li dConvexClass * @li dGeomTransformClass * @li dTriMeshClass * @li dSimpleSpaceClass * @li dHashSpaceClass * @li dQuadTreeSpaceClass * @li dFirstUserClass * @li dLastUserClass * * User-defined class will return their own number. * * @param geom the geom to query * @returns The geom class ID. * @ingroup collide */ ODE_API int dGeomGetClass (dGeomID geom); /** * @brief Set the "category" bitfield for the given geom. * * The category bitfield is used by spaces to govern which geoms will * interact with each other. The bitfield is guaranteed to be at least * 32 bits wide. The default category values for newly created geoms * have all bits set. * * @param geom the geom to set * @param bits the new bitfield value * @ingroup collide */ ODE_API void dGeomSetCategoryBits (dGeomID geom, unsigned long bits); /** * @brief Set the "collide" bitfield for the given geom. * * The collide bitfield is used by spaces to govern which geoms will * interact with each other. The bitfield is guaranteed to be at least * 32 bits wide. The default category values for newly created geoms * have all bits set. * * @param geom the geom to set * @param bits the new bitfield value * @ingroup collide */ ODE_API void dGeomSetCollideBits (dGeomID geom, unsigned long bits); /** * @brief Get the "category" bitfield for the given geom. * * @param geom the geom to set * @param bits the new bitfield value * @sa dGeomSetCategoryBits * @ingroup collide */ ODE_API unsigned long dGeomGetCategoryBits (dGeomID); /** * @brief Get the "collide" bitfield for the given geom. * * @param geom the geom to set * @param bits the new bitfield value * @sa dGeomSetCollideBits * @ingroup collide */ ODE_API unsigned long dGeomGetCollideBits (dGeomID); /** * @brief Enable a geom. * * Disabled geoms are completely ignored by dSpaceCollide and dSpaceCollide2, * although they can still be members of a space. New geoms are created in * the enabled state. * * @param geom the geom to enable * @sa dGeomDisable * @sa dGeomIsEnabled * @ingroup collide */ ODE_API void dGeomEnable (dGeomID geom); /** * @brief Disable a geom. * * Disabled geoms are completely ignored by dSpaceCollide and dSpaceCollide2, * although they can still be members of a space. New geoms are created in * the enabled state. * * @param geom the geom to disable * @sa dGeomDisable * @sa dGeomIsEnabled * @ingroup collide */ ODE_API void dGeomDisable (dGeomID geom); /** * @brief Check to see if a geom is enabled. * * Disabled geoms are completely ignored by dSpaceCollide and dSpaceCollide2, * although they can still be members of a space. New geoms are created in * the enabled state. * * @param geom the geom to query * @returns Non-zero if the geom is enabled, zero otherwise. * @sa dGeomDisable * @sa dGeomIsEnabled * @ingroup collide */ ODE_API int dGeomIsEnabled (dGeomID geom); enum { dGeomCommonControlClass = 0, dGeomColliderControlClass = 1 }; enum { dGeomCommonAnyControlCode = 0, dGeomColliderSetMergeSphereContactsControlCode = 1, dGeomColliderGetMergeSphereContactsControlCode = 2 }; enum { dGeomColliderMergeContactsValue__Default = 0, /* Used with Set... to restore default value*/ dGeomColliderMergeContactsValue_None = 1, dGeomColliderMergeContactsValue_Normals = 2, dGeomColliderMergeContactsValue_Full = 3 }; /** * @brief Execute low level control operation for geometry. * * The variable the dataSize points to must be initialized before the call. * If the size does not match the one expected for the control class/code function * changes it to the size expected and returns failure. This implies the function * can be called with NULL data and zero size to test if control class/code is supported * and obtain required data size for it. * * dGeomCommonAnyControlCode applies to any control class and returns success if * at least one control code is available for the given class with given geom. * * Currently there are the folliwing control classes supported: * @li dGeomColliderControlClass * * For dGeomColliderControlClass there are the following codes available: * @li dGeomColliderSetMergeSphereContactsControlCode (arg of type int, dGeomColliderMergeContactsValue_*) * @li dGeomColliderGetMergeSphereContactsControlCode (arg of type int, dGeomColliderMergeContactsValue_*) * * @param geom the geom to control * @param controlClass the control class * @param controlCode the control code for the class * @param dataValue the control argument pointer * @param dataSize the control argument size provided or expected * @returns Boolean execution status * @ingroup collide */ ODE_API int dGeomLowLevelControl (dGeomID geom, int controlClass, int controlCode, void *dataValue, int *dataSize); /** * @brief Get world position of a relative point on geom. * * Calling this function on a non-placeable geom results in the same point being * returned. * * @ingroup collide * @param result will contain the result. */ ODE_API void dGeomGetRelPointPos ( dGeomID geom, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief takes a point in global coordinates and returns * the point's position in geom-relative coordinates. * * Calling this function on a non-placeable geom results in the same point being * returned. * * @remarks * This is the inverse of dGeomGetRelPointPos() * @ingroup collide * @param result will contain the result. */ ODE_API void dGeomGetPosRelPoint ( dGeomID geom, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief Convert from geom-local to world coordinates. * * Calling this function on a non-placeable geom results in the same vector being * returned. * * @ingroup collide * @param result will contain the result. */ ODE_API void dGeomVectorToWorld ( dGeomID geom, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief Convert from world to geom-local coordinates. * * Calling this function on a non-placeable geom results in the same vector being * returned. * * @ingroup collide * @param result will contain the result. */ ODE_API void dGeomVectorFromWorld ( dGeomID geom, dReal px, dReal py, dReal pz, dVector3 result ); /* ************************************************************************ */ /* geom offset from body */ /** * @brief Set the local offset position of a geom from its body. * * Sets the geom's positional offset in local coordinates. * After this call, the geom will be at a new position determined from the * body's position and the offset. * The geom must be attached to a body. * If the geom did not have an offset, it is automatically created. * * @param geom the geom to set. * @param x the new X coordinate. * @param y the new Y coordinate. * @param z the new Z coordinate. * @ingroup collide */ ODE_API void dGeomSetOffsetPosition (dGeomID geom, dReal x, dReal y, dReal z); /** * @brief Set the local offset rotation matrix of a geom from its body. * * Sets the geom's rotational offset in local coordinates. * After this call, the geom will be at a new position determined from the * body's position and the offset. * The geom must be attached to a body. * If the geom did not have an offset, it is automatically created. * * @param geom the geom to set. * @param R the new rotation matrix. * @ingroup collide */ ODE_API void dGeomSetOffsetRotation (dGeomID geom, const dMatrix3 R); /** * @brief Set the local offset rotation of a geom from its body. * * Sets the geom's rotational offset in local coordinates. * After this call, the geom will be at a new position determined from the * body's position and the offset. * The geom must be attached to a body. * If the geom did not have an offset, it is automatically created. * * @param geom the geom to set. * @param Q the new rotation. * @ingroup collide */ ODE_API void dGeomSetOffsetQuaternion (dGeomID geom, const dQuaternion Q); /** * @brief Set the offset position of a geom from its body. * * Sets the geom's positional offset to move it to the new world * coordinates. * After this call, the geom will be at the world position passed in, * and the offset will be the difference from the current body position. * The geom must be attached to a body. * If the geom did not have an offset, it is automatically created. * * @param geom the geom to set. * @param x the new X coordinate. * @param y the new Y coordinate. * @param z the new Z coordinate. * @ingroup collide */ ODE_API void dGeomSetOffsetWorldPosition (dGeomID geom, dReal x, dReal y, dReal z); /** * @brief Set the offset rotation of a geom from its body. * * Sets the geom's rotational offset to orient it to the new world * rotation matrix. * After this call, the geom will be at the world orientation passed in, * and the offset will be the difference from the current body orientation. * The geom must be attached to a body. * If the geom did not have an offset, it is automatically created. * * @param geom the geom to set. * @param R the new rotation matrix. * @ingroup collide */ ODE_API void dGeomSetOffsetWorldRotation (dGeomID geom, const dMatrix3 R); /** * @brief Set the offset rotation of a geom from its body. * * Sets the geom's rotational offset to orient it to the new world * rotation matrix. * After this call, the geom will be at the world orientation passed in, * and the offset will be the difference from the current body orientation. * The geom must be attached to a body. * If the geom did not have an offset, it is automatically created. * * @param geom the geom to set. * @param Q the new rotation. * @ingroup collide */ ODE_API void dGeomSetOffsetWorldQuaternion (dGeomID geom, const dQuaternion); /** * @brief Clear any offset from the geom. * * If the geom has an offset, it is eliminated and the geom is * repositioned at the body's position. If the geom has no offset, * this function does nothing. * This is more efficient than calling dGeomSetOffsetPosition(zero) * and dGeomSetOffsetRotation(identiy), because this function actually * eliminates the offset, rather than leaving it as the identity transform. * * @param geom the geom to have its offset destroyed. * @ingroup collide */ ODE_API void dGeomClearOffset(dGeomID geom); /** * @brief Check to see whether the geom has an offset. * * This function will return non-zero if the offset has been created. * Note that there is a difference between a geom with no offset, * and a geom with an offset that is the identity transform. * In the latter case, although the observed behaviour is identical, * there is a unnecessary computation involved because the geom will * be applying the transform whenever it needs to recalculate its world * position. * * @param geom the geom to query. * @returns Non-zero if the geom has an offset, zero otherwise. * @ingroup collide */ ODE_API int dGeomIsOffset(dGeomID geom); /** * @brief Get the offset position vector of a geom. * * Returns the positional offset of the geom in local coordinates. * If the geom has no offset, this function returns the zero vector. * * @param geom the geom to query. * @returns A pointer to the geom's offset vector. * @remarks The returned value is a pointer to the geom's internal * data structure. It is valid until any changes are made * to the geom. * @ingroup collide */ ODE_API const dReal * dGeomGetOffsetPosition (dGeomID geom); /** * @brief Copy the offset position vector of a geom. * * Returns the positional offset of the geom in local coordinates. * If the geom has no offset, this function returns the zero vector. * * @param geom the geom to query. * @param pos returns the offset position * @ingroup collide */ ODE_API void dGeomCopyOffsetPosition (dGeomID geom, dVector3 pos); /** * @brief Get the offset rotation matrix of a geom. * * Returns the rotational offset of the geom in local coordinates. * If the geom has no offset, this function returns the identity * matrix. * * @param geom the geom to query. * @returns A pointer to the geom's offset rotation matrix. * @remarks The returned value is a pointer to the geom's internal * data structure. It is valid until any changes are made * to the geom. * @ingroup collide */ ODE_API const dReal * dGeomGetOffsetRotation (dGeomID geom); /** * @brief Copy the offset rotation matrix of a geom. * * Returns the rotational offset of the geom in local coordinates. * If the geom has no offset, this function returns the identity * matrix. * * @param geom the geom to query. * @param R returns the rotation matrix. * @ingroup collide */ ODE_API void dGeomCopyOffsetRotation (dGeomID geom, dMatrix3 R); /** * @brief Get the offset rotation quaternion of a geom. * * Returns the rotation offset of the geom as a quaternion. * If the geom has no offset, the identity quaternion is returned. * * @param geom the geom to query. * @param result a copy of the rotation quaternion. * @ingroup collide */ ODE_API void dGeomGetOffsetQuaternion (dGeomID geom, dQuaternion result); /* ************************************************************************ */ /* collision detection */ /* * Just generate any contacts (disables any contact refining). */ #define CONTACTS_UNIMPORTANT 0x80000000 /** * * @brief Given two geoms o1 and o2 that potentially intersect, * generate contact information for them. * * Internally, this just calls the correct class-specific collision * functions for o1 and o2. * * @param o1 The first geom to test. * @param o2 The second geom to test. * * @param flags The flags specify how contacts should be generated if * the geoms touch. The lower 16 bits of flags is an integer that * specifies the maximum number of contact points to generate. You must * ask for at least one contact. * Additionally, following bits may be set: * CONTACTS_UNIMPORTANT -- just generate any contacts (skip contact refining). * All other bits in flags must be set to zero. In the future the other bits * may be used to select from different contact generation strategies. * * @param contact Points to an array of dContactGeom structures. The array * must be able to hold at least the maximum number of contacts. These * dContactGeom structures may be embedded within larger structures in the * array -- the skip parameter is the byte offset from one dContactGeom to * the next in the array. If skip is sizeof(dContactGeom) then contact * points to a normal (C-style) array. It is an error for skip to be smaller * than sizeof(dContactGeom). * * @returns If the geoms intersect, this function returns the number of contact * points generated (and updates the contact array), otherwise it returns 0 * (and the contact array is not touched). * * @remarks If a space is passed as o1 or o2 then this function will collide * all objects contained in o1 with all objects contained in o2, and return * the resulting contact points. This method for colliding spaces with geoms * (or spaces with spaces) provides no user control over the individual * collisions. To get that control, use dSpaceCollide or dSpaceCollide2 instead. * * @remarks If o1 and o2 are the same geom then this function will do nothing * and return 0. Technically speaking an object intersects with itself, but it * is not useful to find contact points in this case. * * @remarks This function does not care if o1 and o2 are in the same space or not * (or indeed if they are in any space at all). * * @ingroup collide */ ODE_API int dCollide (dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, int skip); /** * @brief Determines which pairs of geoms in a space may potentially intersect, * and calls the callback function for each candidate pair. * * @param space The space to test. * * @param data Passed from dSpaceCollide directly to the callback * function. Its meaning is user defined. The o1 and o2 arguments are the * geoms that may be near each other. * * @param callback A callback function is of type @ref dNearCallback. * * @remarks Other spaces that are contained within the colliding space are * not treated specially, i.e. they are not recursed into. The callback * function may be passed these contained spaces as one or both geom * arguments. * * @remarks dSpaceCollide() is guaranteed to pass all intersecting geom * pairs to the callback function, but may also pass close but * non-intersecting pairs. The number of these calls depends on the * internal algorithms used by the space. Thus you should not expect * that dCollide will return contacts for every pair passed to the * callback. * * @sa dSpaceCollide2 * @ingroup collide */ ODE_API void dSpaceCollide (dSpaceID space, void *data, dNearCallback *callback); /** * @brief Determines which geoms from one space may potentially intersect with * geoms from another space, and calls the callback function for each candidate * pair. * * @param space1 The first space to test. * * @param space2 The second space to test. * * @param data Passed from dSpaceCollide directly to the callback * function. Its meaning is user defined. The o1 and o2 arguments are the * geoms that may be near each other. * * @param callback A callback function is of type @ref dNearCallback. * * @remarks This function can also test a single non-space geom against a * space. This function is useful when there is a collision hierarchy, i.e. * when there are spaces that contain other spaces. * * @remarks Other spaces that are contained within the colliding space are * not treated specially, i.e. they are not recursed into. The callback * function may be passed these contained spaces as one or both geom * arguments. * * @remarks Sublevel value of space affects how the spaces are iterated. * Both spaces are recursed only if their sublevels match. Otherwise, only * the space with greater sublevel is recursed and the one with lesser sublevel * is used as a geom itself. * * @remarks dSpaceCollide2() is guaranteed to pass all intersecting geom * pairs to the callback function, but may also pass close but * non-intersecting pairs. The number of these calls depends on the * internal algorithms used by the space. Thus you should not expect * that dCollide will return contacts for every pair passed to the * callback. * * @sa dSpaceCollide * @sa dSpaceSetSublevel * @ingroup collide */ ODE_API void dSpaceCollide2 (dGeomID space1, dGeomID space2, void *data, dNearCallback *callback); /* ************************************************************************ */ /* standard classes */ /* the maximum number of user classes that are supported */ enum { dMaxUserClasses = 4 }; /* class numbers - each geometry object needs a unique number */ enum { dSphereClass = 0, dBoxClass, dCapsuleClass, dCylinderClass, dPlaneClass, dRayClass, dConvexClass, dGeomTransformClass, dTriMeshClass, dHeightfieldClass, dFirstSpaceClass, dSimpleSpaceClass = dFirstSpaceClass, dHashSpaceClass, dSweepAndPruneSpaceClass, /* SAP */ dQuadTreeSpaceClass, dLastSpaceClass = dQuadTreeSpaceClass, dFirstUserClass, dLastUserClass = dFirstUserClass + dMaxUserClasses - 1, dGeomNumClasses }; /** * @defgroup collide_sphere Sphere Class * @ingroup collide */ /** * @brief Create a sphere geom of the given radius, and return its ID. * * @param space a space to contain the new geom. May be null. * @param radius the radius of the sphere. * * @returns A new sphere geom. * * @remarks The point of reference for a sphere is its center. * * @sa dGeomDestroy * @sa dGeomSphereSetRadius * @ingroup collide_sphere */ ODE_API dGeomID dCreateSphere (dSpaceID space, dReal radius); /** * @brief Set the radius of a sphere geom. * * @param sphere the sphere to set. * @param radius the new radius. * * @sa dGeomSphereGetRadius * @ingroup collide_sphere */ ODE_API void dGeomSphereSetRadius (dGeomID sphere, dReal radius); /** * @brief Retrieves the radius of a sphere geom. * * @param sphere the sphere to query. * * @sa dGeomSphereSetRadius * @ingroup collide_sphere */ ODE_API dReal dGeomSphereGetRadius (dGeomID sphere); /** * @brief Calculate the depth of the a given point within a sphere. * * @param sphere the sphere to query. * @param x the X coordinate of the point. * @param y the Y coordinate of the point. * @param z the Z coordinate of the point. * * @returns The depth of the point. Points inside the sphere will have a * positive depth, points outside it will have a negative depth, and points * on the surface will have a depth of zero. * * @ingroup collide_sphere */ ODE_API dReal dGeomSpherePointDepth (dGeomID sphere, dReal x, dReal y, dReal z); /*--> Convex Functions*/ ODE_API dGeomID dCreateConvex (dSpaceID space, const dReal *_planes, unsigned int _planecount, const dReal *_points, unsigned int _pointcount, const unsigned int *_polygons); ODE_API void dGeomSetConvex (dGeomID g, const dReal *_planes, unsigned int _count, const dReal *_points, unsigned int _pointcount, const unsigned int *_polygons); /*<-- Convex Functions*/ /** * @defgroup collide_box Box Class * @ingroup collide */ /** * @brief Create a box geom with the provided side lengths. * * @param space a space to contain the new geom. May be null. * @param lx the length of the box along the X axis * @param ly the length of the box along the Y axis * @param lz the length of the box along the Z axis * * @returns A new box geom. * * @remarks The point of reference for a box is its center. * * @sa dGeomDestroy * @sa dGeomBoxSetLengths * @ingroup collide_box */ ODE_API dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz); /** * @brief Set the side lengths of the given box. * * @param box the box to set * @param lx the length of the box along the X axis * @param ly the length of the box along the Y axis * @param lz the length of the box along the Z axis * * @sa dGeomBoxGetLengths * @ingroup collide_box */ ODE_API void dGeomBoxSetLengths (dGeomID box, dReal lx, dReal ly, dReal lz); /** * @brief Get the side lengths of a box. * * @param box the box to query * @param result the returned side lengths * * @sa dGeomBoxSetLengths * @ingroup collide_box */ ODE_API void dGeomBoxGetLengths (dGeomID box, dVector3 result); /** * @brief Return the depth of a point in a box. * * @param box the box to query * @param x the X coordinate of the point to test. * @param y the Y coordinate of the point to test. * @param z the Z coordinate of the point to test. * * @returns The depth of the point. Points inside the box will have a * positive depth, points outside it will have a negative depth, and points * on the surface will have a depth of zero. */ ODE_API dReal dGeomBoxPointDepth (dGeomID box, dReal x, dReal y, dReal z); ODE_API dGeomID dCreatePlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d); ODE_API void dGeomPlaneSetParams (dGeomID plane, dReal a, dReal b, dReal c, dReal d); ODE_API void dGeomPlaneGetParams (dGeomID plane, dVector4 result); ODE_API dReal dGeomPlanePointDepth (dGeomID plane, dReal x, dReal y, dReal z); ODE_API dGeomID dCreateCapsule (dSpaceID space, dReal radius, dReal length); ODE_API void dGeomCapsuleSetParams (dGeomID ccylinder, dReal radius, dReal length); ODE_API void dGeomCapsuleGetParams (dGeomID ccylinder, dReal *radius, dReal *length); ODE_API dReal dGeomCapsulePointDepth (dGeomID ccylinder, dReal x, dReal y, dReal z); /* For now we want to have a backwards compatible C-API, note: C++ API is not.*/ #define dCreateCCylinder dCreateCapsule #define dGeomCCylinderSetParams dGeomCapsuleSetParams #define dGeomCCylinderGetParams dGeomCapsuleGetParams #define dGeomCCylinderPointDepth dGeomCapsulePointDepth #define dCCylinderClass dCapsuleClass ODE_API dGeomID dCreateCylinder (dSpaceID space, dReal radius, dReal length); ODE_API void dGeomCylinderSetParams (dGeomID cylinder, dReal radius, dReal length); ODE_API void dGeomCylinderGetParams (dGeomID cylinder, dReal *radius, dReal *length); ODE_API dGeomID dCreateRay (dSpaceID space, dReal length); ODE_API void dGeomRaySetLength (dGeomID ray, dReal length); ODE_API dReal dGeomRayGetLength (dGeomID ray); ODE_API void dGeomRaySet (dGeomID ray, dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz); ODE_API void dGeomRayGet (dGeomID ray, dVector3 start, dVector3 dir); /* * Set/get ray flags that influence ray collision detection. * These flags are currently only noticed by the trimesh collider, because * they can make a major differences there. */ ODE_API_DEPRECATED ODE_API void dGeomRaySetParams (dGeomID g, int FirstContact, int BackfaceCull); ODE_API_DEPRECATED ODE_API void dGeomRayGetParams (dGeomID g, int *FirstContact, int *BackfaceCull); ODE_API void dGeomRaySetFirstContact (dGeomID g, int firstContact); ODE_API int dGeomRayGetFirstContact (dGeomID g); ODE_API void dGeomRaySetBackfaceCull (dGeomID g, int backfaceCull); ODE_API int dGeomRayGetBackfaceCull (dGeomID g); ODE_API void dGeomRaySetClosestHit (dGeomID g, int closestHit); ODE_API int dGeomRayGetClosestHit (dGeomID g); #include "collision_trimesh.h" ODE_API_DEPRECATED ODE_API dGeomID dCreateGeomTransform (dSpaceID space); ODE_API_DEPRECATED ODE_API void dGeomTransformSetGeom (dGeomID g, dGeomID obj); ODE_API_DEPRECATED ODE_API dGeomID dGeomTransformGetGeom (dGeomID g); ODE_API_DEPRECATED ODE_API void dGeomTransformSetCleanup (dGeomID g, int mode); ODE_API_DEPRECATED ODE_API int dGeomTransformGetCleanup (dGeomID g); ODE_API_DEPRECATED ODE_API void dGeomTransformSetInfo (dGeomID g, int mode); ODE_API_DEPRECATED ODE_API int dGeomTransformGetInfo (dGeomID g); /* ************************************************************************ */ /* heightfield functions */ /* Data storage for heightfield data.*/ struct dxHeightfieldData; typedef struct dxHeightfieldData* dHeightfieldDataID; /** * @brief Callback prototype * * Used by the callback heightfield data type to sample a height for a * given cell position. * * @param p_user_data User data specified when creating the dHeightfieldDataID * @param x The index of a sample in the local x axis. It is a value * in the range zero to ( nWidthSamples - 1 ). * @param x The index of a sample in the local z axis. It is a value * in the range zero to ( nDepthSamples - 1 ). * * @return The sample height which is then scaled and offset using the * values specified when the heightfield data was created. * * @ingroup collide */ typedef dReal dHeightfieldGetHeight( void* p_user_data, int x, int z ); /** * @brief Creates a heightfield geom. * * Uses the information in the given dHeightfieldDataID to construct * a geom representing a heightfield in a collision space. * * @param space The space to add the geom to. * @param data The dHeightfieldDataID created by dGeomHeightfieldDataCreate and * setup by dGeomHeightfieldDataBuildCallback, dGeomHeightfieldDataBuildByte, * dGeomHeightfieldDataBuildShort or dGeomHeightfieldDataBuildFloat. * @param bPlaceable If non-zero this geom can be transformed in the world using the * usual functions such as dGeomSetPosition and dGeomSetRotation. If the geom is * not set as placeable, then it uses a fixed orientation where the global y axis * represents the dynamic 'height' of the heightfield. * * @return A geom id to reference this geom in other calls. * * @ingroup collide */ ODE_API dGeomID dCreateHeightfield( dSpaceID space, dHeightfieldDataID data, int bPlaceable ); /** * @brief Creates a new empty dHeightfieldDataID. * * Allocates a new dHeightfieldDataID and returns it. You must call * dGeomHeightfieldDataDestroy to destroy it after the geom has been removed. * The dHeightfieldDataID value is used when specifying a data format type. * * @return A dHeightfieldDataID for use with dGeomHeightfieldDataBuildCallback, * dGeomHeightfieldDataBuildByte, dGeomHeightfieldDataBuildShort or * dGeomHeightfieldDataBuildFloat. * @ingroup collide */ ODE_API dHeightfieldDataID dGeomHeightfieldDataCreate(void); /** * @brief Destroys a dHeightfieldDataID. * * Deallocates a given dHeightfieldDataID and all managed resources. * * @param d A dHeightfieldDataID created by dGeomHeightfieldDataCreate * @ingroup collide */ ODE_API void dGeomHeightfieldDataDestroy( dHeightfieldDataID d ); /** * @brief Configures a dHeightfieldDataID to use a callback to * retrieve height data. * * Before a dHeightfieldDataID can be used by a geom it must be * configured to specify the format of the height data. * This call specifies that the heightfield data is computed by * the user and it should use the given callback when determining * the height of a given element of it's shape. * * @param d A new dHeightfieldDataID created by dGeomHeightfieldDataCreate * * @param width Specifies the total 'width' of the heightfield along * the geom's local x axis. * @param depth Specifies the total 'depth' of the heightfield along * the geom's local z axis. * * @param widthSamples Specifies the number of vertices to sample * along the width of the heightfield. Each vertex has a corresponding * height value which forms the overall shape. * Naturally this value must be at least two or more. * @param depthSamples Specifies the number of vertices to sample * along the depth of the heightfield. * * @param scale A uniform scale applied to all raw height data. * @param offset An offset applied to the scaled height data. * * @param thickness A value subtracted from the lowest height * value which in effect adds an additional cuboid to the base of the * heightfield. This is used to prevent geoms from looping under the * desired terrain and not registering as a collision. Note that the * thickness is not affected by the scale or offset parameters. * * @param bWrap If non-zero the heightfield will infinitely tile in both * directions along the local x and z axes. If zero the heightfield is * bounded from zero to width in the local x axis, and zero to depth in * the local z axis. * * @ingroup collide */ ODE_API void dGeomHeightfieldDataBuildCallback( dHeightfieldDataID d, void* pUserData, dHeightfieldGetHeight* pCallback, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap ); /** * @brief Configures a dHeightfieldDataID to use height data in byte format. * * Before a dHeightfieldDataID can be used by a geom it must be * configured to specify the format of the height data. * This call specifies that the heightfield data is stored as a rectangular * array of bytes (8 bit unsigned) representing the height at each sample point. * * @param d A new dHeightfieldDataID created by dGeomHeightfieldDataCreate * * @param pHeightData A pointer to the height data. * @param bCopyHeightData When non-zero the height data is copied to an * internal store. When zero the height data is accessed by reference and * so must persist throughout the lifetime of the heightfield. * * @param width Specifies the total 'width' of the heightfield along * the geom's local x axis. * @param depth Specifies the total 'depth' of the heightfield along * the geom's local z axis. * * @param widthSamples Specifies the number of vertices to sample * along the width of the heightfield. Each vertex has a corresponding * height value which forms the overall shape. * Naturally this value must be at least two or more. * @param depthSamples Specifies the number of vertices to sample * along the depth of the heightfield. * * @param scale A uniform scale applied to all raw height data. * @param offset An offset applied to the scaled height data. * * @param thickness A value subtracted from the lowest height * value which in effect adds an additional cuboid to the base of the * heightfield. This is used to prevent geoms from looping under the * desired terrain and not registering as a collision. Note that the * thickness is not affected by the scale or offset parameters. * * @param bWrap If non-zero the heightfield will infinitely tile in both * directions along the local x and z axes. If zero the heightfield is * bounded from zero to width in the local x axis, and zero to depth in * the local z axis. * * @ingroup collide */ ODE_API void dGeomHeightfieldDataBuildByte( dHeightfieldDataID d, const unsigned char* pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap ); /** * @brief Configures a dHeightfieldDataID to use height data in short format. * * Before a dHeightfieldDataID can be used by a geom it must be * configured to specify the format of the height data. * This call specifies that the heightfield data is stored as a rectangular * array of shorts (16 bit signed) representing the height at each sample point. * * @param d A new dHeightfieldDataID created by dGeomHeightfieldDataCreate * * @param pHeightData A pointer to the height data. * @param bCopyHeightData When non-zero the height data is copied to an * internal store. When zero the height data is accessed by reference and * so must persist throughout the lifetime of the heightfield. * * @param width Specifies the total 'width' of the heightfield along * the geom's local x axis. * @param depth Specifies the total 'depth' of the heightfield along * the geom's local z axis. * * @param widthSamples Specifies the number of vertices to sample * along the width of the heightfield. Each vertex has a corresponding * height value which forms the overall shape. * Naturally this value must be at least two or more. * @param depthSamples Specifies the number of vertices to sample * along the depth of the heightfield. * * @param scale A uniform scale applied to all raw height data. * @param offset An offset applied to the scaled height data. * * @param thickness A value subtracted from the lowest height * value which in effect adds an additional cuboid to the base of the * heightfield. This is used to prevent geoms from looping under the * desired terrain and not registering as a collision. Note that the * thickness is not affected by the scale or offset parameters. * * @param bWrap If non-zero the heightfield will infinitely tile in both * directions along the local x and z axes. If zero the heightfield is * bounded from zero to width in the local x axis, and zero to depth in * the local z axis. * * @ingroup collide */ ODE_API void dGeomHeightfieldDataBuildShort( dHeightfieldDataID d, const short* pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap ); /** * @brief Configures a dHeightfieldDataID to use height data in * single precision floating point format. * * Before a dHeightfieldDataID can be used by a geom it must be * configured to specify the format of the height data. * This call specifies that the heightfield data is stored as a rectangular * array of single precision floats representing the height at each * sample point. * * @param d A new dHeightfieldDataID created by dGeomHeightfieldDataCreate * * @param pHeightData A pointer to the height data. * @param bCopyHeightData When non-zero the height data is copied to an * internal store. When zero the height data is accessed by reference and * so must persist throughout the lifetime of the heightfield. * * @param width Specifies the total 'width' of the heightfield along * the geom's local x axis. * @param depth Specifies the total 'depth' of the heightfield along * the geom's local z axis. * * @param widthSamples Specifies the number of vertices to sample * along the width of the heightfield. Each vertex has a corresponding * height value which forms the overall shape. * Naturally this value must be at least two or more. * @param depthSamples Specifies the number of vertices to sample * along the depth of the heightfield. * * @param scale A uniform scale applied to all raw height data. * @param offset An offset applied to the scaled height data. * * @param thickness A value subtracted from the lowest height * value which in effect adds an additional cuboid to the base of the * heightfield. This is used to prevent geoms from looping under the * desired terrain and not registering as a collision. Note that the * thickness is not affected by the scale or offset parameters. * * @param bWrap If non-zero the heightfield will infinitely tile in both * directions along the local x and z axes. If zero the heightfield is * bounded from zero to width in the local x axis, and zero to depth in * the local z axis. * * @ingroup collide */ ODE_API void dGeomHeightfieldDataBuildSingle( dHeightfieldDataID d, const float* pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap ); /** * @brief Configures a dHeightfieldDataID to use height data in * double precision floating point format. * * Before a dHeightfieldDataID can be used by a geom it must be * configured to specify the format of the height data. * This call specifies that the heightfield data is stored as a rectangular * array of double precision floats representing the height at each * sample point. * * @param d A new dHeightfieldDataID created by dGeomHeightfieldDataCreate * * @param pHeightData A pointer to the height data. * @param bCopyHeightData When non-zero the height data is copied to an * internal store. When zero the height data is accessed by reference and * so must persist throughout the lifetime of the heightfield. * * @param width Specifies the total 'width' of the heightfield along * the geom's local x axis. * @param depth Specifies the total 'depth' of the heightfield along * the geom's local z axis. * * @param widthSamples Specifies the number of vertices to sample * along the width of the heightfield. Each vertex has a corresponding * height value which forms the overall shape. * Naturally this value must be at least two or more. * @param depthSamples Specifies the number of vertices to sample * along the depth of the heightfield. * * @param scale A uniform scale applied to all raw height data. * @param offset An offset applied to the scaled height data. * * @param thickness A value subtracted from the lowest height * value which in effect adds an additional cuboid to the base of the * heightfield. This is used to prevent geoms from looping under the * desired terrain and not registering as a collision. Note that the * thickness is not affected by the scale or offset parameters. * * @param bWrap If non-zero the heightfield will infinitely tile in both * directions along the local x and z axes. If zero the heightfield is * bounded from zero to width in the local x axis, and zero to depth in * the local z axis. * * @ingroup collide */ ODE_API void dGeomHeightfieldDataBuildDouble( dHeightfieldDataID d, const double* pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, dReal scale, dReal offset, dReal thickness, int bWrap ); /** * @brief Manually set the minimum and maximum height bounds. * * This call allows you to set explicit min / max values after initial * creation typically for callback heightfields which default to +/- infinity, * or those whose data has changed. This must be set prior to binding with a * geom, as the the AABB is not recomputed after it's first generation. * * @remarks The minimum and maximum values are used to compute the AABB * for the heightfield which is used for early rejection of collisions. * A close fit will yield a more efficient collision check. * * @param d A dHeightfieldDataID created by dGeomHeightfieldDataCreate * @param min_height The new minimum height value. Scale, offset and thickness is then applied. * @param max_height The new maximum height value. Scale and offset is then applied. * @ingroup collide */ ODE_API void dGeomHeightfieldDataSetBounds( dHeightfieldDataID d, dReal minHeight, dReal maxHeight ); /** * @brief Assigns a dHeightfieldDataID to a heightfield geom. * * Associates the given dHeightfieldDataID with a heightfield geom. * This is done without affecting the GEOM_PLACEABLE flag. * * @param g A geom created by dCreateHeightfield * @param d A dHeightfieldDataID created by dGeomHeightfieldDataCreate * @ingroup collide */ ODE_API void dGeomHeightfieldSetHeightfieldData( dGeomID g, dHeightfieldDataID d ); /** * @brief Gets the dHeightfieldDataID bound to a heightfield geom. * * Returns the dHeightfieldDataID associated with a heightfield geom. * * @param g A geom created by dCreateHeightfield * @return The dHeightfieldDataID which may be NULL if none was assigned. * @ingroup collide */ ODE_API dHeightfieldDataID dGeomHeightfieldGetHeightfieldData( dGeomID g ); /* ************************************************************************ */ /* utility functions */ ODE_API void dClosestLineSegmentPoints (const dVector3 a1, const dVector3 a2, const dVector3 b1, const dVector3 b2, dVector3 cp1, dVector3 cp2); ODE_API int dBoxTouchesBox (const dVector3 _p1, const dMatrix3 R1, const dVector3 side1, const dVector3 _p2, const dMatrix3 R2, const dVector3 side2); /* The meaning of flags parameter is the same as in dCollide()*/ ODE_API int dBoxBox (const dVector3 p1, const dMatrix3 R1, const dVector3 side1, const dVector3 p2, const dMatrix3 R2, const dVector3 side2, dVector3 normal, dReal *depth, int *return_code, int flags, dContactGeom *contact, int skip); ODE_API void dInfiniteAABB (dGeomID geom, dReal aabb[6]); /* ************************************************************************ */ /* custom classes */ typedef void dGetAABBFn (dGeomID, dReal aabb[6]); typedef int dColliderFn (dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, int skip); typedef dColliderFn * dGetColliderFnFn (int num); typedef void dGeomDtorFn (dGeomID o); typedef int dAABBTestFn (dGeomID o1, dGeomID o2, dReal aabb[6]); typedef struct dGeomClass { int bytes; dGetColliderFnFn *collider; dGetAABBFn *aabb; dAABBTestFn *aabb_test; dGeomDtorFn *dtor; } dGeomClass; ODE_API int dCreateGeomClass (const dGeomClass *classptr); ODE_API void * dGeomGetClassData (dGeomID); ODE_API dGeomID dCreateGeom (int classnum); /** * @brief Sets a custom collider function for two geom classes. * * @param i The first geom class handled by this collider * @param j The second geom class handled by this collider * @param fn The collider function to use to determine collisions. * @ingroup collide */ ODE_API void dSetColliderOverride (int i, int j, dColliderFn *fn); /* ************************************************************************ */ #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/collision_space.h0000644000000000000000000001472012635011627016423 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_COLLISION_SPACE_H_ #define _ODE_COLLISION_SPACE_H_ #include #ifdef __cplusplus extern "C" { #endif struct dContactGeom; /** * @brief User callback for geom-geom collision testing. * * @param data The user data object, as passed to dSpaceCollide. * @param o1 The first geom being tested. * @param o2 The second geom being test. * * @remarks The callback function can call dCollide on o1 and o2 to generate * contact points between each pair. Then these contact points may be added * to the simulation as contact joints. The user's callback function can of * course chose not to call dCollide for any pair, e.g. if the user decides * that those pairs should not interact. * * @ingroup collide */ typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); ODE_API dSpaceID dSimpleSpaceCreate (dSpaceID space); ODE_API dSpaceID dHashSpaceCreate (dSpaceID space); ODE_API dSpaceID dQuadTreeSpaceCreate (dSpaceID space, const dVector3 Center, const dVector3 Extents, int Depth); /* SAP */ /* Order XZY or ZXY usually works best, if your Y is up. */ #define dSAP_AXES_XYZ ((0)|(1<<2)|(2<<4)) #define dSAP_AXES_XZY ((0)|(2<<2)|(1<<4)) #define dSAP_AXES_YXZ ((1)|(0<<2)|(2<<4)) #define dSAP_AXES_YZX ((1)|(2<<2)|(0<<4)) #define dSAP_AXES_ZXY ((2)|(0<<2)|(1<<4)) #define dSAP_AXES_ZYX ((2)|(1<<2)|(0<<4)) ODE_API dSpaceID dSweepAndPruneSpaceCreate( dSpaceID space, int axisorder ); ODE_API void dSpaceDestroy (dSpaceID); ODE_API void dHashSpaceSetLevels (dSpaceID space, int minlevel, int maxlevel); ODE_API void dHashSpaceGetLevels (dSpaceID space, int *minlevel, int *maxlevel); ODE_API void dSpaceSetCleanup (dSpaceID space, int mode); ODE_API int dSpaceGetCleanup (dSpaceID space); /** * @brief Sets sublevel value for a space. * * Sublevel affects how the space is handled in dSpaceCollide2 when it is collided * with another space. If sublevels of both spaces match, the function iterates * geometries of both spaces and collides them with each other. If sublevel of one * space is greater than the sublevel of another one, only the geometries of the * space with greater sublevel are iterated, another space is passed into * collision callback as a geometry itself. By default all the spaces are assigned * zero sublevel. * * @note * The space sublevel @e IS @e NOT automatically updated when one space is inserted * into another or removed from one. It is a client's responsibility to update sublevel * value if necessary. * * @param space the space to modify * @param sublevel the sublevel value to be assigned * @ingroup collide * @see dSpaceGetSublevel * @see dSpaceCollide2 */ ODE_API void dSpaceSetSublevel (dSpaceID space, int sublevel); /** * @brief Gets sublevel value of a space. * * Sublevel affects how the space is handled in dSpaceCollide2 when it is collided * with another space. See @c dSpaceSetSublevel for more details. * * @param space the space to query * @returns the sublevel value of the space * @ingroup collide * @see dSpaceSetSublevel * @see dSpaceCollide2 */ ODE_API int dSpaceGetSublevel (dSpaceID space); /** * @brief Sets manual cleanup flag for a space. * * Manual cleanup flag marks a space as eligible for manual thread data cleanup. * This function should be called for every space object right after creation in * case if ODE has been initialized with @c dInitFlagManualThreadCleanup flag. * * Failure to set manual cleanup flag for a space may lead to some resources * remaining leaked until the program exit. * * @param space the space to modify * @param mode 1 for manual cleanup mode and 0 for default cleanup mode * @ingroup collide * @see dSpaceGetManualCleanup * @see dInitODE2 */ ODE_API void dSpaceSetManualCleanup (dSpaceID space, int mode); /** * @brief Get manual cleanup flag of a space. * * Manual cleanup flag marks a space space as eligible for manual thread data cleanup. * See @c dSpaceSetManualCleanup for more details. * * @param space the space to query * @returns 1 for manual cleanup mode and 0 for default cleanup mode of the space * @ingroup collide * @see dSpaceSetManualCleanup * @see dInitODE2 */ ODE_API int dSpaceGetManualCleanup (dSpaceID space); ODE_API void dSpaceAdd (dSpaceID, dGeomID); ODE_API void dSpaceRemove (dSpaceID, dGeomID); ODE_API int dSpaceQuery (dSpaceID, dGeomID); ODE_API void dSpaceClean (dSpaceID); ODE_API int dSpaceGetNumGeoms (dSpaceID); ODE_API dGeomID dSpaceGetGeom (dSpaceID, int i); /** * @brief Given a space, this returns its class. * * The ODE classes are: * @li dSimpleSpaceClass * @li dHashSpaceClass * @li dSweepAndPruneSpaceClass * @li dQuadTreeSpaceClass * @li dFirstUserClass * @li dLastUserClass * * The class id not defined by the user should be between * dFirstSpaceClass and dLastSpaceClass. * * User-defined class will return their own number. * * @param space the space to query * @returns The space class ID. * @ingroup collide */ ODE_API int dSpaceGetClass(dSpaceID space); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/collision_trimesh.h0000644000000000000000000002101112635011627016772 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* * TriMesh code by Erwin de Vries. * * Trimesh data. * This is where the actual vertexdata (pointers), and BV tree is stored. * Vertices should be single precision! * This should be more sophisticated, so that the user can easyly implement * another collision library, but this is a lot of work, and also costs some * performance because some data has to be copied. */ #ifndef _ODE_COLLISION_TRIMESH_H_ #define _ODE_COLLISION_TRIMESH_H_ #ifdef __cplusplus extern "C" { #endif /* * Data storage for triangle meshes. */ struct dxTriMeshData; typedef struct dxTriMeshData* dTriMeshDataID; /* * These dont make much sense now, but they will later when we add more * features. */ ODE_API dTriMeshDataID dGeomTriMeshDataCreate(void); ODE_API void dGeomTriMeshDataDestroy(dTriMeshDataID g); enum { TRIMESH_FACE_NORMALS }; ODE_API void dGeomTriMeshDataSet(dTriMeshDataID g, int data_id, void* in_data); ODE_API void* dGeomTriMeshDataGet(dTriMeshDataID g, int data_id); /** * We need to set the last transform after each time step for * accurate collision response. These functions get and set that transform. * It is stored per geom instance, rather than per dTriMeshDataID. */ ODE_API void dGeomTriMeshSetLastTransform( dGeomID g, dMatrix4 last_trans ); ODE_API dReal* dGeomTriMeshGetLastTransform( dGeomID g ); /* * Build a TriMesh data object with single precision vertex data. */ ODE_API void dGeomTriMeshDataBuildSingle(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride); /* same again with a normals array (used as trimesh-trimesh optimization) */ ODE_API void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride, const void* Normals); /* * Build a TriMesh data object with double precision vertex data. */ ODE_API void dGeomTriMeshDataBuildDouble(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride); /* same again with a normals array (used as trimesh-trimesh optimization) */ ODE_API void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g, const void* Vertices, int VertexStride, int VertexCount, const void* Indices, int IndexCount, int TriStride, const void* Normals); /* * Simple build. Single/double precision based on dSINGLE/dDOUBLE! */ ODE_API void dGeomTriMeshDataBuildSimple(dTriMeshDataID g, const dReal* Vertices, int VertexCount, const dTriIndex* Indices, int IndexCount); /* same again with a normals array (used as trimesh-trimesh optimization) */ ODE_API void dGeomTriMeshDataBuildSimple1(dTriMeshDataID g, const dReal* Vertices, int VertexCount, const dTriIndex* Indices, int IndexCount, const int* Normals); /* Preprocess the trimesh data to remove mark unnecessary edges and vertices */ ODE_API void dGeomTriMeshDataPreprocess(dTriMeshDataID g); /* Get and set the internal preprocessed trimesh data buffer, for loading and saving */ ODE_API void dGeomTriMeshDataGetBuffer(dTriMeshDataID g, unsigned char** buf, int* bufLen); ODE_API void dGeomTriMeshDataSetBuffer(dTriMeshDataID g, unsigned char* buf); /* * Per triangle callback. Allows the user to say if he wants a collision with * a particular triangle. */ typedef int dTriCallback(dGeomID TriMesh, dGeomID RefObject, int TriangleIndex); ODE_API void dGeomTriMeshSetCallback(dGeomID g, dTriCallback* Callback); ODE_API dTriCallback* dGeomTriMeshGetCallback(dGeomID g); /* * Per object callback. Allows the user to get the list of triangles in 1 * shot. Maybe we should remove this one. */ typedef void dTriArrayCallback(dGeomID TriMesh, dGeomID RefObject, const int* TriIndices, int TriCount); ODE_API void dGeomTriMeshSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback); ODE_API dTriArrayCallback* dGeomTriMeshGetArrayCallback(dGeomID g); /* * Ray callback. * Allows the user to say if a ray collides with a triangle on barycentric * coords. The user can for example sample a texture with alpha transparency * to determine if a collision should occur. */ typedef int dTriRayCallback(dGeomID TriMesh, dGeomID Ray, int TriangleIndex, dReal u, dReal v); ODE_API void dGeomTriMeshSetRayCallback(dGeomID g, dTriRayCallback* Callback); ODE_API dTriRayCallback* dGeomTriMeshGetRayCallback(dGeomID g); /* * Triangle merging callback. * Allows the user to generate a fake triangle index for a new contact generated * from merging of two other contacts. That index could later be used by the * user to determine attributes of original triangles used as sources for a * merged contact. */ typedef int dTriTriMergeCallback(dGeomID TriMesh, int FirstTriangleIndex, int SecondTriangleIndex); ODE_API void dGeomTriMeshSetTriMergeCallback(dGeomID g, dTriTriMergeCallback* Callback); ODE_API dTriTriMergeCallback* dGeomTriMeshGetTriMergeCallback(dGeomID g); /* * Trimesh class * Construction. Callbacks are optional. */ ODE_API dGeomID dCreateTriMesh(dSpaceID space, dTriMeshDataID Data, dTriCallback* Callback, dTriArrayCallback* ArrayCallback, dTriRayCallback* RayCallback); ODE_API void dGeomTriMeshSetData(dGeomID g, dTriMeshDataID Data); ODE_API dTriMeshDataID dGeomTriMeshGetData(dGeomID g); /* enable/disable/check temporal coherence*/ ODE_API void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable); ODE_API int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass); /* * Clears the internal temporal coherence caches. When a geom has its * collision checked with a trimesh once, data is stored inside the trimesh. * With large worlds with lots of seperate objects this list could get huge. * We should be able to do this automagically. */ ODE_API void dGeomTriMeshClearTCCache(dGeomID g); /* * returns the TriMeshDataID */ ODE_API dTriMeshDataID dGeomTriMeshGetTriMeshDataID(dGeomID g); /* * Gets a triangle. */ ODE_API void dGeomTriMeshGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2); /* * Gets the point on the requested triangle and the given barycentric * coordinates. */ ODE_API void dGeomTriMeshGetPoint(dGeomID g, int Index, dReal u, dReal v, dVector3 Out); /* This is how the strided data works: struct StridedVertex{ dVector3 Vertex; // Userdata }; int VertexStride = sizeof(StridedVertex); struct StridedTri{ int Indices[3]; // Userdata }; int TriStride = sizeof(StridedTri); */ ODE_API int dGeomTriMeshGetTriangleCount (dGeomID g); ODE_API void dGeomTriMeshDataUpdate(dTriMeshDataID g); #ifdef __cplusplus } #endif #endif /* _ODE_COLLISION_TRIMESH_H_ */ ode-0.14/include/ode/common.h0000644000000000000000000002540312635011627014545 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_COMMON_H_ #define _ODE_COMMON_H_ #include #include #ifdef __cplusplus extern "C" { #endif /* configuration stuff */ /* constants */ /* pi and 1/sqrt(2) are defined here if necessary because they don't get * defined in on some platforms (like MS-Windows) */ #ifndef M_PI #define M_PI REAL(3.1415926535897932384626433832795029) #endif #ifndef M_PI_2 #define M_PI_2 REAL(1.5707963267948966192313216916398) #endif #ifndef M_SQRT1_2 #define M_SQRT1_2 REAL(0.7071067811865475244008443621048490) #endif /* floating point data type, vector, matrix and quaternion types */ #if defined(dSINGLE) typedef float dReal; #ifdef dDOUBLE #error You can only #define dSINGLE or dDOUBLE, not both. #endif /* dDOUBLE */ #elif defined(dDOUBLE) typedef double dReal; #else #error You must #define dSINGLE or dDOUBLE #endif /* Detect if we've got both trimesh engines enabled. */ #if dTRIMESH_ENABLED #if dTRIMESH_OPCODE && dTRIMESH_GIMPACT #error You can only #define dTRIMESH_OPCODE or dTRIMESH_GIMPACT, not both. #endif #endif /* dTRIMESH_ENABLED */ /* * Define a type for indices, either 16 or 32 bit, based on build option * TODO: Currently GIMPACT only supports 32 bit indices. */ #if dTRIMESH_16BIT_INDICES #if dTRIMESH_GIMPACT typedef duint32 dTriIndex; #else /* dTRIMESH_GIMPACT */ typedef duint16 dTriIndex; #endif /* dTRIMESH_GIMPACT */ #else /* dTRIMESH_16BIT_INDICES */ typedef duint32 dTriIndex; #endif /* dTRIMESH_16BIT_INDICES */ /* round an integer up to a multiple of 4, except that 0 and 1 are unmodified * (used to compute matrix leading dimensions) */ #define dPAD(a) (((a) > 1) ? ((((a)-1)|3)+1) : (a)) /* these types are mainly just used in headers */ typedef dReal dVector3[4]; typedef dReal dVector4[4]; typedef dReal dMatrix3[4*3]; typedef dReal dMatrix4[4*4]; typedef dReal dMatrix6[8*6]; typedef dReal dQuaternion[4]; /* precision dependent scalar math functions */ #if defined(dSINGLE) #define REAL(x) (x##f) /* form a constant */ #define dRecip(x) ((1.0f/(x))) /* reciprocal */ #define dSqrt(x) (sqrtf(x)) /* square root */ #define dRecipSqrt(x) ((1.0f/sqrtf(x))) /* reciprocal square root */ #define dSin(x) (sinf(x)) /* sine */ #define dCos(x) (cosf(x)) /* cosine */ #define dFabs(x) (fabsf(x)) /* absolute value */ #define dAtan2(y,x) (atan2f(y,x)) /* arc tangent with 2 args */ #define dAcos(x) (acosf(x)) #define dFMod(a,b) (fmodf(a,b)) /* modulo */ #define dFloor(x) floorf(x) /* floor */ #define dCeil(x) ceilf(x) /* ceil */ #define dCopySign(a,b) _ode_copysignf(a, b) /* copy value sign */ #define dNextAfter(x, y) _ode_nextafterf(x, y) /* next value after */ #ifdef HAVE___ISNANF #define dIsNan(x) (__isnanf(x)) #elif defined(HAVE__ISNANF) #define dIsNan(x) (_isnanf(x)) #elif defined(HAVE_ISNANF) #define dIsNan(x) (isnanf(x)) #else /* fall back to _isnan which is the VC way, this may seem redundant since we already checked for _isnan before, but if isnan is detected by configure but is not found during compilation we should always make sure we check for __isnanf, _isnanf and isnanf in that order before falling back to a default */ #define dIsNan(x) (_isnan(x)) #endif #elif defined(dDOUBLE) #define REAL(x) (x) #define dRecip(x) (1.0/(x)) #define dSqrt(x) sqrt(x) #define dRecipSqrt(x) (1.0/sqrt(x)) #define dSin(x) sin(x) #define dCos(x) cos(x) #define dFabs(x) fabs(x) #define dAtan2(y,x) atan2((y),(x)) #define dAcos(x) acos(x) #define dFMod(a,b) (fmod((a),(b))) #define dFloor(x) floor(x) #define dCeil(x) ceil(x) #define dCopySign(a,b) _ode_copysign(a, b) #define dNextAfter(x, y) _ode_nextafter(x, y) #ifdef HAVE___ISNAN #define dIsNan(x) (__isnan(x)) #elif defined(HAVE__ISNAN) #define dIsNan(x) (_isnan(x)) #elif defined(HAVE_ISNAN) #define dIsNan(x) (isnan(x)) #else #define dIsNan(x) (_isnan(x)) #endif #else #error You must #define dSINGLE or dDOUBLE #endif /* internal object types (all prefixed with `dx') */ struct dxWorld; /* dynamics world */ struct dxSpace; /* collision space */ struct dxBody; /* rigid body (dynamics object) */ struct dxGeom; /* geometry (collision object) */ struct dxJoint; struct dxJointNode; struct dxJointGroup; struct dxWorldProcessThreadingManager; typedef struct dxWorld *dWorldID; typedef struct dxSpace *dSpaceID; typedef struct dxBody *dBodyID; typedef struct dxGeom *dGeomID; typedef struct dxJoint *dJointID; typedef struct dxJointGroup *dJointGroupID; typedef struct dxWorldProcessThreadingManager *dWorldStepThreadingManagerID; /* error numbers */ enum { d_ERR_UNKNOWN = 0, /* unknown error */ d_ERR_IASSERT, /* internal assertion failed */ d_ERR_UASSERT, /* user assertion failed */ d_ERR_LCP /* user assertion failed */ }; /* joint type numbers */ typedef enum { dJointTypeNone = 0, /* or "unknown" */ dJointTypeBall, dJointTypeHinge, dJointTypeSlider, dJointTypeContact, dJointTypeUniversal, dJointTypeHinge2, dJointTypeFixed, dJointTypeNull, dJointTypeAMotor, dJointTypeLMotor, dJointTypePlane2D, dJointTypePR, dJointTypePU, dJointTypePiston, dJointTypeDBall, dJointTypeDHinge, dJointTypeTransmission, } dJointType; /* an alternative way of setting joint parameters, using joint parameter * structures and member constants. we don't actually do this yet. */ /* typedef struct dLimot { int mode; dReal lostop, histop; dReal vel, fmax; dReal fudge_factor; dReal bounce, soft; dReal suspension_erp, suspension_cfm; } dLimot; enum { dLimotLoStop = 0x0001, dLimotHiStop = 0x0002, dLimotVel = 0x0004, dLimotFMax = 0x0008, dLimotFudgeFactor = 0x0010, dLimotBounce = 0x0020, dLimotSoft = 0x0040 }; */ /* standard joint parameter names. why are these here? - because we don't want * to include all the joint function definitions in joint.cpp. hmmmm. * MSVC complains if we call D_ALL_PARAM_NAMES_X with a blank second argument, * which is why we have the D_ALL_PARAM_NAMES macro as well. please copy and * paste between these two. */ #define D_ALL_PARAM_NAMES(start) \ /* parameters for limits and motors */ \ dParamLoStop = start, \ dParamHiStop, \ dParamVel, \ dParamLoVel, \ dParamHiVel, \ dParamFMax, \ dParamFudgeFactor, \ dParamBounce, \ dParamCFM, \ dParamStopERP, \ dParamStopCFM, \ /* parameters for suspension */ \ dParamSuspensionERP, \ dParamSuspensionCFM, \ dParamERP, \ /* * \enum D_ALL_PARAM_NAMES_X * * \var dParamGroup This is the starting value of the different group * (i.e. dParamGroup1, dParamGroup2, dParamGroup3) * It also helps in the use of parameter * (dParamGroup2 | dParamFMax) == dParamFMax2 */ #define D_ALL_PARAM_NAMES_X(start,x) \ dParamGroup ## x = start, \ /* parameters for limits and motors */ \ dParamLoStop ## x = start, \ dParamHiStop ## x, \ dParamVel ## x, \ dParamLoVel ## x, \ dParamHiVel ## x, \ dParamFMax ## x, \ dParamFudgeFactor ## x, \ dParamBounce ## x, \ dParamCFM ## x, \ dParamStopERP ## x, \ dParamStopCFM ## x, \ /* parameters for suspension */ \ dParamSuspensionERP ## x, \ dParamSuspensionCFM ## x, \ dParamERP ## x, enum { D_ALL_PARAM_NAMES(0) dParamsInGroup, /* < Number of parameter in a group */ D_ALL_PARAM_NAMES_X(0x000,1) D_ALL_PARAM_NAMES_X(0x100,2) D_ALL_PARAM_NAMES_X(0x200,3) /* add a multiple of this constant to the basic parameter numbers to get * the parameters for the second, third etc axes. */ dParamGroup=0x100 }; /* angular motor mode numbers */ enum { dAMotorUser = 0, dAMotorEuler = 1 }; /* transmission joint mode numbers */ enum { dTransmissionParallelAxes = 0, dTransmissionIntersectingAxes = 1, dTransmissionChainDrive = 2 }; /* joint force feedback information */ typedef struct dJointFeedback { dVector3 f1; /* force applied to body 1 */ dVector3 t1; /* torque applied to body 1 */ dVector3 f2; /* force applied to body 2 */ dVector3 t2; /* torque applied to body 2 */ } dJointFeedback; /* private functions that must be implemented by the collision library: * (1) indicate that a geom has moved, (2) get the next geom in a body list. * these functions are called whenever the position of geoms connected to a * body have changed, e.g. with dBodySetPosition(), dBodySetRotation(), or * when the ODE step function updates the body state. */ void dGeomMoved (dGeomID); dGeomID dGeomGetBodyNext (dGeomID); /** * dGetConfiguration returns the specific ODE build configuration as * a string of tokens. The string can be parsed in a similar way to * the OpenGL extension mechanism, the naming convention should be * familiar too. The following extensions are reported: * * ODE * ODE_single_precision * ODE_double_precision * ODE_EXT_no_debug * ODE_EXT_trimesh * ODE_EXT_opcode * ODE_EXT_gimpact * ODE_OPC_16bit_indices * ODE_OPC_new_collider * ODE_EXT_mt_collisions * ODE_EXT_threading * ODE_THR_builtin_impl */ ODE_API const char* dGetConfiguration (void); /** * Helper to check for a token in the ODE configuration string. * Caution, this function is case sensitive. * * @param token A configuration token, see dGetConfiguration for details * * @return 1 if exact token is present, 0 if not present */ ODE_API int dCheckConfiguration( const char* token ); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/compatibility.h0000644000000000000000000000366112635011627016130 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_COMPATIBILITY_H_ #define _ODE_COMPATIBILITY_H_ /* * ODE's backward compatibility system ensures that as ODE's API * evolves, user code will not break. */ /* * These new rotation function names are more consistent with the * rest of the API. */ #define dQtoR(q,R) dRfromQ((R),(q)) #define dRtoQ(R,q) dQfromR((q),(R)) #define dWtoDQ(w,q,dq) dDQfromW((dq),(w),(q)) #endif ode-0.14/include/ode/contact.h0000644000000000000000000001021312635011627014701 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_CONTACT_H_ #define _ODE_CONTACT_H_ #include #ifdef __cplusplus extern "C" { #endif enum { dContactMu2 = 0x001, /**< Use axis dependent friction */ dContactAxisDep = 0x001, /**< Same as above */ dContactFDir1 = 0x002, /**< Use FDir for the first friction value */ dContactBounce = 0x004, /**< Restore collision energy anti-parallel to the normal */ dContactSoftERP = 0x008, /**< Don't use global erp for penetration reduction */ dContactSoftCFM = 0x010, /**< Don't use global cfm for penetration constraint */ dContactMotion1 = 0x020, /**< Use a non-zero target velocity for the constraint */ dContactMotion2 = 0x040, dContactMotionN = 0x080, dContactSlip1 = 0x100, /**< Force-dependent slip. */ dContactSlip2 = 0x200, dContactRolling = 0x400, /**< Rolling/Angular friction */ dContactApprox0 = 0x0000, dContactApprox1_1 = 0x1000, dContactApprox1_2 = 0x2000, dContactApprox1_N = 0x4000, /**< For rolling friction */ dContactApprox1 = 0x7000 }; typedef struct dSurfaceParameters { /* must always be defined */ int mode; dReal mu; /* only defined if the corresponding flag is set in mode */ dReal mu2; dReal rho; /**< Rolling friction */ dReal rho2; dReal rhoN; /**< Spinning friction */ dReal bounce; /**< Coefficient of restitution */ dReal bounce_vel; /**< Bouncing threshold */ dReal soft_erp; dReal soft_cfm; dReal motion1,motion2,motionN; dReal slip1,slip2; } dSurfaceParameters; /** * @brief Describe the contact point between two geoms. * * If two bodies touch, or if a body touches a static feature in its * environment, the contact is represented by one or more "contact * points", described by dContactGeom. * * The convention is that if body 1 is moved along the normal vector by * a distance depth (or equivalently if body 2 is moved the same distance * in the opposite direction) then the contact depth will be reduced to * zero. This means that the normal vector points "in" to body 1. * * @ingroup collide */ typedef struct dContactGeom { dVector3 pos; /*< contact position*/ dVector3 normal; /*< normal vector*/ dReal depth; /*< penetration depth*/ dGeomID g1,g2; /*< the colliding geoms*/ int side1,side2; /*< (to be documented)*/ } dContactGeom; /* contact info used by contact joint */ typedef struct dContact { dSurfaceParameters surface; dContactGeom geom; dVector3 fdir1; } dContact; #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/error.h0000644000000000000000000000526312635011627014410 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* this comes from the `reuse' library. copy any changes back to the source */ #ifndef _ODE_ERROR_H_ #define _ODE_ERROR_H_ #include #ifdef __cplusplus extern "C" { #endif /* all user defined error functions have this type. error and debug functions * should not return. */ typedef void dMessageFunction (int errnum, const char *msg, va_list ap); /* set a new error, debug or warning handler. if fn is 0, the default handlers * are used. */ ODE_API void dSetErrorHandler (dMessageFunction *fn); ODE_API void dSetDebugHandler (dMessageFunction *fn); ODE_API void dSetMessageHandler (dMessageFunction *fn); /* return the current error, debug or warning handler. if the return value is * 0, the default handlers are in place. */ ODE_API dMessageFunction *dGetErrorHandler(void); ODE_API dMessageFunction *dGetDebugHandler(void); ODE_API dMessageFunction *dGetMessageHandler(void); /* generate a fatal error, debug trap or a message. */ ODE_API void dError (int num, const char *msg, ...); ODE_API void dDebug (int num, const char *msg, ...); ODE_API void dMessage (int num, const char *msg, ...); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/export-dif.h0000644000000000000000000000342312635011627015334 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_EXPORT_DIF_ #define _ODE_EXPORT_DIF_ #include #ifdef __cplusplus extern "C" { #endif ODE_API void dWorldExportDIF (dWorldID w, FILE *file, const char *world_name); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/mass.h0000644000000000000000000001247512635011627014225 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_MASS_H_ #define _ODE_MASS_H_ #include #ifdef __cplusplus extern "C" { #endif struct dMass; typedef struct dMass dMass; /** * Check if a mass structure has valid value. * The function check if the mass and innertia matrix are positive definits * * @param m A mass structure to check * * @return 1 if both codition are met */ ODE_API int dMassCheck(const dMass *m); ODE_API void dMassSetZero (dMass *); ODE_API void dMassSetParameters (dMass *, dReal themass, dReal cgx, dReal cgy, dReal cgz, dReal I11, dReal I22, dReal I33, dReal I12, dReal I13, dReal I23); ODE_API void dMassSetSphere (dMass *, dReal density, dReal radius); ODE_API void dMassSetSphereTotal (dMass *, dReal total_mass, dReal radius); ODE_API void dMassSetCapsule (dMass *, dReal density, int direction, dReal radius, dReal length); ODE_API void dMassSetCapsuleTotal (dMass *, dReal total_mass, int direction, dReal radius, dReal length); ODE_API void dMassSetCylinder (dMass *, dReal density, int direction, dReal radius, dReal length); ODE_API void dMassSetCylinderTotal (dMass *, dReal total_mass, int direction, dReal radius, dReal length); ODE_API void dMassSetBox (dMass *, dReal density, dReal lx, dReal ly, dReal lz); ODE_API void dMassSetBoxTotal (dMass *, dReal total_mass, dReal lx, dReal ly, dReal lz); ODE_API void dMassSetTrimesh (dMass *, dReal density, dGeomID g); ODE_API void dMassSetTrimeshTotal (dMass *m, dReal total_mass, dGeomID g); ODE_API void dMassAdjust (dMass *, dReal newmass); ODE_API void dMassTranslate (dMass *, dReal x, dReal y, dReal z); ODE_API void dMassRotate (dMass *, const dMatrix3 R); ODE_API void dMassAdd (dMass *a, const dMass *b); /* Backwards compatible API */ ODE_API ODE_API_DEPRECATED void dMassSetCappedCylinder(dMass *a, dReal b, int c, dReal d, dReal e); ODE_API ODE_API_DEPRECATED void dMassSetCappedCylinderTotal(dMass *a, dReal b, int c, dReal d, dReal e); struct dMass { dReal mass; dVector3 c; dMatrix3 I; #ifdef __cplusplus dMass() { dMassSetZero (this); } void setZero() { dMassSetZero (this); } void setParameters (dReal themass, dReal cgx, dReal cgy, dReal cgz, dReal I11, dReal I22, dReal I33, dReal I12, dReal I13, dReal I23) { dMassSetParameters (this,themass,cgx,cgy,cgz,I11,I22,I33,I12,I13,I23); } void setSphere (dReal density, dReal radius) { dMassSetSphere (this,density,radius); } void setSphereTotal (dReal total, dReal radius) { dMassSetSphereTotal (this,total,radius); } void setCapsule (dReal density, int direction, dReal radius, dReal length) { dMassSetCapsule (this,density,direction,radius,length); } void setCapsuleTotal (dReal total, int direction, dReal radius, dReal length) { dMassSetCapsule (this,total,direction,radius,length); } void setCylinder(dReal density, int direction, dReal radius, dReal length) { dMassSetCylinder (this,density,direction,radius,length); } void setCylinderTotal(dReal total, int direction, dReal radius, dReal length) { dMassSetCylinderTotal (this,total,direction,radius,length); } void setBox (dReal density, dReal lx, dReal ly, dReal lz) { dMassSetBox (this,density,lx,ly,lz); } void setBoxTotal (dReal total, dReal lx, dReal ly, dReal lz) { dMassSetBoxTotal (this,total,lx,ly,lz); } void setTrimesh(dReal density, dGeomID g) { dMassSetTrimesh (this, density, g); } void setTrimeshTotal(dReal total, dGeomID g) { dMassSetTrimeshTotal (this, total, g); } void adjust (dReal newmass) { dMassAdjust (this,newmass); } void translate (dReal x, dReal y, dReal z) { dMassTranslate (this,x,y,z); } void rotate (const dMatrix3 R) { dMassRotate (this,R); } void add (const dMass *b) { dMassAdd (this,b); } #endif }; #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/matrix.h0000644000000000000000000001721512635011627014563 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* optimized and unoptimized vector and matrix functions */ #ifndef _ODE_MATRIX_H_ #define _ODE_MATRIX_H_ #include #ifdef __cplusplus extern "C" { #endif /* set a vector/matrix of size n to all zeros, or to a specific value. */ ODE_API void dSetZero (dReal *a, int n); ODE_API void dSetValue (dReal *a, int n, dReal value); /* get the dot product of two n*1 vectors. if n <= 0 then * zero will be returned (in which case a and b need not be valid). */ ODE_API dReal dDot (const dReal *a, const dReal *b, int n); /* get the dot products of (a0,b), (a1,b), etc and return them in outsum. * all vectors are n*1. if n <= 0 then zeroes will be returned (in which case * the input vectors need not be valid). this function is somewhat faster * than calling dDot() for all of the combinations separately. */ /* NOT INCLUDED in the library for now. void dMultidot2 (const dReal *a0, const dReal *a1, const dReal *b, dReal *outsum, int n); */ /* matrix multiplication. all matrices are stored in standard row format. * the digit refers to the argument that is transposed: * 0: A = B * C (sizes: A:p*r B:p*q C:q*r) * 1: A = B' * C (sizes: A:p*r B:q*p C:q*r) * 2: A = B * C' (sizes: A:p*r B:p*q C:r*q) * case 1,2 are equivalent to saying that the operation is A=B*C but * B or C are stored in standard column format. */ ODE_API void dMultiply0 (dReal *A, const dReal *B, const dReal *C, int p,int q,int r); ODE_API void dMultiply1 (dReal *A, const dReal *B, const dReal *C, int p,int q,int r); ODE_API void dMultiply2 (dReal *A, const dReal *B, const dReal *C, int p,int q,int r); /* do an in-place cholesky decomposition on the lower triangle of the n*n * symmetric matrix A (which is stored by rows). the resulting lower triangle * will be such that L*L'=A. return 1 on success and 0 on failure (on failure * the matrix is not positive definite). */ ODE_API int dFactorCholesky (dReal *A, int n); /* solve for x: L*L'*x = b, and put the result back into x. * L is size n*n, b is size n*1. only the lower triangle of L is considered. */ ODE_API void dSolveCholesky (const dReal *L, dReal *b, int n); /* compute the inverse of the n*n positive definite matrix A and put it in * Ainv. this is not especially fast. this returns 1 on success (A was * positive definite) or 0 on failure (not PD). */ ODE_API int dInvertPDMatrix (const dReal *A, dReal *Ainv, int n); /* check whether an n*n matrix A is positive definite, return 1/0 (yes/no). * positive definite means that x'*A*x > 0 for any x. this performs a * cholesky decomposition of A. if the decomposition fails then the matrix * is not positive definite. A is stored by rows. A is not altered. */ ODE_API int dIsPositiveDefinite (const dReal *A, int n); /* factorize a matrix A into L*D*L', where L is lower triangular with ones on * the diagonal, and D is diagonal. * A is an n*n matrix stored by rows, with a leading dimension of n rounded * up to 4. L is written into the strict lower triangle of A (the ones are not * written) and the reciprocal of the diagonal elements of D are written into * d. */ ODE_API void dFactorLDLT (dReal *A, dReal *d, int n, int nskip); /* solve L*x=b, where L is n*n lower triangular with ones on the diagonal, * and x,b are n*1. b is overwritten with x. * the leading dimension of L is `nskip'. */ ODE_API void dSolveL1 (const dReal *L, dReal *b, int n, int nskip); /* solve L'*x=b, where L is n*n lower triangular with ones on the diagonal, * and x,b are n*1. b is overwritten with x. * the leading dimension of L is `nskip'. */ ODE_API void dSolveL1T (const dReal *L, dReal *b, int n, int nskip); /* in matlab syntax: a(1:n) = a(1:n) .* d(1:n) */ ODE_API void dVectorScale (dReal *a, const dReal *d, int n); /* given `L', a n*n lower triangular matrix with ones on the diagonal, * and `d', a n*1 vector of the reciprocal diagonal elements of an n*n matrix * D, solve L*D*L'*x=b where x,b are n*1. x overwrites b. * the leading dimension of L is `nskip'. */ ODE_API void dSolveLDLT (const dReal *L, const dReal *d, dReal *b, int n, int nskip); /* given an L*D*L' factorization of an n*n matrix A, return the updated * factorization L2*D2*L2' of A plus the following "top left" matrix: * * [ b a' ] <-- b is a[0] * [ a 0 ] <-- a is a[1..n-1] * * - L has size n*n, its leading dimension is nskip. L is lower triangular * with ones on the diagonal. only the lower triangle of L is referenced. * - d has size n. d contains the reciprocal diagonal elements of D. * - a has size n. * the result is written into L, except that the left column of L and d[0] * are not actually modified. see ldltaddTL.m for further comments. */ ODE_API void dLDLTAddTL (dReal *L, dReal *d, const dReal *a, int n, int nskip); /* given an L*D*L' factorization of a permuted matrix A, produce a new * factorization for row and column `r' removed. * - A has size n1*n1, its leading dimension in nskip. A is symmetric and * positive definite. only the lower triangle of A is referenced. * A itself may actually be an array of row pointers. * - L has size n2*n2, its leading dimension in nskip. L is lower triangular * with ones on the diagonal. only the lower triangle of L is referenced. * - d has size n2. d contains the reciprocal diagonal elements of D. * - p is a permutation vector. it contains n2 indexes into A. each index * must be in the range 0..n1-1. * - r is the row/column of L to remove. * the new L will be written within the old L, i.e. will have the same leading * dimension. the last row and column of L, and the last element of d, are * undefined on exit. * * a fast O(n^2) algorithm is used. see ldltremove.m for further comments. */ ODE_API void dLDLTRemove (dReal **A, const int *p, dReal *L, dReal *d, int n1, int n2, int r, int nskip); /* given an n*n matrix A (with leading dimension nskip), remove the r'th row * and column by moving elements. the new matrix will have the same leading * dimension. the last row and column of A are untouched on exit. */ ODE_API void dRemoveRowCol (dReal *A, int n, int nskip, int r); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/memory.h0000644000000000000000000000514512635011627014566 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* this comes from the `reuse' library. copy any changes back to the source */ #ifndef _ODE_MEMORY_H_ #define _ODE_MEMORY_H_ #include #ifdef __cplusplus extern "C" { #endif /* function types to allocate and free memory */ typedef void * dAllocFunction (size_t size); typedef void * dReallocFunction (void *ptr, size_t oldsize, size_t newsize); typedef void dFreeFunction (void *ptr, size_t size); /* set new memory management functions. if fn is 0, the default handlers are * used. */ ODE_API void dSetAllocHandler (dAllocFunction *fn); ODE_API void dSetReallocHandler (dReallocFunction *fn); ODE_API void dSetFreeHandler (dFreeFunction *fn); /* get current memory management functions */ ODE_API dAllocFunction *dGetAllocHandler (void); ODE_API dReallocFunction *dGetReallocHandler (void); ODE_API dFreeFunction *dGetFreeHandler (void); /* allocate and free memory. */ ODE_API void * dAlloc (size_t size); ODE_API void * dRealloc (void *ptr, size_t oldsize, size_t newsize); ODE_API void dFree (void *ptr, size_t size); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/misc.h0000644000000000000000000000644212635011627014212 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* miscellaneous math functions. these are mostly useful for testing */ #ifndef _ODE_MISC_H_ #define _ODE_MISC_H_ #include #ifdef __cplusplus extern "C" { #endif /* return 1 if the random number generator is working. */ ODE_API int dTestRand(void); /* return next 32 bit random number. this uses a not-very-random linear * congruential method. */ ODE_API unsigned long dRand(void); /* get and set the current random number seed. */ ODE_API unsigned long dRandGetSeed(void); ODE_API void dRandSetSeed (unsigned long s); /* return a random integer between 0..n-1. the distribution will get worse * as n approaches 2^32. */ ODE_API int dRandInt (int n); /* return a random real number between 0..1 */ ODE_API dReal dRandReal(void); /* print out a matrix */ ODE_API void dPrintMatrix (const dReal *A, int n, int m, const char *fmt, FILE *f); /* make a random vector with entries between +/- range. A has n elements. */ ODE_API void dMakeRandomVector (dReal *A, int n, dReal range); /* make a random matrix with entries between +/- range. A has size n*m. */ ODE_API void dMakeRandomMatrix (dReal *A, int n, int m, dReal range); /* clear the upper triangle of a square matrix */ ODE_API void dClearUpperTriangle (dReal *A, int n); /* return the maximum element difference between the two n*m matrices */ ODE_API dReal dMaxDifference (const dReal *A, const dReal *B, int n, int m); /* return the maximum element difference between the lower triangle of two * n*n matrices */ ODE_API dReal dMaxDifferenceLowerTriangle (const dReal *A, const dReal *B, int n); #ifdef __cplusplus } #endif #ifdef __cplusplus static inline void dPrintMatrix (const dReal *A, int n, int m, const char *fmt="%10.4f ") { dPrintMatrix(A, n, m, fmt, stdout); } #endif #endif ode-0.14/include/ode/objects.h0000644000000000000000000032103512635011627014706 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_OBJECTS_H_ #define _ODE_OBJECTS_H_ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @defgroup world World * * The world object is a container for rigid bodies and joints. Objects in * different worlds can not interact, for example rigid bodies from two * different worlds can not collide. * * All the objects in a world exist at the same point in time, thus one * reason to use separate worlds is to simulate systems at different rates. * Most applications will only need one world. */ /** * @brief Create a new, empty world and return its ID number. * @return an identifier * @ingroup world */ ODE_API dWorldID dWorldCreate(void); /** * @brief Destroy a world and everything in it. * * This includes all bodies, and all joints that are not part of a joint * group. Joints that are part of a joint group will be deactivated, and * can be destroyed by calling, for example, dJointGroupEmpty(). * @ingroup world * @param world the identifier for the world the be destroyed. */ ODE_API void dWorldDestroy (dWorldID world); /** * @brief Set the user-data pointer * @param world the world to set the data on * @param data * @ingroup world */ ODE_API void dWorldSetData (dWorldID world, void* data); /** * @brief Get the user-data pointer * @param world the world to set the data on * @param data * @ingroup world */ ODE_API void* dWorldGetData (dWorldID world); /** * @brief Set the world's global gravity vector. * * The units are m/s^2, so Earth's gravity vector would be (0,0,-9.81), * assuming that +z is up. The default is no gravity, i.e. (0,0,0). * * @ingroup world */ ODE_API void dWorldSetGravity (dWorldID, dReal x, dReal y, dReal z); /** * @brief Get the gravity vector for a given world. * @ingroup world */ ODE_API void dWorldGetGravity (dWorldID, dVector3 gravity); /** * @brief Set the global ERP value, that controls how much error * correction is performed in each time step. * @ingroup world * @param dWorldID the identifier of the world. * @param erp Typical values are in the range 0.1--0.8. The default is 0.2. */ ODE_API void dWorldSetERP (dWorldID, dReal erp); /** * @brief Get the error reduction parameter. * @ingroup world * @return ERP value */ ODE_API dReal dWorldGetERP (dWorldID); /** * @brief Set the global CFM (constraint force mixing) value. * @ingroup world * @param cfm Typical values are in the range @m{10^{-9}} -- 1. * The default is 10^-5 if single precision is being used, or 10^-10 * if double precision is being used. */ ODE_API void dWorldSetCFM (dWorldID, dReal cfm); /** * @brief Get the constraint force mixing value. * @ingroup world * @return CFM value */ ODE_API dReal dWorldGetCFM (dWorldID); #define dWORLDSTEP_THREADCOUNT_UNLIMITED 0U /** * @brief Set maximum threads to be used for island stepping * * The actual number of threads that is going to be used will be the minimum * of this limit and number of threads in the threading pool. By default * there is no limit (@c dWORLDSTEP_THREADCOUNT_UNLIMITED). * * @warning * WARNING! Running island stepping in multiple threads requires allocating * individual stepping memory buffer for each of those threads. The size of buffers * allocated is the size needed to handle the largest island in the world. * * Note: Setting a limit for island stepping does not affect threading at lower * levels in stepper functions. The sub-calls scheduled from them can be executed * in as many threads as there are available in the pool. * * @param w The world affected * @param count Thread count limit value for island stepping * @ingroup world * @see dWorldGetStepIslandsProcessingMaxThreadCount */ ODE_API void dWorldSetStepIslandsProcessingMaxThreadCount(dWorldID w, unsigned count); /** * @brief Get maximum threads that are allowed to be used for island stepping. * * Please read commentaries to @c dWorldSetStepIslandsProcessingMaxThreadCount for * important information regarding the value returned. * * @param w The world queried * @returns Current thread count limit value for island stepping * @ingroup world * @see dWorldSetStepIslandsProcessingMaxThreadCount */ ODE_API unsigned dWorldGetStepIslandsProcessingMaxThreadCount(dWorldID w); /** * @brief Set the world to use shared working memory along with another world. * * The worlds allocate working memory internally for simulation stepping. This * memory is cached among the calls to @c dWordStep and @c dWorldQuickStep. * Similarly, several worlds can be set up to share this memory caches thus * reducing overall memory usage by cost of making worlds inappropriate for * simultaneous simulation in multiple threads. * * If null value is passed for @a from_world parameter the world is detached from * sharing and returns to defaults for working memory, reservation policy and * memory manager as if just created. This can also be used to enable use of shared * memory for a world that has already had working memory allocated privately. * Normally using shared memory after a world has its private working memory allocated * is prohibited. * * Allocation policy used can only increase world's internal reserved memory size * and never decreases it. @c dWorldCleanupWorkingMemory can be used to release * working memory for a world in case if number of objects/joint decreases * significantly in it. * * With sharing working memory worlds also automatically share memory reservation * policy and memory manager. Thus, these parameters need to be customized for * initial world to be used as sharing source only. * * If worlds share working memory they must also use compatible threading implementations * (i.e. it is illegal for one world to perform stepping with self-threaded implementation * when the other world is assigned a multi-threaded implementation). * For more information read section about threading approaches in ODE. * * Failure result status means a memory allocation failure. * * @param w The world to use the shared memory with. * @param from_world Null or the world the shared memory is to be used from. * @returns 1 for success and 0 for failure. * * @ingroup world * @see dWorldCleanupWorkingMemory * @see dWorldSetStepMemoryReservationPolicy * @see dWorldSetStepMemoryManager */ ODE_API int dWorldUseSharedWorkingMemory(dWorldID w, dWorldID from_world/*=NULL*/); /** * @brief Release internal working memory allocated for world * * The worlds allocate working memory internally for simulation stepping. This * function can be used to free world's internal memory cache in case if number of * objects/joints in the world decreases significantly. By default, internal * allocation policy is used to only increase cache size as necessary and never * decrease it. * * If a world shares its working memory with other worlds the cache deletion * affects all the linked worlds. However the shared status itself remains intact. * * The function call does affect neither memory reservation policy nor memory manager. * * @param w The world to release working memory for. * * @ingroup world * @see dWorldUseSharedWorkingMemory * @see dWorldSetStepMemoryReservationPolicy * @see dWorldSetStepMemoryManager */ ODE_API void dWorldCleanupWorkingMemory(dWorldID w); #define dWORLDSTEP_RESERVEFACTOR_DEFAULT 1.2f #define dWORLDSTEP_RESERVESIZE_DEFAULT 65536U /** * @struct dWorldStepReserveInfo * @brief Memory reservation policy descriptor structure for world stepping functions. * * @c struct_size should be assigned the size of the structure. * * @c reserve_factor is a quotient that is multiplied by required memory size * to allocate extra reserve whenever reallocation is needed. * * @c reserve_minimum is a minimum size that is checked against whenever reallocation * is needed to allocate expected working memory minimum at once without extra * reallocations as number of bodies/joints grows. * * @ingroup world * @see dWorldSetStepMemoryReservationPolicy */ typedef struct { unsigned struct_size; float reserve_factor; /* Use float as precision does not matter here*/ unsigned reserve_minimum; } dWorldStepReserveInfo; /** * @brief Set memory reservation policy for world to be used with simulation stepping functions * * The function allows to customize reservation policy to be used for internal * memory which is allocated to aid simulation for a world. By default, values * of @c dWORLDSTEP_RESERVEFACTOR_DEFAULT and @c dWORLDSTEP_RESERVESIZE_DEFAULT * are used. * * Passing @a policyinfo argument as NULL results in reservation policy being * reset to defaults as if the world has been just created. The content of * @a policyinfo structure is copied internally and does not need to remain valid * after the call returns. * * If the world uses working memory sharing, changing memory reservation policy * affects all the worlds linked together. * * Failure result status means a memory allocation failure. * * @param w The world to change memory reservation policy for. * @param policyinfo Null or a pointer to policy descriptor structure. * @returns 1 for success and 0 for failure. * * @ingroup world * @see dWorldUseSharedWorkingMemory */ ODE_API int dWorldSetStepMemoryReservationPolicy(dWorldID w, const dWorldStepReserveInfo *policyinfo/*=NULL*/); /** * @struct dWorldStepMemoryFunctionsInfo * @brief World stepping memory manager descriptor structure * * This structure is intended to define the functions of memory manager to be used * with world stepping functions. * * @c struct_size should be assigned the size of the structure * * @c alloc_block is a function to allocate memory block of given size. * * @c shrink_block is a function to shrink existing memory block to a smaller size. * It must preserve the contents of block head while shrinking. The new block size * is guaranteed to be always less than the existing one. * * @c free_block is a function to delete existing memory block. * * @ingroup init * @see dWorldSetStepMemoryManager */ typedef struct { unsigned struct_size; void *(*alloc_block)(size_t block_size); void *(*shrink_block)(void *block_pointer, size_t block_current_size, size_t block_smaller_size); void (*free_block)(void *block_pointer, size_t block_current_size); } dWorldStepMemoryFunctionsInfo; /** * @brief Set memory manager for world to be used with simulation stepping functions * * The function allows to customize memory manager to be used for internal * memory allocation during simulation for a world. By default, @c dAlloc/@c dRealloc/@c dFree * based memory manager is used. * * Passing @a memfuncs argument as NULL results in memory manager being * reset to default one as if the world has been just created. The content of * @a memfuncs structure is copied internally and does not need to remain valid * after the call returns. * * If the world uses working memory sharing, changing memory manager * affects all the worlds linked together. * * Failure result status means a memory allocation failure. * * @param w The world to change memory reservation policy for. * @param memfuncs Null or a pointer to memory manager descriptor structure. * @returns 1 for success and 0 for failure. * * @ingroup world * @see dWorldUseSharedWorkingMemory */ ODE_API int dWorldSetStepMemoryManager(dWorldID w, const dWorldStepMemoryFunctionsInfo *memfuncs); /** * @brief Assign threading implementation to be used for [quick]stepping the world. * * @warning It is not recommended to assign the same threading implementation to * different worlds if they are going to be called in parallel. In particular this * makes resources preallocation for threaded calls to lose its sense. * Built-in threading implementation is likely to crash if misused this way. * * @param w The world to change threading implementation for. * @param functions_info Pointer to threading functions structure * @param threading_impl ID of threading implementation object * * @ingroup world */ ODE_API void dWorldSetStepThreadingImplementation(dWorldID w, const dThreadingFunctionsInfo *functions_info, dThreadingImplementationID threading_impl); /** * @brief Step the world. * * This uses a "big matrix" method that takes time on the order of m^3 * and memory on the order of m^2, where m is the total number of constraint * rows. For large systems this will use a lot of memory and can be very slow, * but this is currently the most accurate method. * * Failure result status means that the memory allocation has failed for operation. * In such a case all the objects remain in unchanged state and simulation can be * retried as soon as more memory is available. * * @param w The world to be stepped * @param stepsize The number of seconds that the simulation has to advance. * @returns 1 for success and 0 for failure * * @ingroup world */ ODE_API int dWorldStep (dWorldID w, dReal stepsize); /** * @brief Quick-step the world. * * This uses an iterative method that takes time on the order of m*N * and memory on the order of m, where m is the total number of constraint * rows N is the number of iterations. * For large systems this is a lot faster than dWorldStep(), * but it is less accurate. * * QuickStep is great for stacks of objects especially when the * auto-disable feature is used as well. * However, it has poor accuracy for near-singular systems. * Near-singular systems can occur when using high-friction contacts, motors, * or certain articulated structures. For example, a robot with multiple legs * sitting on the ground may be near-singular. * * There are ways to help overcome QuickStep's inaccuracy problems: * * \li Increase CFM. * \li Reduce the number of contacts in your system (e.g. use the minimum * number of contacts for the feet of a robot or creature). * \li Don't use excessive friction in the contacts. * \li Use contact slip if appropriate * \li Avoid kinematic loops (however, kinematic loops are inevitable in * legged creatures). * \li Don't use excessive motor strength. * \liUse force-based motors instead of velocity-based motors. * * Increasing the number of QuickStep iterations may help a little bit, but * it is not going to help much if your system is really near singular. * * Failure result status means that the memory allocation has failed for operation. * In such a case all the objects remain in unchanged state and simulation can be * retried as soon as more memory is available. * * @param w The world to be stepped * @param stepsize The number of seconds that the simulation has to advance. * @returns 1 for success and 0 for failure * * @ingroup world */ ODE_API int dWorldQuickStep (dWorldID w, dReal stepsize); /** * @brief Converts an impulse to a force. * @ingroup world * @remarks * If you want to apply a linear or angular impulse to a rigid body, * instead of a force or a torque, then you can use this function to convert * the desired impulse into a force/torque vector before calling the * BodyAdd... function. * The current algorithm simply scales the impulse by 1/stepsize, * where stepsize is the step size for the next step that will be taken. * This function is given a dWorldID because, in the future, the force * computation may depend on integrator parameters that are set as * properties of the world. */ ODE_API void dWorldImpulseToForce ( dWorldID, dReal stepsize, dReal ix, dReal iy, dReal iz, dVector3 force ); /** * @brief Set the number of iterations that the QuickStep method performs per * step. * @ingroup world * @remarks * More iterations will give a more accurate solution, but will take * longer to compute. * @param num The default is 20 iterations. */ ODE_API void dWorldSetQuickStepNumIterations (dWorldID, int num); /** * @brief Get the number of iterations that the QuickStep method performs per * step. * @ingroup world * @return nr of iterations */ ODE_API int dWorldGetQuickStepNumIterations (dWorldID); /** * @brief Set the SOR over-relaxation parameter * @ingroup world * @param over_relaxation value to use by SOR */ ODE_API void dWorldSetQuickStepW (dWorldID, dReal over_relaxation); /** * @brief Get the SOR over-relaxation parameter * @ingroup world * @returns the over-relaxation setting */ ODE_API dReal dWorldGetQuickStepW (dWorldID); /* World contact parameter functions */ /** * @brief Set the maximum correcting velocity that contacts are allowed * to generate. * @ingroup world * @param vel The default value is infinity (i.e. no limit). * @remarks * Reducing this value can help prevent "popping" of deeply embedded objects. */ ODE_API void dWorldSetContactMaxCorrectingVel (dWorldID, dReal vel); /** * @brief Get the maximum correcting velocity that contacts are allowed * to generated. * @ingroup world */ ODE_API dReal dWorldGetContactMaxCorrectingVel (dWorldID); /** * @brief Set the depth of the surface layer around all geometry objects. * @ingroup world * @remarks * Contacts are allowed to sink into the surface layer up to the given * depth before coming to rest. * @param depth The default value is zero. * @remarks * Increasing this to some small value (e.g. 0.001) can help prevent * jittering problems due to contacts being repeatedly made and broken. */ ODE_API void dWorldSetContactSurfaceLayer (dWorldID, dReal depth); /** * @brief Get the depth of the surface layer around all geometry objects. * @ingroup world * @returns the depth */ ODE_API dReal dWorldGetContactSurfaceLayer (dWorldID); /** * @defgroup disable Automatic Enabling and Disabling * @ingroup world bodies * * Every body can be enabled or disabled. Enabled bodies participate in the * simulation, while disabled bodies are turned off and do not get updated * during a simulation step. New bodies are always created in the enabled state. * * A disabled body that is connected through a joint to an enabled body will be * automatically re-enabled at the next simulation step. * * Disabled bodies do not consume CPU time, therefore to speed up the simulation * bodies should be disabled when they come to rest. This can be done automatically * with the auto-disable feature. * * If a body has its auto-disable flag turned on, it will automatically disable * itself when * @li It has been idle for a given number of simulation steps. * @li It has also been idle for a given amount of simulation time. * * A body is considered to be idle when the magnitudes of both its * linear average velocity and angular average velocity are below given thresholds. * The sample size for the average defaults to one and can be disabled by setting * to zero with * * Thus, every body has six auto-disable parameters: an enabled flag, a idle step * count, an idle time, linear/angular average velocity thresholds, and the * average samples count. * * Newly created bodies get these parameters from world. */ /** * @brief Get auto disable linear average threshold for newly created bodies. * @ingroup disable * @return the threshold */ ODE_API dReal dWorldGetAutoDisableLinearThreshold (dWorldID); /** * @brief Set auto disable linear average threshold for newly created bodies. * @param linear_average_threshold default is 0.01 * @ingroup disable */ ODE_API void dWorldSetAutoDisableLinearThreshold (dWorldID, dReal linear_average_threshold); /** * @brief Get auto disable angular average threshold for newly created bodies. * @ingroup disable * @return the threshold */ ODE_API dReal dWorldGetAutoDisableAngularThreshold (dWorldID); /** * @brief Set auto disable angular average threshold for newly created bodies. * @param linear_average_threshold default is 0.01 * @ingroup disable */ ODE_API void dWorldSetAutoDisableAngularThreshold (dWorldID, dReal angular_average_threshold); /** * @brief Get auto disable sample count for newly created bodies. * @ingroup disable * @return number of samples used */ ODE_API int dWorldGetAutoDisableAverageSamplesCount (dWorldID); /** * @brief Set auto disable average sample count for newly created bodies. * @ingroup disable * @param average_samples_count Default is 1, meaning only instantaneous velocity is used. * Set to zero to disable sampling and thus prevent any body from auto-disabling. */ ODE_API void dWorldSetAutoDisableAverageSamplesCount (dWorldID, unsigned int average_samples_count ); /** * @brief Get auto disable steps for newly created bodies. * @ingroup disable * @return nr of steps */ ODE_API int dWorldGetAutoDisableSteps (dWorldID); /** * @brief Set auto disable steps for newly created bodies. * @ingroup disable * @param steps default is 10 */ ODE_API void dWorldSetAutoDisableSteps (dWorldID, int steps); /** * @brief Get auto disable time for newly created bodies. * @ingroup disable * @return nr of seconds */ ODE_API dReal dWorldGetAutoDisableTime (dWorldID); /** * @brief Set auto disable time for newly created bodies. * @ingroup disable * @param time default is 0 seconds */ ODE_API void dWorldSetAutoDisableTime (dWorldID, dReal time); /** * @brief Get auto disable flag for newly created bodies. * @ingroup disable * @return 0 or 1 */ ODE_API int dWorldGetAutoDisableFlag (dWorldID); /** * @brief Set auto disable flag for newly created bodies. * @ingroup disable * @param do_auto_disable default is false. */ ODE_API void dWorldSetAutoDisableFlag (dWorldID, int do_auto_disable); /** * @defgroup damping Damping * @ingroup bodies world * * Damping serves two purposes: reduce simulation instability, and to allow * the bodies to come to rest (and possibly auto-disabling them). * * Bodies are constructed using the world's current damping parameters. Setting * the scales to 0 disables the damping. * * Here is how it is done: after every time step linear and angular * velocities are tested against the corresponding thresholds. If they * are above, they are multiplied by (1 - scale). So a negative scale value * will actually increase the speed, and values greater than one will * make the object oscillate every step; both can make the simulation unstable. * * To disable damping just set the damping scale to zero. * * You can also limit the maximum angular velocity. In contrast to the damping * functions, the angular velocity is affected before the body is moved. * This means that it will introduce errors in joints that are forcing the body * to rotate too fast. Some bodies have naturally high angular velocities * (like cars' wheels), so you may want to give them a very high (like the default, * dInfinity) limit. * * @note The velocities are damped after the stepper function has moved the * object. Otherwise the damping could introduce errors in joints. First the * joint constraints are processed by the stepper (moving the body), then * the damping is applied. * * @note The damping happens right after the moved callback is called; this way * it still possible use the exact velocities the body has acquired during the * step. You can even use the callback to create your own customized damping. */ /** * @brief Get the world's linear damping threshold. * @ingroup damping */ ODE_API dReal dWorldGetLinearDampingThreshold (dWorldID w); /** * @brief Set the world's linear damping threshold. * @param threshold The damping won't be applied if the linear speed is * below this threshold. Default is 0.01. * @ingroup damping */ ODE_API void dWorldSetLinearDampingThreshold(dWorldID w, dReal threshold); /** * @brief Get the world's angular damping threshold. * @ingroup damping */ ODE_API dReal dWorldGetAngularDampingThreshold (dWorldID w); /** * @brief Set the world's angular damping threshold. * @param threshold The damping won't be applied if the angular speed is * below this threshold. Default is 0.01. * @ingroup damping */ ODE_API void dWorldSetAngularDampingThreshold(dWorldID w, dReal threshold); /** * @brief Get the world's linear damping scale. * @ingroup damping */ ODE_API dReal dWorldGetLinearDamping (dWorldID w); /** * @brief Set the world's linear damping scale. * @param scale The linear damping scale that is to be applied to bodies. * Default is 0 (no damping). Should be in the interval [0, 1]. * @ingroup damping */ ODE_API void dWorldSetLinearDamping (dWorldID w, dReal scale); /** * @brief Get the world's angular damping scale. * @ingroup damping */ ODE_API dReal dWorldGetAngularDamping (dWorldID w); /** * @brief Set the world's angular damping scale. * @param scale The angular damping scale that is to be applied to bodies. * Default is 0 (no damping). Should be in the interval [0, 1]. * @ingroup damping */ ODE_API void dWorldSetAngularDamping(dWorldID w, dReal scale); /** * @brief Convenience function to set body linear and angular scales. * @param linear_scale The linear damping scale that is to be applied to bodies. * @param angular_scale The angular damping scale that is to be applied to bodies. * @ingroup damping */ ODE_API void dWorldSetDamping(dWorldID w, dReal linear_scale, dReal angular_scale); /** * @brief Get the default maximum angular speed. * @ingroup damping * @sa dBodyGetMaxAngularSpeed() */ ODE_API dReal dWorldGetMaxAngularSpeed (dWorldID w); /** * @brief Set the default maximum angular speed for new bodies. * @ingroup damping * @sa dBodySetMaxAngularSpeed() */ ODE_API void dWorldSetMaxAngularSpeed (dWorldID w, dReal max_speed); /** * @defgroup bodies Rigid Bodies * * A rigid body has various properties from the point of view of the * simulation. Some properties change over time: * * @li Position vector (x,y,z) of the body's point of reference. * Currently the point of reference must correspond to the body's center of mass. * @li Linear velocity of the point of reference, a vector (vx,vy,vz). * @li Orientation of a body, represented by a quaternion (qs,qx,qy,qz) or * a 3x3 rotation matrix. * @li Angular velocity vector (wx,wy,wz) which describes how the orientation * changes over time. * * Other body properties are usually constant over time: * * @li Mass of the body. * @li Position of the center of mass with respect to the point of reference. * In the current implementation the center of mass and the point of * reference must coincide. * @li Inertia matrix. This is a 3x3 matrix that describes how the body's mass * is distributed around the center of mass. Conceptually each body has an * x-y-z coordinate frame embedded in it that moves and rotates with the body. * * The origin of this coordinate frame is the body's point of reference. Some values * in ODE (vectors, matrices etc) are relative to the body coordinate frame, and others * are relative to the global coordinate frame. * * Note that the shape of a rigid body is not a dynamical property (except insofar as * it influences the various mass properties). It is only collision detection that cares * about the detailed shape of the body. */ /** * @brief Get auto disable linear average threshold. * @ingroup bodies disable * @return the threshold */ ODE_API dReal dBodyGetAutoDisableLinearThreshold (dBodyID); /** * @brief Set auto disable linear average threshold. * @ingroup bodies disable * @return the threshold */ ODE_API void dBodySetAutoDisableLinearThreshold (dBodyID, dReal linear_average_threshold); /** * @brief Get auto disable angular average threshold. * @ingroup bodies disable * @return the threshold */ ODE_API dReal dBodyGetAutoDisableAngularThreshold (dBodyID); /** * @brief Set auto disable angular average threshold. * @ingroup bodies disable * @return the threshold */ ODE_API void dBodySetAutoDisableAngularThreshold (dBodyID, dReal angular_average_threshold); /** * @brief Get auto disable average size (samples count). * @ingroup bodies disable * @return the nr of steps/size. */ ODE_API int dBodyGetAutoDisableAverageSamplesCount (dBodyID); /** * @brief Set auto disable average buffer size (average steps). * @ingroup bodies disable * @param average_samples_count the nr of samples to review. */ ODE_API void dBodySetAutoDisableAverageSamplesCount (dBodyID, unsigned int average_samples_count); /** * @brief Get auto steps a body must be thought of as idle to disable * @ingroup bodies disable * @return the nr of steps */ ODE_API int dBodyGetAutoDisableSteps (dBodyID); /** * @brief Set auto disable steps. * @ingroup bodies disable * @param steps the nr of steps. */ ODE_API void dBodySetAutoDisableSteps (dBodyID, int steps); /** * @brief Get auto disable time. * @ingroup bodies disable * @return nr of seconds */ ODE_API dReal dBodyGetAutoDisableTime (dBodyID); /** * @brief Set auto disable time. * @ingroup bodies disable * @param time nr of seconds. */ ODE_API void dBodySetAutoDisableTime (dBodyID, dReal time); /** * @brief Get auto disable flag. * @ingroup bodies disable * @return 0 or 1 */ ODE_API int dBodyGetAutoDisableFlag (dBodyID); /** * @brief Set auto disable flag. * @ingroup bodies disable * @param do_auto_disable 0 or 1 */ ODE_API void dBodySetAutoDisableFlag (dBodyID, int do_auto_disable); /** * @brief Set auto disable defaults. * @remarks * Set the values for the body to those set as default for the world. * @ingroup bodies disable */ ODE_API void dBodySetAutoDisableDefaults (dBodyID); /** * @brief Retrieves the world attached to te given body. * @remarks * * @ingroup bodies */ ODE_API dWorldID dBodyGetWorld (dBodyID); /** * @brief Create a body in given world. * @remarks * Default mass parameters are at position (0,0,0). * @ingroup bodies */ ODE_API dBodyID dBodyCreate (dWorldID); /** * @brief Destroy a body. * @remarks * All joints that are attached to this body will be put into limbo: * i.e. unattached and not affecting the simulation, but they will NOT be * deleted. * @ingroup bodies */ ODE_API void dBodyDestroy (dBodyID); /** * @brief Set the body's user-data pointer. * @ingroup bodies * @param data arbitraty pointer */ ODE_API void dBodySetData (dBodyID, void *data); /** * @brief Get the body's user-data pointer. * @ingroup bodies * @return a pointer to the user's data. */ ODE_API void *dBodyGetData (dBodyID); /** * @brief Set position of a body. * @remarks * After setting, the outcome of the simulation is undefined * if the new configuration is inconsistent with the joints/constraints * that are present. * @ingroup bodies */ ODE_API void dBodySetPosition (dBodyID, dReal x, dReal y, dReal z); /** * @brief Set the orientation of a body. * @ingroup bodies * @remarks * After setting, the outcome of the simulation is undefined * if the new configuration is inconsistent with the joints/constraints * that are present. */ ODE_API void dBodySetRotation (dBodyID, const dMatrix3 R); /** * @brief Set the orientation of a body. * @ingroup bodies * @remarks * After setting, the outcome of the simulation is undefined * if the new configuration is inconsistent with the joints/constraints * that are present. */ ODE_API void dBodySetQuaternion (dBodyID, const dQuaternion q); /** * @brief Set the linear velocity of a body. * @ingroup bodies */ ODE_API void dBodySetLinearVel (dBodyID, dReal x, dReal y, dReal z); /** * @brief Set the angular velocity of a body. * @ingroup bodies */ ODE_API void dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z); /** * @brief Get the position of a body. * @ingroup bodies * @remarks * When getting, the returned values are pointers to internal data structures, * so the vectors are valid until any changes are made to the rigid body * system structure. * @sa dBodyCopyPosition */ ODE_API const dReal * dBodyGetPosition (dBodyID); /** * @brief Copy the position of a body into a vector. * @ingroup bodies * @param body the body to query * @param pos a copy of the body position * @sa dBodyGetPosition */ ODE_API void dBodyCopyPosition (dBodyID body, dVector3 pos); /** * @brief Get the rotation of a body. * @ingroup bodies * @return pointer to a 4x3 rotation matrix. */ ODE_API const dReal * dBodyGetRotation (dBodyID); /** * @brief Copy the rotation of a body. * @ingroup bodies * @param body the body to query * @param R a copy of the rotation matrix * @sa dBodyGetRotation */ ODE_API void dBodyCopyRotation (dBodyID, dMatrix3 R); /** * @brief Get the rotation of a body. * @ingroup bodies * @return pointer to 4 scalars that represent the quaternion. */ ODE_API const dReal * dBodyGetQuaternion (dBodyID); /** * @brief Copy the orientation of a body into a quaternion. * @ingroup bodies * @param body the body to query * @param quat a copy of the orientation quaternion * @sa dBodyGetQuaternion */ ODE_API void dBodyCopyQuaternion(dBodyID body, dQuaternion quat); /** * @brief Get the linear velocity of a body. * @ingroup bodies */ ODE_API const dReal * dBodyGetLinearVel (dBodyID); /** * @brief Get the angular velocity of a body. * @ingroup bodies */ ODE_API const dReal * dBodyGetAngularVel (dBodyID); /** * @brief Set the mass of a body. * @ingroup bodies */ ODE_API void dBodySetMass (dBodyID, const dMass *mass); /** * @brief Get the mass of a body. * @ingroup bodies */ ODE_API void dBodyGetMass (dBodyID, dMass *mass); /** * @brief Add force at centre of mass of body in absolute coordinates. * @ingroup bodies */ ODE_API void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); /** * @brief Add torque at centre of mass of body in absolute coordinates. * @ingroup bodies */ ODE_API void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); /** * @brief Add force at centre of mass of body in coordinates relative to body. * @ingroup bodies */ ODE_API void dBodyAddRelForce (dBodyID, dReal fx, dReal fy, dReal fz); /** * @brief Add torque at centre of mass of body in coordinates relative to body. * @ingroup bodies */ ODE_API void dBodyAddRelTorque (dBodyID, dReal fx, dReal fy, dReal fz); /** * @brief Add force at specified point in body in global coordinates. * @ingroup bodies */ ODE_API void dBodyAddForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); /** * @brief Add force at specified point in body in local coordinates. * @ingroup bodies */ ODE_API void dBodyAddForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); /** * @brief Add force at specified point in body in global coordinates. * @ingroup bodies */ ODE_API void dBodyAddRelForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); /** * @brief Add force at specified point in body in local coordinates. * @ingroup bodies */ ODE_API void dBodyAddRelForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz); /** * @brief Return the current accumulated force vector. * @return points to an array of 3 reals. * @remarks * The returned values are pointers to internal data structures, so * the vectors are only valid until any changes are made to the rigid * body system. * @ingroup bodies */ ODE_API const dReal * dBodyGetForce (dBodyID); /** * @brief Return the current accumulated torque vector. * @return points to an array of 3 reals. * @remarks * The returned values are pointers to internal data structures, so * the vectors are only valid until any changes are made to the rigid * body system. * @ingroup bodies */ ODE_API const dReal * dBodyGetTorque (dBodyID); /** * @brief Set the body force accumulation vector. * @remarks * This is mostly useful to zero the force and torque for deactivated bodies * before they are reactivated, in the case where the force-adding functions * were called on them while they were deactivated. * @ingroup bodies */ ODE_API void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z); /** * @brief Set the body torque accumulation vector. * @remarks * This is mostly useful to zero the force and torque for deactivated bodies * before they are reactivated, in the case where the force-adding functions * were called on them while they were deactivated. * @ingroup bodies */ ODE_API void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z); /** * @brief Get world position of a relative point on body. * @ingroup bodies * @param result will contain the result. */ ODE_API void dBodyGetRelPointPos ( dBodyID, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief Get velocity vector in global coords of a relative point on body. * @ingroup bodies * @param result will contain the result. */ ODE_API void dBodyGetRelPointVel ( dBodyID, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief Get velocity vector in global coords of a globally * specified point on a body. * @ingroup bodies * @param result will contain the result. */ ODE_API void dBodyGetPointVel ( dBodyID, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief takes a point in global coordinates and returns * the point's position in body-relative coordinates. * @remarks * This is the inverse of dBodyGetRelPointPos() * @ingroup bodies * @param result will contain the result. */ ODE_API void dBodyGetPosRelPoint ( dBodyID, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief Convert from local to world coordinates. * @ingroup bodies * @param result will contain the result. */ ODE_API void dBodyVectorToWorld ( dBodyID, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief Convert from world to local coordinates. * @ingroup bodies * @param result will contain the result. */ ODE_API void dBodyVectorFromWorld ( dBodyID, dReal px, dReal py, dReal pz, dVector3 result ); /** * @brief controls the way a body's orientation is updated at each timestep. * @ingroup bodies * @param mode can be 0 or 1: * \li 0: An ``infinitesimal'' orientation update is used. * This is fast to compute, but it can occasionally cause inaccuracies * for bodies that are rotating at high speed, especially when those * bodies are joined to other bodies. * This is the default for every new body that is created. * \li 1: A ``finite'' orientation update is used. * This is more costly to compute, but will be more accurate for high * speed rotations. * @remarks * Note however that high speed rotations can result in many types of * error in a simulation, and the finite mode will only fix one of those * sources of error. */ ODE_API void dBodySetFiniteRotationMode (dBodyID, int mode); /** * @brief sets the finite rotation axis for a body. * @ingroup bodies * @remarks * This is axis only has meaning when the finite rotation mode is set * If this axis is zero (0,0,0), full finite rotations are performed on * the body. * If this axis is nonzero, the body is rotated by performing a partial finite * rotation along the axis direction followed by an infinitesimal rotation * along an orthogonal direction. * @remarks * This can be useful to alleviate certain sources of error caused by quickly * spinning bodies. For example, if a car wheel is rotating at high speed * you can call this function with the wheel's hinge axis as the argument to * try and improve its behavior. */ ODE_API void dBodySetFiniteRotationAxis (dBodyID, dReal x, dReal y, dReal z); /** * @brief Get the way a body's orientation is updated each timestep. * @ingroup bodies * @return the mode 0 (infitesimal) or 1 (finite). */ ODE_API int dBodyGetFiniteRotationMode (dBodyID); /** * @brief Get the finite rotation axis. * @param result will contain the axis. * @ingroup bodies */ ODE_API void dBodyGetFiniteRotationAxis (dBodyID, dVector3 result); /** * @brief Get the number of joints that are attached to this body. * @ingroup bodies * @return nr of joints */ ODE_API int dBodyGetNumJoints (dBodyID b); /** * @brief Return a joint attached to this body, given by index. * @ingroup bodies * @param index valid range is 0 to n-1 where n is the value returned by * dBodyGetNumJoints(). */ ODE_API dJointID dBodyGetJoint (dBodyID, int index); /** * @brief Set rigid body to dynamic state (default). * @param dBodyID identification of body. * @ingroup bodies */ ODE_API void dBodySetDynamic (dBodyID); /** * @brief Set rigid body to kinematic state. * When in kinematic state the body isn't simulated as a dynamic * body (it's "unstoppable", doesn't respond to forces), * but can still affect dynamic bodies (e.g. in joints). * Kinematic bodies can be controlled by position and velocity. * @note A kinematic body has infinite mass. If you set its mass * to something else, it loses the kinematic state and behaves * as a normal dynamic body. * @param dBodyID identification of body. * @ingroup bodies */ ODE_API void dBodySetKinematic (dBodyID); /** * @brief Check wether a body is in kinematic state. * @ingroup bodies * @return 1 if a body is kinematic or 0 if it is dynamic. */ ODE_API int dBodyIsKinematic (dBodyID); /** * @brief Manually enable a body. * @param dBodyID identification of body. * @ingroup bodies */ ODE_API void dBodyEnable (dBodyID); /** * @brief Manually disable a body. * @ingroup bodies * @remarks * A disabled body that is connected through a joint to an enabled body will * be automatically re-enabled at the next simulation step. */ ODE_API void dBodyDisable (dBodyID); /** * @brief Check wether a body is enabled. * @ingroup bodies * @return 1 if a body is currently enabled or 0 if it is disabled. */ ODE_API int dBodyIsEnabled (dBodyID); /** * @brief Set whether the body is influenced by the world's gravity or not. * @ingroup bodies * @param mode when nonzero gravity affects this body. * @remarks * Newly created bodies are always influenced by the world's gravity. */ ODE_API void dBodySetGravityMode (dBodyID b, int mode); /** * @brief Get whether the body is influenced by the world's gravity or not. * @ingroup bodies * @return nonzero means gravity affects this body. */ ODE_API int dBodyGetGravityMode (dBodyID b); /** * @brief Set the 'moved' callback of a body. * * Whenever a body has its position or rotation changed during the * timestep, the callback will be called (with body as the argument). * Use it to know which body may need an update in an external * structure (like a 3D engine). * * @param b the body that needs to be watched. * @param callback the callback to be invoked when the body moves. Set to zero * to disable. * @ingroup bodies */ ODE_API void dBodySetMovedCallback(dBodyID b, void (*callback)(dBodyID)); /** * @brief Return the first geom associated with the body. * * You can traverse through the geoms by repeatedly calling * dBodyGetNextGeom(). * * @return the first geom attached to this body, or 0. * @ingroup bodies */ ODE_API dGeomID dBodyGetFirstGeom (dBodyID b); /** * @brief returns the next geom associated with the same body. * @param g a geom attached to some body. * @return the next geom attached to the same body, or 0. * @sa dBodyGetFirstGeom * @ingroup bodies */ ODE_API dGeomID dBodyGetNextGeom (dGeomID g); /** * @brief Resets the damping settings to the current world's settings. * @ingroup bodies damping */ ODE_API void dBodySetDampingDefaults(dBodyID b); /** * @brief Get the body's linear damping scale. * @ingroup bodies damping */ ODE_API dReal dBodyGetLinearDamping (dBodyID b); /** * @brief Set the body's linear damping scale. * @param scale The linear damping scale. Should be in the interval [0, 1]. * @ingroup bodies damping * @remarks From now on the body will not use the world's linear damping * scale until dBodySetDampingDefaults() is called. * @sa dBodySetDampingDefaults() */ ODE_API void dBodySetLinearDamping(dBodyID b, dReal scale); /** * @brief Get the body's angular damping scale. * @ingroup bodies damping * @remarks If the body's angular damping scale was not set, this function * returns the world's angular damping scale. */ ODE_API dReal dBodyGetAngularDamping (dBodyID b); /** * @brief Set the body's angular damping scale. * @param scale The angular damping scale. Should be in the interval [0, 1]. * @ingroup bodies damping * @remarks From now on the body will not use the world's angular damping * scale until dBodyResetAngularDamping() is called. * @sa dBodyResetAngularDamping() */ ODE_API void dBodySetAngularDamping(dBodyID b, dReal scale); /** * @brief Convenience function to set linear and angular scales at once. * @param linear_scale The linear damping scale. Should be in the interval [0, 1]. * @param angular_scale The angular damping scale. Should be in the interval [0, 1]. * @ingroup bodies damping * @sa dBodySetLinearDamping() dBodySetAngularDamping() */ ODE_API void dBodySetDamping(dBodyID b, dReal linear_scale, dReal angular_scale); /** * @brief Get the body's linear damping threshold. * @ingroup bodies damping */ ODE_API dReal dBodyGetLinearDampingThreshold (dBodyID b); /** * @brief Set the body's linear damping threshold. * @param threshold The linear threshold to be used. Damping * is only applied if the linear speed is above this limit. * @ingroup bodies damping */ ODE_API void dBodySetLinearDampingThreshold(dBodyID b, dReal threshold); /** * @brief Get the body's angular damping threshold. * @ingroup bodies damping */ ODE_API dReal dBodyGetAngularDampingThreshold (dBodyID b); /** * @brief Set the body's angular damping threshold. * @param threshold The angular threshold to be used. Damping is * only used if the angular speed is above this limit. * @ingroup bodies damping */ ODE_API void dBodySetAngularDampingThreshold(dBodyID b, dReal threshold); /** * @brief Get the body's maximum angular speed. * @ingroup damping bodies * @sa dWorldGetMaxAngularSpeed() */ ODE_API dReal dBodyGetMaxAngularSpeed (dBodyID b); /** * @brief Set the body's maximum angular speed. * @ingroup damping bodies * @sa dWorldSetMaxAngularSpeed() dBodyResetMaxAngularSpeed() * The default value is dInfinity, but it's a good idea to limit * it at less than 500 if the body has the gyroscopic term * enabled. */ ODE_API void dBodySetMaxAngularSpeed(dBodyID b, dReal max_speed); /** * @brief Get the body's gyroscopic state. * * @return nonzero if gyroscopic term computation is enabled (default), * zero otherwise. * @ingroup bodies */ ODE_API int dBodyGetGyroscopicMode(dBodyID b); /** * @brief Enable/disable the body's gyroscopic term. * * Disabling the gyroscopic term of a body usually improves * stability. It also helps turning spining objects, like cars' * wheels. * * @param enabled nonzero (default) to enable gyroscopic term, 0 * to disable. * @ingroup bodies */ ODE_API void dBodySetGyroscopicMode(dBodyID b, int enabled); /** * @defgroup joints Joints * * In real life a joint is something like a hinge, that is used to connect two * objects. * In ODE a joint is very similar: It is a relationship that is enforced between * two bodies so that they can only have certain positions and orientations * relative to each other. * This relationship is called a constraint -- the words joint and * constraint are often used interchangeably. * * A joint has a set of parameters that can be set. These include: * * * \li dParamLoStop Low stop angle or position. Setting this to * -dInfinity (the default value) turns off the low stop. * For rotational joints, this stop must be greater than -pi to be * effective. * \li dParamHiStop High stop angle or position. Setting this to * dInfinity (the default value) turns off the high stop. * For rotational joints, this stop must be less than pi to be * effective. * If the high stop is less than the low stop then both stops will * be ineffective. * \li dParamVel Desired motor velocity (this will be an angular or * linear velocity). * \li dParamFMax The maximum force or torque that the motor will use to * achieve the desired velocity. * This must always be greater than or equal to zero. * Setting this to zero (the default value) turns off the motor. * \li dParamFudgeFactor The current joint stop/motor implementation has * a small problem: * when the joint is at one stop and the motor is set to move it away * from the stop, too much force may be applied for one time step, * causing a ``jumping'' motion. * This fudge factor is used to scale this excess force. * It should have a value between zero and one (the default value). * If the jumping motion is too visible in a joint, the value can be * reduced. * Making this value too small can prevent the motor from being able to * move the joint away from a stop. * \li dParamBounce The bouncyness of the stops. * This is a restitution parameter in the range 0..1. * 0 means the stops are not bouncy at all, 1 means maximum bouncyness. * \li dParamCFM The constraint force mixing (CFM) value used when not * at a stop. * \li dParamStopERP The error reduction parameter (ERP) used by the * stops. * \li dParamStopCFM The constraint force mixing (CFM) value used by the * stops. Together with the ERP value this can be used to get spongy or * soft stops. * Note that this is intended for unpowered joints, it does not really * work as expected when a powered joint reaches its limit. * \li dParamSuspensionERP Suspension error reduction parameter (ERP). * Currently this is only implemented on the hinge-2 joint. * \li dParamSuspensionCFM Suspension constraint force mixing (CFM) value. * Currently this is only implemented on the hinge-2 joint. * * If a particular parameter is not implemented by a given joint, setting it * will have no effect. * These parameter names can be optionally followed by a digit (2 or 3) * to indicate the second or third set of parameters, e.g. for the second axis * in a hinge-2 joint, or the third axis in an AMotor joint. */ /** * @brief Create a new joint of the ball type. * @ingroup joints * @remarks * The joint is initially in "limbo" (i.e. it has no effect on the simulation) * because it does not connect to any bodies. * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateBall (dWorldID, dJointGroupID); /** * @brief Create a new joint of the hinge type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateHinge (dWorldID, dJointGroupID); /** * @brief Create a new joint of the slider type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateSlider (dWorldID, dJointGroupID); /** * @brief Create a new joint of the contact type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateContact (dWorldID, dJointGroupID, const dContact *); /** * @brief Create a new joint of the hinge2 type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateHinge2 (dWorldID, dJointGroupID); /** * @brief Create a new joint of the universal type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateUniversal (dWorldID, dJointGroupID); /** * @brief Create a new joint of the PR (Prismatic and Rotoide) type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreatePR (dWorldID, dJointGroupID); /** * @brief Create a new joint of the PU (Prismatic and Universal) type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreatePU (dWorldID, dJointGroupID); /** * @brief Create a new joint of the Piston type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given * joint group. */ ODE_API dJointID dJointCreatePiston (dWorldID, dJointGroupID); /** * @brief Create a new joint of the fixed type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateFixed (dWorldID, dJointGroupID); ODE_API dJointID dJointCreateNull (dWorldID, dJointGroupID); /** * @brief Create a new joint of the A-motor type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateAMotor (dWorldID, dJointGroupID); /** * @brief Create a new joint of the L-motor type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateLMotor (dWorldID, dJointGroupID); /** * @brief Create a new joint of the plane-2d type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreatePlane2D (dWorldID, dJointGroupID); /** * @brief Create a new joint of the double ball type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateDBall (dWorldID, dJointGroupID); /** * @brief Create a new joint of the double hinge type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateDHinge (dWorldID, dJointGroupID); /** * @brief Create a new joint of the Transmission type. * @ingroup joints * @param dJointGroupID set to 0 to allocate the joint normally. * If it is nonzero the joint is allocated in the given joint group. */ ODE_API dJointID dJointCreateTransmission (dWorldID, dJointGroupID); /** * @brief Destroy a joint. * @ingroup joints * * disconnects it from its attached bodies and removing it from the world. * However, if the joint is a member of a group then this function has no * effect - to destroy that joint the group must be emptied or destroyed. */ ODE_API void dJointDestroy (dJointID); /** * @brief Create a joint group * @ingroup joints * @param max_size deprecated. Set to 0. */ ODE_API dJointGroupID dJointGroupCreate (int max_size); /** * @brief Destroy a joint group. * @ingroup joints * * All joints in the joint group will be destroyed. */ ODE_API void dJointGroupDestroy (dJointGroupID); /** * @brief Empty a joint group. * @ingroup joints * * All joints in the joint group will be destroyed, * but the joint group itself will not be destroyed. */ ODE_API void dJointGroupEmpty (dJointGroupID); /** * @brief Return the number of bodies attached to the joint * @ingroup joints */ ODE_API int dJointGetNumBodies(dJointID); /** * @brief Attach the joint to some new bodies. * @ingroup joints * * If the joint is already attached, it will be detached from the old bodies * first. * To attach this joint to only one body, set body1 or body2 to zero - a zero * body refers to the static environment. * Setting both bodies to zero puts the joint into "limbo", i.e. it will * have no effect on the simulation. * @remarks * Some joints, like hinge-2 need to be attached to two bodies to work. */ ODE_API void dJointAttach (dJointID, dBodyID body1, dBodyID body2); /** * @brief Manually enable a joint. * @param dJointID identification of joint. * @ingroup joints */ ODE_API void dJointEnable (dJointID); /** * @brief Manually disable a joint. * @ingroup joints * @remarks * A disabled joint will not affect the simulation, but will maintain the anchors and * axes so it can be enabled later. */ ODE_API void dJointDisable (dJointID); /** * @brief Check wether a joint is enabled. * @ingroup joints * @return 1 if a joint is currently enabled or 0 if it is disabled. */ ODE_API int dJointIsEnabled (dJointID); /** * @brief Set the user-data pointer * @ingroup joints */ ODE_API void dJointSetData (dJointID, void *data); /** * @brief Get the user-data pointer * @ingroup joints */ ODE_API void *dJointGetData (dJointID); /** * @brief Get the type of the joint * @ingroup joints * @return the type, being one of these: * \li dJointTypeBall * \li dJointTypeHinge * \li dJointTypeSlider * \li dJointTypeContact * \li dJointTypeUniversal * \li dJointTypeHinge2 * \li dJointTypeFixed * \li dJointTypeNull * \li dJointTypeAMotor * \li dJointTypeLMotor * \li dJointTypePlane2D * \li dJointTypePR * \li dJointTypePU * \li dJointTypePiston */ ODE_API dJointType dJointGetType (dJointID); /** * @brief Return the bodies that this joint connects. * @ingroup joints * @param index return the first (0) or second (1) body. * @remarks * If one of these returned body IDs is zero, the joint connects the other body * to the static environment. * If both body IDs are zero, the joint is in ``limbo'' and has no effect on * the simulation. */ ODE_API dBodyID dJointGetBody (dJointID, int index); /** * @brief Sets the datastructure that is to receive the feedback. * * The feedback can be used by the user, so that it is known how * much force an individual joint exerts. * @ingroup joints */ ODE_API void dJointSetFeedback (dJointID, dJointFeedback *); /** * @brief Gets the datastructure that is to receive the feedback. * @ingroup joints */ ODE_API dJointFeedback *dJointGetFeedback (dJointID); /** * @brief Set the joint anchor point. * @ingroup joints * * The joint will try to keep this point on each body * together. The input is specified in world coordinates. */ ODE_API void dJointSetBallAnchor (dJointID, dReal x, dReal y, dReal z); /** * @brief Set the joint anchor point. * @ingroup joints */ ODE_API void dJointSetBallAnchor2 (dJointID, dReal x, dReal y, dReal z); /** * @brief Param setting for Ball joints * @ingroup joints */ ODE_API void dJointSetBallParam (dJointID, int parameter, dReal value); /** * @brief Set hinge anchor parameter. * @ingroup joints */ ODE_API void dJointSetHingeAnchor (dJointID, dReal x, dReal y, dReal z); ODE_API void dJointSetHingeAnchorDelta (dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); /** * @brief Set hinge axis. * @ingroup joints */ ODE_API void dJointSetHingeAxis (dJointID, dReal x, dReal y, dReal z); /** * @brief Set the Hinge axis as if the 2 bodies were already at angle appart. * @ingroup joints * * This function initialize the Axis and the relative orientation of each body * as if body1 was rotated around the axis by the angle value. \br * Ex: *
     * dJointSetHingeAxis(jId, 1, 0, 0);
     * // If you request the position you will have: dJointGetHingeAngle(jId) == 0
     * dJointSetHingeAxisDelta(jId, 1, 0, 0, 0.23);
     * // If you request the position you will have: dJointGetHingeAngle(jId) == 0.23
     * 
    * @param j The Hinge joint ID for which the axis will be set * @param x The X component of the axis in world frame * @param y The Y component of the axis in world frame * @param z The Z component of the axis in world frame * @param angle The angle for the offset of the relative orientation. * As if body1 was rotated by angle when the Axis was set (see below). * The rotation is around the new Hinge axis. * * @note Usually the function dJointSetHingeAxis set the current position of body1 * and body2 as the zero angle position. This function set the current position * as the if the 2 bodies where \b angle appart. * @warning Calling dJointSetHingeAnchor or dJointSetHingeAxis will reset the "zero" * angle position. */ ODE_API void dJointSetHingeAxisOffset (dJointID j, dReal x, dReal y, dReal z, dReal angle); /** * @brief set joint parameter * @ingroup joints */ ODE_API void dJointSetHingeParam (dJointID, int parameter, dReal value); /** * @brief Applies the torque about the hinge axis. * * That is, it applies a torque with specified magnitude in the direction * of the hinge axis, to body 1, and with the same magnitude but in opposite * direction to body 2. This function is just a wrapper for dBodyAddTorque()} * @ingroup joints */ ODE_API void dJointAddHingeTorque(dJointID joint, dReal torque); /** * @brief set the joint axis * @ingroup joints */ ODE_API void dJointSetSliderAxis (dJointID, dReal x, dReal y, dReal z); /** * @ingroup joints */ ODE_API void dJointSetSliderAxisDelta (dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); /** * @brief set joint parameter * @ingroup joints */ ODE_API void dJointSetSliderParam (dJointID, int parameter, dReal value); /** * @brief Applies the given force in the slider's direction. * * That is, it applies a force with specified magnitude, in the direction of * slider's axis, to body1, and with the same magnitude but opposite * direction to body2. This function is just a wrapper for dBodyAddForce(). * @ingroup joints */ ODE_API void dJointAddSliderForce(dJointID joint, dReal force); /** * @brief set anchor * @ingroup joints */ ODE_API void dJointSetHinge2Anchor (dJointID, dReal x, dReal y, dReal z); /** * @brief set axis * @ingroup joints */ ODE_API void dJointSetHinge2Axis1 (dJointID, dReal x, dReal y, dReal z); /** * @brief set axis * @ingroup joints */ ODE_API void dJointSetHinge2Axis2 (dJointID, dReal x, dReal y, dReal z); /** * @brief set joint parameter * @ingroup joints */ ODE_API void dJointSetHinge2Param (dJointID, int parameter, dReal value); /** * @brief Applies torque1 about the hinge2's axis 1, torque2 about the * hinge2's axis 2. * @remarks This function is just a wrapper for dBodyAddTorque(). * @ingroup joints */ ODE_API void dJointAddHinge2Torques(dJointID joint, dReal torque1, dReal torque2); /** * @brief set anchor * @ingroup joints */ ODE_API void dJointSetUniversalAnchor (dJointID, dReal x, dReal y, dReal z); /** * @brief set axis * @ingroup joints */ ODE_API void dJointSetUniversalAxis1 (dJointID, dReal x, dReal y, dReal z); /** * @brief Set the Universal axis1 as if the 2 bodies were already at * offset1 and offset2 appart with respect to axis1 and axis2. * @ingroup joints * * This function initialize the axis1 and the relative orientation of * each body as if body1 was rotated around the new axis1 by the offset1 * value and as if body2 was rotated around the axis2 by offset2. \br * Ex: *
     * dJointSetHuniversalAxis1(jId, 1, 0, 0);
     * // If you request the position you will have: dJointGetUniversalAngle1(jId) == 0
     * // If you request the position you will have: dJointGetUniversalAngle2(jId) == 0
     * dJointSetHuniversalAxis1Offset(jId, 1, 0, 0, 0.2, 0.17);
     * // If you request the position you will have: dJointGetUniversalAngle1(jId) == 0.2
     * // If you request the position you will have: dJointGetUniversalAngle2(jId) == 0.17
     * 
    * * @param j The Hinge joint ID for which the axis will be set * @param x The X component of the axis in world frame * @param y The Y component of the axis in world frame * @param z The Z component of the axis in world frame * @param angle The angle for the offset of the relative orientation. * As if body1 was rotated by angle when the Axis was set (see below). * The rotation is around the new Hinge axis. * * @note Usually the function dJointSetHingeAxis set the current position of body1 * and body2 as the zero angle position. This function set the current position * as the if the 2 bodies where \b offsets appart. * * @note Any previous offsets are erased. * * @warning Calling dJointSetUniversalAnchor, dJointSetUnivesalAxis1, * dJointSetUniversalAxis2, dJointSetUniversalAxis2Offset * will reset the "zero" angle position. */ ODE_API void dJointSetUniversalAxis1Offset (dJointID, dReal x, dReal y, dReal z, dReal offset1, dReal offset2); /** * @brief set axis * @ingroup joints */ ODE_API void dJointSetUniversalAxis2 (dJointID, dReal x, dReal y, dReal z); /** * @brief Set the Universal axis2 as if the 2 bodies were already at * offset1 and offset2 appart with respect to axis1 and axis2. * @ingroup joints * * This function initialize the axis2 and the relative orientation of * each body as if body1 was rotated around the axis1 by the offset1 * value and as if body2 was rotated around the new axis2 by offset2. \br * Ex: *
     * dJointSetHuniversalAxis2(jId, 0, 1, 0);
     * // If you request the position you will have: dJointGetUniversalAngle1(jId) == 0
     * // If you request the position you will have: dJointGetUniversalAngle2(jId) == 0
     * dJointSetHuniversalAxis2Offset(jId, 0, 1, 0, 0.2, 0.17);
     * // If you request the position you will have: dJointGetUniversalAngle1(jId) == 0.2
     * // If you request the position you will have: dJointGetUniversalAngle2(jId) == 0.17
     * 
    * @param j The Hinge joint ID for which the axis will be set * @param x The X component of the axis in world frame * @param y The Y component of the axis in world frame * @param z The Z component of the axis in world frame * @param angle The angle for the offset of the relative orientation. * As if body1 was rotated by angle when the Axis was set (see below). * The rotation is around the new Hinge axis. * * @note Usually the function dJointSetHingeAxis set the current position of body1 * and body2 as the zero angle position. This function set the current position * as the if the 2 bodies where \b offsets appart. * * @note Any previous offsets are erased. * * @warning Calling dJointSetUniversalAnchor, dJointSetUnivesalAxis1, * dJointSetUniversalAxis2, dJointSetUniversalAxis2Offset * will reset the "zero" angle position. */ ODE_API void dJointSetUniversalAxis2Offset (dJointID, dReal x, dReal y, dReal z, dReal offset1, dReal offset2); /** * @brief set joint parameter * @ingroup joints */ ODE_API void dJointSetUniversalParam (dJointID, int parameter, dReal value); /** * @brief Applies torque1 about the universal's axis 1, torque2 about the * universal's axis 2. * @remarks This function is just a wrapper for dBodyAddTorque(). * @ingroup joints */ ODE_API void dJointAddUniversalTorques(dJointID joint, dReal torque1, dReal torque2); /** * @brief set anchor * @ingroup joints */ ODE_API void dJointSetPRAnchor (dJointID, dReal x, dReal y, dReal z); /** * @brief set the axis for the prismatic articulation * @ingroup joints */ ODE_API void dJointSetPRAxis1 (dJointID, dReal x, dReal y, dReal z); /** * @brief set the axis for the rotoide articulation * @ingroup joints */ ODE_API void dJointSetPRAxis2 (dJointID, dReal x, dReal y, dReal z); /** * @brief set joint parameter * @ingroup joints * * @note parameterX where X equal 2 refer to parameter for the rotoide articulation */ ODE_API void dJointSetPRParam (dJointID, int parameter, dReal value); /** * @brief Applies the torque about the rotoide axis of the PR joint * * That is, it applies a torque with specified magnitude in the direction * of the rotoide axis, to body 1, and with the same magnitude but in opposite * direction to body 2. This function is just a wrapper for dBodyAddTorque()} * @ingroup joints */ ODE_API void dJointAddPRTorque (dJointID j, dReal torque); /** * @brief set anchor * @ingroup joints */ ODE_API void dJointSetPUAnchor (dJointID, dReal x, dReal y, dReal z); /** * @brief set anchor * @ingroup joints */ ODE_API_DEPRECATED ODE_API void dJointSetPUAnchorDelta (dJointID, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz); /** * @brief Set the PU anchor as if the 2 bodies were already at [dx, dy, dz] appart. * @ingroup joints * * This function initialize the anchor and the relative position of each body * as if the position between body1 and body2 was already the projection of [dx, dy, dz] * along the Piston axis. (i.e as if the body1 was at its current position - [dx,dy,dy] when the * axis is set). * Ex: *
     * dReal offset = 3;
     * dVector3 axis;
     * dJointGetPUAxis(jId, axis);
     * dJointSetPUAnchor(jId, 0, 0, 0);
     * // If you request the position you will have: dJointGetPUPosition(jId) == 0
     * dJointSetPUAnchorOffset(jId, 0, 0, 0, axis[X]*offset, axis[Y]*offset, axis[Z]*offset);
     * // If you request the position you will have: dJointGetPUPosition(jId) == offset
     * 
    * @param j The PU joint for which the anchor point will be set * @param x The X position of the anchor point in world frame * @param y The Y position of the anchor point in world frame * @param z The Z position of the anchor point in world frame * @param dx A delta to be substracted to the X position as if the anchor was set * when body1 was at current_position[X] - dx * @param dx A delta to be substracted to the Y position as if the anchor was set * when body1 was at current_position[Y] - dy * @param dx A delta to be substracted to the Z position as if the anchor was set * when body1 was at current_position[Z] - dz */ ODE_API void dJointSetPUAnchorOffset (dJointID, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz); /** * @brief set the axis for the first axis or the universal articulation * @ingroup joints */ ODE_API void dJointSetPUAxis1 (dJointID, dReal x, dReal y, dReal z); /** * @brief set the axis for the second axis or the universal articulation * @ingroup joints */ ODE_API void dJointSetPUAxis2 (dJointID, dReal x, dReal y, dReal z); /** * @brief set the axis for the prismatic articulation * @ingroup joints */ ODE_API void dJointSetPUAxis3 (dJointID, dReal x, dReal y, dReal z); /** * @brief set the axis for the prismatic articulation * @ingroup joints * @note This function was added for convenience it is the same as * dJointSetPUAxis3 */ ODE_API void dJointSetPUAxisP (dJointID id, dReal x, dReal y, dReal z); /** * @brief set joint parameter * @ingroup joints * * @note parameterX where X equal 2 refer to parameter for second axis of the * universal articulation * @note parameterX where X equal 3 refer to parameter for prismatic * articulation */ ODE_API void dJointSetPUParam (dJointID, int parameter, dReal value); /** * @brief Applies the torque about the rotoide axis of the PU joint * * That is, it applies a torque with specified magnitude in the direction * of the rotoide axis, to body 1, and with the same magnitude but in opposite * direction to body 2. This function is just a wrapper for dBodyAddTorque()} * @ingroup joints */ ODE_API void dJointAddPUTorque (dJointID j, dReal torque); /** * @brief set the joint anchor * @ingroup joints */ ODE_API void dJointSetPistonAnchor (dJointID, dReal x, dReal y, dReal z); /** * @brief Set the Piston anchor as if the 2 bodies were already at [dx,dy, dz] appart. * @ingroup joints * * This function initialize the anchor and the relative position of each body * as if the position between body1 and body2 was already the projection of [dx, dy, dz] * along the Piston axis. (i.e as if the body1 was at its current position - [dx,dy,dy] when the * axis is set). * Ex: *
     * dReal offset = 3;
     * dVector3 axis;
     * dJointGetPistonAxis(jId, axis);
     * dJointSetPistonAnchor(jId, 0, 0, 0);
     * // If you request the position you will have: dJointGetPistonPosition(jId) == 0
     * dJointSetPistonAnchorOffset(jId, 0, 0, 0, axis[X]*offset, axis[Y]*offset, axis[Z]*offset);
     * // If you request the position you will have: dJointGetPistonPosition(jId) == offset
     * 
    * @param j The Piston joint for which the anchor point will be set * @param x The X position of the anchor point in world frame * @param y The Y position of the anchor point in world frame * @param z The Z position of the anchor point in world frame * @param dx A delta to be substracted to the X position as if the anchor was set * when body1 was at current_position[X] - dx * @param dx A delta to be substracted to the Y position as if the anchor was set * when body1 was at current_position[Y] - dy * @param dx A delta to be substracted to the Z position as if the anchor was set * when body1 was at current_position[Z] - dz */ ODE_API void dJointSetPistonAnchorOffset(dJointID j, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz); /** * @brief set the joint axis * @ingroup joints */ ODE_API void dJointSetPistonAxis (dJointID, dReal x, dReal y, dReal z); /** * This function set prismatic axis of the joint and also set the position * of the joint. * * @ingroup joints * @param j The joint affected by this function * @param x The x component of the axis * @param y The y component of the axis * @param z The z component of the axis * @param dx The Initial position of the prismatic join in the x direction * @param dy The Initial position of the prismatic join in the y direction * @param dz The Initial position of the prismatic join in the z direction */ ODE_API_DEPRECATED ODE_API void dJointSetPistonAxisDelta (dJointID j, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); /** * @brief set joint parameter * @ingroup joints */ ODE_API void dJointSetPistonParam (dJointID, int parameter, dReal value); /** * @brief Applies the given force in the slider's direction. * * That is, it applies a force with specified magnitude, in the direction of * prismatic's axis, to body1, and with the same magnitude but opposite * direction to body2. This function is just a wrapper for dBodyAddForce(). * @ingroup joints */ ODE_API void dJointAddPistonForce (dJointID joint, dReal force); /** * @brief Call this on the fixed joint after it has been attached to * remember the current desired relative offset and desired relative * rotation between the bodies. * @ingroup joints */ ODE_API void dJointSetFixed (dJointID); /* * @brief Sets joint parameter * * @ingroup joints */ ODE_API void dJointSetFixedParam (dJointID, int parameter, dReal value); /** * @brief set the nr of axes * @param num 0..3 * @ingroup joints */ ODE_API void dJointSetAMotorNumAxes (dJointID, int num); /** * @brief set axis * @ingroup joints */ ODE_API void dJointSetAMotorAxis (dJointID, int anum, int rel, dReal x, dReal y, dReal z); /** * @brief Tell the AMotor what the current angle is along axis anum. * * This function should only be called in dAMotorUser mode, because in this * mode the AMotor has no other way of knowing the joint angles. * The angle information is needed if stops have been set along the axis, * but it is not needed for axis motors. * @ingroup joints */ ODE_API void dJointSetAMotorAngle (dJointID, int anum, dReal angle); /** * @brief set joint parameter * @ingroup joints */ ODE_API void dJointSetAMotorParam (dJointID, int parameter, dReal value); /** * @brief set mode * @ingroup joints */ ODE_API void dJointSetAMotorMode (dJointID, int mode); /** * @brief Applies torque0 about the AMotor's axis 0, torque1 about the * AMotor's axis 1, and torque2 about the AMotor's axis 2. * @remarks * If the motor has fewer than three axes, the higher torques are ignored. * This function is just a wrapper for dBodyAddTorque(). * @ingroup joints */ ODE_API void dJointAddAMotorTorques (dJointID, dReal torque1, dReal torque2, dReal torque3); /** * @brief Set the number of axes that will be controlled by the LMotor. * @param num can range from 0 (which effectively deactivates the joint) to 3. * @ingroup joints */ ODE_API void dJointSetLMotorNumAxes (dJointID, int num); /** * @brief Set the AMotor axes. * @param anum selects the axis to change (0,1 or 2). * @param rel Each axis can have one of three ``relative orientation'' modes * \li 0: The axis is anchored to the global frame. * \li 1: The axis is anchored to the first body. * \li 2: The axis is anchored to the second body. * @remarks The axis vector is always specified in global coordinates * regardless of the setting of rel. * @ingroup joints */ ODE_API void dJointSetLMotorAxis (dJointID, int anum, int rel, dReal x, dReal y, dReal z); /** * @brief set joint parameter * @ingroup joints */ ODE_API void dJointSetLMotorParam (dJointID, int parameter, dReal value); /** * @ingroup joints */ ODE_API void dJointSetPlane2DXParam (dJointID, int parameter, dReal value); /** * @ingroup joints */ ODE_API void dJointSetPlane2DYParam (dJointID, int parameter, dReal value); /** * @ingroup joints */ ODE_API void dJointSetPlane2DAngleParam (dJointID, int parameter, dReal value); /** * @brief Get the joint anchor point, in world coordinates. * * This returns the point on body 1. If the joint is perfectly satisfied, * this will be the same as the point on body 2. */ ODE_API void dJointGetBallAnchor (dJointID, dVector3 result); /** * @brief Get the joint anchor point, in world coordinates. * * This returns the point on body 2. You can think of a ball and socket * joint as trying to keep the result of dJointGetBallAnchor() and * dJointGetBallAnchor2() the same. If the joint is perfectly satisfied, * this function will return the same value as dJointGetBallAnchor() to * within roundoff errors. dJointGetBallAnchor2() can be used, along with * dJointGetBallAnchor(), to see how far the joint has come apart. */ ODE_API void dJointGetBallAnchor2 (dJointID, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetBallParam (dJointID, int parameter); /** * @brief Get the hinge anchor point, in world coordinates. * * This returns the point on body 1. If the joint is perfectly satisfied, * this will be the same as the point on body 2. * @ingroup joints */ ODE_API void dJointGetHingeAnchor (dJointID, dVector3 result); /** * @brief Get the joint anchor point, in world coordinates. * @return The point on body 2. If the joint is perfectly satisfied, * this will return the same value as dJointGetHingeAnchor(). * If not, this value will be slightly different. * This can be used, for example, to see how far the joint has come apart. * @ingroup joints */ ODE_API void dJointGetHingeAnchor2 (dJointID, dVector3 result); /** * @brief get axis * @ingroup joints */ ODE_API void dJointGetHingeAxis (dJointID, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetHingeParam (dJointID, int parameter); /** * @brief Get the hinge angle. * * The angle is measured between the two bodies, or between the body and * the static environment. * The angle will be between -pi..pi. * Give the relative rotation with respect to the Hinge axis of Body 1 with * respect to Body 2. * When the hinge anchor or axis is set, the current position of the attached * bodies is examined and that position will be the zero angle. * @ingroup joints */ ODE_API dReal dJointGetHingeAngle (dJointID); /** * @brief Get the hinge angle time derivative. * @ingroup joints */ ODE_API dReal dJointGetHingeAngleRate (dJointID); /** * @brief Get the slider linear position (i.e. the slider's extension) * * When the axis is set, the current position of the attached bodies is * examined and that position will be the zero position. * The position is the distance, with respect to the zero position, * along the slider axis of body 1 with respect to * body 2. (A NULL body is replaced by the world). * @ingroup joints */ ODE_API dReal dJointGetSliderPosition (dJointID); /** * @brief Get the slider linear position's time derivative. * @ingroup joints */ ODE_API dReal dJointGetSliderPositionRate (dJointID); /** * @brief Get the slider axis * @ingroup joints */ ODE_API void dJointGetSliderAxis (dJointID, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetSliderParam (dJointID, int parameter); /** * @brief Get the joint anchor point, in world coordinates. * @return the point on body 1. If the joint is perfectly satisfied, * this will be the same as the point on body 2. * @ingroup joints */ ODE_API void dJointGetHinge2Anchor (dJointID, dVector3 result); /** * @brief Get the joint anchor point, in world coordinates. * This returns the point on body 2. If the joint is perfectly satisfied, * this will return the same value as dJointGetHinge2Anchor. * If not, this value will be slightly different. * This can be used, for example, to see how far the joint has come apart. * @ingroup joints */ ODE_API void dJointGetHinge2Anchor2 (dJointID, dVector3 result); /** * @brief Get joint axis * @ingroup joints */ ODE_API void dJointGetHinge2Axis1 (dJointID, dVector3 result); /** * @brief Get joint axis * @ingroup joints */ ODE_API void dJointGetHinge2Axis2 (dJointID, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetHinge2Param (dJointID, int parameter); /** * @brief Get angle * @ingroup joints */ ODE_API dReal dJointGetHinge2Angle1 (dJointID); /** * @brief Get angle * @ingroup joints */ ODE_API dReal dJointGetHinge2Angle2 (dJointID); /** * @brief Get time derivative of angle * @ingroup joints */ ODE_API dReal dJointGetHinge2Angle1Rate (dJointID); /** * @brief Get time derivative of angle * @ingroup joints */ ODE_API dReal dJointGetHinge2Angle2Rate (dJointID); /** * @brief Get the joint anchor point, in world coordinates. * @return the point on body 1. If the joint is perfectly satisfied, * this will be the same as the point on body 2. * @ingroup joints */ ODE_API void dJointGetUniversalAnchor (dJointID, dVector3 result); /** * @brief Get the joint anchor point, in world coordinates. * @return This returns the point on body 2. * @remarks * You can think of the ball and socket part of a universal joint as * trying to keep the result of dJointGetBallAnchor() and * dJointGetBallAnchor2() the same. If the joint is * perfectly satisfied, this function will return the same value * as dJointGetUniversalAnchor() to within roundoff errors. * dJointGetUniversalAnchor2() can be used, along with * dJointGetUniversalAnchor(), to see how far the joint has come apart. * @ingroup joints */ ODE_API void dJointGetUniversalAnchor2 (dJointID, dVector3 result); /** * @brief Get axis * @ingroup joints */ ODE_API void dJointGetUniversalAxis1 (dJointID, dVector3 result); /** * @brief Get axis * @ingroup joints */ ODE_API void dJointGetUniversalAxis2 (dJointID, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetUniversalParam (dJointID, int parameter); /** * @brief Get both angles at the same time. * @ingroup joints * * @param joint The universal joint for which we want to calculate the angles * @param angle1 The angle between the body1 and the axis 1 * @param angle2 The angle between the body2 and the axis 2 * * @note This function combine getUniversalAngle1 and getUniversalAngle2 together * and try to avoid redundant calculation */ ODE_API void dJointGetUniversalAngles (dJointID, dReal *angle1, dReal *angle2); /** * @brief Get angle * @ingroup joints */ ODE_API dReal dJointGetUniversalAngle1 (dJointID); /** * @brief Get angle * @ingroup joints */ ODE_API dReal dJointGetUniversalAngle2 (dJointID); /** * @brief Get time derivative of angle * @ingroup joints */ ODE_API dReal dJointGetUniversalAngle1Rate (dJointID); /** * @brief Get time derivative of angle * @ingroup joints */ ODE_API dReal dJointGetUniversalAngle2Rate (dJointID); /** * @brief Get the joint anchor point, in world coordinates. * @return the point on body 1. If the joint is perfectly satisfied, * this will be the same as the point on body 2. * @ingroup joints */ ODE_API void dJointGetPRAnchor (dJointID, dVector3 result); /** * @brief Get the PR linear position (i.e. the prismatic's extension) * * When the axis is set, the current position of the attached bodies is * examined and that position will be the zero position. * * The position is the "oriented" length between the * position = (Prismatic axis) dot_product [(body1 + offset) - (body2 + anchor2)] * * @ingroup joints */ ODE_API dReal dJointGetPRPosition (dJointID); /** * @brief Get the PR linear position's time derivative * * @ingroup joints */ ODE_API dReal dJointGetPRPositionRate (dJointID); /** * @brief Get the PR angular position (i.e. the twist between the 2 bodies) * * When the axis is set, the current position of the attached bodies is * examined and that position will be the zero position. * @ingroup joints */ ODE_API dReal dJointGetPRAngle (dJointID); /** * @brief Get the PR angular position's time derivative * * @ingroup joints */ ODE_API dReal dJointGetPRAngleRate (dJointID); /** * @brief Get the prismatic axis * @ingroup joints */ ODE_API void dJointGetPRAxis1 (dJointID, dVector3 result); /** * @brief Get the Rotoide axis * @ingroup joints */ ODE_API void dJointGetPRAxis2 (dJointID, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetPRParam (dJointID, int parameter); /** * @brief Get the joint anchor point, in world coordinates. * @return the point on body 1. If the joint is perfectly satisfied, * this will be the same as the point on body 2. * @ingroup joints */ ODE_API void dJointGetPUAnchor (dJointID, dVector3 result); /** * @brief Get the PU linear position (i.e. the prismatic's extension) * * When the axis is set, the current position of the attached bodies is * examined and that position will be the zero position. * * The position is the "oriented" length between the * position = (Prismatic axis) dot_product [(body1 + offset) - (body2 + anchor2)] * * @ingroup joints */ ODE_API dReal dJointGetPUPosition (dJointID); /** * @brief Get the PR linear position's time derivative * * @ingroup joints */ ODE_API dReal dJointGetPUPositionRate (dJointID); /** * @brief Get the first axis of the universal component of the joint * @ingroup joints */ ODE_API void dJointGetPUAxis1 (dJointID, dVector3 result); /** * @brief Get the second axis of the Universal component of the joint * @ingroup joints */ ODE_API void dJointGetPUAxis2 (dJointID, dVector3 result); /** * @brief Get the prismatic axis * @ingroup joints */ ODE_API void dJointGetPUAxis3 (dJointID, dVector3 result); /** * @brief Get the prismatic axis * @ingroup joints * * @note This function was added for convenience it is the same as * dJointGetPUAxis3 */ ODE_API void dJointGetPUAxisP (dJointID id, dVector3 result); /** * @brief Get both angles at the same time. * @ingroup joints * * @param joint The Prismatic universal joint for which we want to calculate the angles * @param angle1 The angle between the body1 and the axis 1 * @param angle2 The angle between the body2 and the axis 2 * * @note This function combine dJointGetPUAngle1 and dJointGetPUAngle2 together * and try to avoid redundant calculation */ ODE_API void dJointGetPUAngles (dJointID, dReal *angle1, dReal *angle2); /** * @brief Get angle * @ingroup joints */ ODE_API dReal dJointGetPUAngle1 (dJointID); /** * @brief * @brief Get time derivative of angle1 * * @ingroup joints */ ODE_API dReal dJointGetPUAngle1Rate (dJointID); /** * @brief Get angle * @ingroup joints */ ODE_API dReal dJointGetPUAngle2 (dJointID); /** * @brief * @brief Get time derivative of angle2 * * @ingroup joints */ ODE_API dReal dJointGetPUAngle2Rate (dJointID); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetPUParam (dJointID, int parameter); /** * @brief Get the Piston linear position (i.e. the piston's extension) * * When the axis is set, the current position of the attached bodies is * examined and that position will be the zero position. * @ingroup joints */ ODE_API dReal dJointGetPistonPosition (dJointID); /** * @brief Get the piston linear position's time derivative. * @ingroup joints */ ODE_API dReal dJointGetPistonPositionRate (dJointID); /** * @brief Get the Piston angular position (i.e. the twist between the 2 bodies) * * When the axis is set, the current position of the attached bodies is * examined and that position will be the zero position. * @ingroup joints */ ODE_API dReal dJointGetPistonAngle (dJointID); /** * @brief Get the piston angular position's time derivative. * @ingroup joints */ ODE_API dReal dJointGetPistonAngleRate (dJointID); /** * @brief Get the joint anchor * * This returns the point on body 1. If the joint is perfectly satisfied, * this will be the same as the point on body 2 in direction perpendicular * to the prismatic axis. * * @ingroup joints */ ODE_API void dJointGetPistonAnchor (dJointID, dVector3 result); /** * @brief Get the joint anchor w.r.t. body 2 * * This returns the point on body 2. You can think of a Piston * joint as trying to keep the result of dJointGetPistonAnchor() and * dJointGetPistonAnchor2() the same in the direction perpendicular to the * pirsmatic axis. If the joint is perfectly satisfied, * this function will return the same value as dJointGetPistonAnchor() to * within roundoff errors. dJointGetPistonAnchor2() can be used, along with * dJointGetPistonAnchor(), to see how far the joint has come apart. * * @ingroup joints */ ODE_API void dJointGetPistonAnchor2 (dJointID, dVector3 result); /** * @brief Get the prismatic axis (This is also the rotoide axis. * @ingroup joints */ ODE_API void dJointGetPistonAxis (dJointID, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetPistonParam (dJointID, int parameter); /** * @brief Get the number of angular axes that will be controlled by the * AMotor. * @param num can range from 0 (which effectively deactivates the * joint) to 3. * This is automatically set to 3 in dAMotorEuler mode. * @ingroup joints */ ODE_API int dJointGetAMotorNumAxes (dJointID); /** * @brief Get the AMotor axes. * @param anum selects the axis to change (0,1 or 2). * @param rel Each axis can have one of three ``relative orientation'' modes. * \li 0: The axis is anchored to the global frame. * \li 1: The axis is anchored to the first body. * \li 2: The axis is anchored to the second body. * @ingroup joints */ ODE_API void dJointGetAMotorAxis (dJointID, int anum, dVector3 result); /** * @brief Get axis * @remarks * The axis vector is always specified in global coordinates regardless * of the setting of rel. * There are two GetAMotorAxis functions, one to return the axis and one to * return the relative mode. * * For dAMotorEuler mode: * \li Only axes 0 and 2 need to be set. Axis 1 will be determined automatically at each time step. * \li Axes 0 and 2 must be perpendicular to each other. * \li Axis 0 must be anchored to the first body, axis 2 must be anchored to the second body. * @ingroup joints */ ODE_API int dJointGetAMotorAxisRel (dJointID, int anum); /** * @brief Get the current angle for axis. * @remarks * In dAMotorUser mode this is simply the value that was set with * dJointSetAMotorAngle(). * In dAMotorEuler mode this is the corresponding euler angle. * @ingroup joints */ ODE_API dReal dJointGetAMotorAngle (dJointID, int anum); /** * @brief Get the current angle rate for axis anum. * @remarks * In dAMotorUser mode this is always zero, as not enough information is * available. * In dAMotorEuler mode this is the corresponding euler angle rate. * @ingroup joints */ ODE_API dReal dJointGetAMotorAngleRate (dJointID, int anum); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetAMotorParam (dJointID, int parameter); /** * @brief Get the angular motor mode. * @param mode must be one of the following constants: * \li dAMotorUser The AMotor axes and joint angle settings are entirely * controlled by the user. This is the default mode. * \li dAMotorEuler Euler angles are automatically computed. * The axis a1 is also automatically computed. * The AMotor axes must be set correctly when in this mode, * as described below. * When this mode is initially set the current relative orientations * of the bodies will correspond to all euler angles at zero. * @ingroup joints */ ODE_API int dJointGetAMotorMode (dJointID); /** * @brief Get nr of axes. * @ingroup joints */ ODE_API int dJointGetLMotorNumAxes (dJointID); /** * @brief Get axis. * @ingroup joints */ ODE_API void dJointGetLMotorAxis (dJointID, int anum, dVector3 result); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetLMotorParam (dJointID, int parameter); /** * @brief get joint parameter * @ingroup joints */ ODE_API dReal dJointGetFixedParam (dJointID, int parameter); /** * @brief get the contact point of the first wheel of the Transmission joint. * @ingroup joints */ ODE_API void dJointGetTransmissionContactPoint1(dJointID, dVector3 result); /** * @brief get contact point of the second wheel of the Transmission joint. * @ingroup joints */ ODE_API void dJointGetTransmissionContactPoint2(dJointID, dVector3 result); /** * @brief set the first axis for the Transmission joint * @remarks This is the axis around which the first body is allowed to * revolve and is attached to it. It is given in global coordinates * and can only be set explicitly in intersecting-axes mode. For the * parallel-axes and chain modes which share one common axis of * revolution for both gears dJointSetTransmissionAxis should be used. * @ingroup joints */ ODE_API void dJointSetTransmissionAxis1(dJointID, dReal x, dReal y, dReal z); /** * @brief get first axis for the Transmission joint * @remarks In parallel-axes and chain mode the common axis with * respect to the first body is returned. If the joint constraint is * satisfied it should be the same as the axis return with * dJointGetTransmissionAxis2 or dJointGetTransmissionAxis. * @ingroup joints */ ODE_API void dJointGetTransmissionAxis1(dJointID, dVector3 result); /** * @brief set second axis for the Transmission joint * @remarks This is the axis around which the second body is allowed * to revolve and is attached to it. It is given in global * coordinates and can only be set explicitly in intersecting-axes * mode. For the parallel-axes and chain modes which share one common * axis of revolution for both gears dJointSetTransmissionAxis should * be used. * @ingroup joints */ ODE_API void dJointSetTransmissionAxis2(dJointID, dReal x, dReal y, dReal z); /** * @brief get second axis for the Transmission joint * @remarks In parallel-axes and chain mode the common axis with * respect to the second body is returned. If the joint constraint is * satisfied it should be the same as the axis return with * dJointGetTransmissionAxis1 or dJointGetTransmissionAxis. * @ingroup joints */ ODE_API void dJointGetTransmissionAxis2(dJointID, dVector3 result); /** * @brief set the first anchor for the Transmission joint * @remarks This is the point of attachment of the wheel on the * first body. It is given in global coordinates. * @ingroup joints */ ODE_API void dJointSetTransmissionAnchor1(dJointID, dReal x, dReal y, dReal z); /** * @brief get the first anchor of the Transmission joint * @ingroup joints */ ODE_API void dJointGetTransmissionAnchor1(dJointID, dVector3 result); /** * @brief set the second anchor for the Transmission joint * @remarks This is the point of attachment of the wheel on the * second body. It is given in global coordinates. * @ingroup joints */ ODE_API void dJointSetTransmissionAnchor2(dJointID, dReal x, dReal y, dReal z); /** * @brief get the second anchor for the Transmission joint * @ingroup joints */ ODE_API void dJointGetTransmissionAnchor2(dJointID, dVector3 result); /** * @brief set a Transmission joint parameter * @ingroup joints */ ODE_API void dJointSetTransmissionParam(dJointID, int parameter, dReal value); /** * @brief get a Transmission joint parameter * @ingroup joints */ ODE_API dReal dJointGetTransmissionParam(dJointID, int parameter); /** * @brief set the Transmission joint mode * @remarks The mode can be one of dTransmissionParallelAxes, * dTransmissionIntersectingAxes and dTransmissionChainDrive simulating a * set of parallel-axes gears, intersecting-axes beveled gears or * chain and sprockets respectively. * @ingroup joints */ ODE_API void dJointSetTransmissionMode( dJointID j, int mode ); /** * @brief get the Transmission joint mode * @ingroup joints */ ODE_API int dJointGetTransmissionMode( dJointID j ); /** * @brief set the Transmission ratio * @remarks This is the ratio of the angular speed of the first gear * to that of the second gear. It can only be set explicitly in * parallel-axes mode. In intersecting-axes mode the ratio is defined * implicitly by the initial configuration of the wheels and in chain * mode it is defined implicitly be the wheel radii. * @ingroup joints */ ODE_API void dJointSetTransmissionRatio( dJointID j, dReal ratio ); /** * @brief get the Transmission joint ratio * @ingroup joints */ ODE_API dReal dJointGetTransmissionRatio( dJointID j ); /** * @brief set the common axis for both wheels of the Transmission joint * @remarks This sets the common axis of revolution for both wheels * and should only be used in parallel-axes or chain mode. For * intersecting-axes mode where each wheel axis needs to be specified * individually dJointSetTransmissionAxis1 and * dJointSetTransmissionAxis2 should be used. The axis is given in * global coordinates * @ingroup joints */ ODE_API void dJointSetTransmissionAxis( dJointID j, dReal x, dReal y, dReal z ); /** * @brief get the common axis for both wheels of the Transmission joint * @ingroup joints */ ODE_API void dJointGetTransmissionAxis( dJointID j, dVector3 result ); /** * @brief get the phase, that is the traversed angle for the first * wheel of the Transmission joint * @ingroup joints */ ODE_API dReal dJointGetTransmissionAngle1( dJointID j ); /** * @brief get the phase, that is the traversed angle for the second * wheel of the Transmission joint * @ingroup joints */ ODE_API dReal dJointGetTransmissionAngle2( dJointID j ); /** * @brief get the radius of the first wheel of the Transmission joint * @ingroup joints */ ODE_API dReal dJointGetTransmissionRadius1( dJointID j ); /** * @brief get the radius of the second wheel of the Transmission joint * @ingroup joints */ ODE_API dReal dJointGetTransmissionRadius2( dJointID j ); /** * @brief set the radius of the first wheel of the Transmission joint * @remarks The wheel radii can only be set explicitly in chain mode. * In the other modes they're defined implicitly by the initial * configuration and ratio of the wheels. * @ingroup joints */ ODE_API void dJointSetTransmissionRadius1( dJointID j, dReal radius ); /** * @brief set the radius of the second wheel of the Transmission joint * @remarks The wheel radii can only be set explicitly in chain mode. * In the other modes they're defined implicitly by the initial * configuration and ratio of the wheels. * @ingroup joints */ ODE_API void dJointSetTransmissionRadius2( dJointID j, dReal radius ); /** * @brief get the backlash of the Transmission joint * @ingroup joints */ ODE_API dReal dJointGetTransmissionBacklash( dJointID j ); /** * @brief set the backlash of the Transmission joint * @remarks Backlash is the clearance in the mesh of the wheels of the * transmission and is defined as the maximum distance that the * geometric contact point can travel without any actual contact or * transfer of power between the wheels. This can be converted in * degrees of revolution for each wheel by dividing by the wheel's * radius. To further illustrate this consider the situation where a * wheel of radius r_1 is driving another wheel of radius r_2 and * there is an amount of backlash equal to b in their mesh. If the * driving wheel were to instantaneously stop there would be no * contact and hence the driven wheel would continue to turn for * another b / r_2 radians until all the backlash in the mesh was take * up and contact restored with the relationship of driving and driven * wheel reversed. The backlash is therefore given in untis of * length. * @ingroup joints */ ODE_API void dJointSetTransmissionBacklash( dJointID j, dReal backlash ); /** * @brief set anchor1 for double ball joint * @ingroup joints */ ODE_API void dJointSetDBallAnchor1(dJointID, dReal x, dReal y, dReal z); /** * @brief set anchor2 for double ball joint * @ingroup joints */ ODE_API void dJointSetDBallAnchor2(dJointID, dReal x, dReal y, dReal z); /** * @brief get anchor1 from double ball joint * @ingroup joints */ ODE_API void dJointGetDBallAnchor1(dJointID, dVector3 result); /** * @brief get anchor2 from double ball joint * @ingroup joints */ ODE_API void dJointGetDBallAnchor2(dJointID, dVector3 result); /** * @brief get the target distance from double ball joint * @ingroup joints */ ODE_API dReal dJointGetDBallDistance(dJointID); /** * @brief set the target distance for the double ball joint * @ingroup joints */ ODE_API void dJointSetDBallDistance(dJointID, dReal dist); /** * @brief set double ball joint parameter * @ingroup joints */ ODE_API void dJointSetDBallParam(dJointID, int parameter, dReal value); /** * @brief get double ball joint parameter * @ingroup joints */ ODE_API dReal dJointGetDBallParam(dJointID, int parameter); /** * @brief set axis for double hinge joint * @ingroup joints */ ODE_API void dJointSetDHingeAxis(dJointID, dReal x, dReal y, dReal z); /** * @brief get axis for double hinge joint * @ingroup joints */ ODE_API void dJointGetDHingeAxis(dJointID, dVector3 result); /** * @brief set anchor1 for double hinge joint * @ingroup joints */ ODE_API void dJointSetDHingeAnchor1(dJointID, dReal x, dReal y, dReal z); /** * @brief set anchor2 for double hinge joint * @ingroup joints */ ODE_API void dJointSetDHingeAnchor2(dJointID, dReal x, dReal y, dReal z); /** * @brief get anchor1 from double hinge joint * @ingroup joints */ ODE_API void dJointGetDHingeAnchor1(dJointID, dVector3 result); /** * @brief get anchor2 from double hinge joint * @ingroup joints */ ODE_API void dJointGetDHingeAnchor2(dJointID, dVector3 result); /** * @brief get the set distance from double hinge joint * @ingroup joints */ ODE_API dReal dJointGetDHingeDistance(dJointID); /** * @brief set double hinge joint parameter * @ingroup joints */ ODE_API void dJointSetDHingeParam(dJointID, int parameter, dReal value); /** * @brief get double hinge joint parameter * @ingroup joints */ ODE_API dReal dJointGetDHingeParam(dJointID, int parameter); /** * @ingroup joints */ ODE_API dJointID dConnectingJoint (dBodyID, dBodyID); /** * @ingroup joints */ ODE_API int dConnectingJointList (dBodyID, dBodyID, dJointID*); /** * @brief Utility function * @return 1 if the two bodies are connected together by * a joint, otherwise return 0. * @ingroup joints */ ODE_API int dAreConnected (dBodyID, dBodyID); /** * @brief Utility function * @return 1 if the two bodies are connected together by * a joint that does not have type @arg{joint_type}, otherwise return 0. * @param body1 A body to check. * @param body2 A body to check. * @param joint_type is a dJointTypeXXX constant. * This is useful for deciding whether to add contact joints between two bodies: * if they are already connected by non-contact joints then it may not be * appropriate to add contacts, however it is okay to add more contact between- * bodies that already have contacts. * @ingroup joints */ ODE_API int dAreConnectedExcluding (dBodyID body1, dBodyID body2, int joint_type); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/ode.h0000644000000000000000000000433012635011627014020 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_ODE_H_ #define _ODE_ODE_H_ /* include *everything* here */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cplusplus # include # include #endif #endif ode-0.14/include/ode/odeconfig.h0000644000000000000000000001154712635011627015216 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_ODECONFIG_H_ #define _ODE_ODECONFIG_H_ /* Pull in the standard headers */ #include #include #include #include #include #include #include #include #include #if defined(ODE_DLL) || defined(ODE_LIB) #define __ODE__ #endif /* Define a DLL export symbol for those platforms that need it */ #if defined(_MSC_VER) || (defined(__GNUC__) && defined(_WIN32)) #if defined(ODE_DLL) #define ODE_API __declspec(dllexport) #elif !defined(ODE_LIB) #define ODE_DLL_API __declspec(dllimport) #endif #endif #if !defined(ODE_API) #define ODE_API #endif #if defined(_MSC_VER) # define ODE_API_DEPRECATED __declspec(deprecated) #elif defined (__GNUC__) && ( (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) ) # define ODE_API_DEPRECATED __attribute__((__deprecated__)) #else # define ODE_API_DEPRECATED #endif #define ODE_PURE_INLINE static __inline #define ODE_INLINE __inline #if defined(__cplusplus) #define ODE_EXTERN_C extern "C" #else #define ODE_EXTERN_C #endif /* Well-defined common data types...need to define for 64 bit systems */ #if defined(_M_IA64) || defined(__ia64__) || defined(_M_AMD64) || defined(__x86_64__) #define X86_64_SYSTEM 1 #if defined(_MSC_VER) typedef __int64 dint64; typedef unsigned __int64 duint64; #else typedef long long dint64; typedef unsigned long long duint64; #endif typedef int dint32; typedef unsigned int duint32; typedef short dint16; typedef unsigned short duint16; typedef signed char dint8; typedef unsigned char duint8; #else #if defined(_MSC_VER) typedef __int64 dint64; typedef unsigned __int64 duint64; #else typedef long long dint64; typedef unsigned long long duint64; #endif typedef int dint32; typedef unsigned int duint32; typedef short dint16; typedef unsigned short duint16; typedef signed char dint8; typedef unsigned char duint8; #endif /* Define the dInfinity macro */ #ifdef INFINITY #ifdef dSINGLE #define dInfinity ((float)INFINITY) #else #define dInfinity ((double)INFINITY) #endif #elif defined(HUGE_VAL) #ifdef dSINGLE #ifdef HUGE_VALF #define dInfinity HUGE_VALF #else #define dInfinity ((float)HUGE_VAL) #endif #else #define dInfinity HUGE_VAL #endif #else #ifdef dSINGLE #define dInfinity ((float)(1.0/0.0)) #else #define dInfinity (1.0/0.0) #endif #endif /* Define the dNaN macro */ #ifdef NAN #define dNaN NAN #else #ifdef dSINGLE #define dNaN ((float)(dInfinity - dInfinity)) #else #define dNaN (dInfinity - dInfinity) #endif #endif /* Visual C does not define these functions */ #if defined(_MSC_VER) #define _ode_copysignf(x, y) ((float)_copysign(x, y)) #define _ode_copysign(x, y) _copysign(x, y) #define _ode_nextafterf(x, y) _nextafterf(x, y) #define _ode_nextafter(x, y) _nextafter(x, y) #if !defined(_WIN64) && defined(dSINGLE) #define _ODE__NEXTAFTERF_REQUIRED ODE_EXTERN_C float _nextafterf(float x, float y); #endif #else #define _ode_copysignf(x, y) copysignf(x, y) #define _ode_copysign(x, y) copysign(x, y) #define _ode_nextafterf(x, y) nextafterf(x, y) #define _ode_nextafter(x, y) nextafter(x, y) #endif #endif ode-0.14/include/ode/odecpp.h0000644000000000000000000014533112635011627014532 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* C++ interface for non-collision stuff */ #ifndef _ODE_ODECPP_H_ #define _ODE_ODECPP_H_ #ifdef __cplusplus //namespace ode { class dWorldSimpleIDContainer { protected: dWorldID _id; dWorldSimpleIDContainer(): _id(0) {} ~dWorldSimpleIDContainer() { destroy(); } void destroy() { if (_id) { dWorldDestroy(_id); _id = 0; } } }; class dWorldDynamicIDContainer: public dWorldSimpleIDContainer { protected: virtual ~dWorldDynamicIDContainer() {} }; template class dWorldTemplate: public dWorldTemplateBase { // intentionally undefined, don't use these dWorldTemplate (const dWorldTemplate &); void operator= (const dWorldTemplate &); protected: dWorldID get_id() const { return dWorldTemplateBase::_id; } void set_id(dWorldID value) { dWorldTemplateBase::_id = value; } public: dWorldTemplate() { set_id(dWorldCreate()); } dWorldID id() const { return get_id(); } operator dWorldID() const { return get_id(); } void setGravity (dReal x, dReal y, dReal z) { dWorldSetGravity (get_id(), x, y, z); } void setGravity (const dVector3 g) { setGravity (g[0], g[1], g[2]); } void getGravity (dVector3 g) const { dWorldGetGravity (get_id(), g); } void setERP (dReal erp) { dWorldSetERP(get_id(), erp); } dReal getERP() const { return dWorldGetERP(get_id()); } void setCFM (dReal cfm) { dWorldSetCFM(get_id(), cfm); } dReal getCFM() const { return dWorldGetCFM(get_id()); } void step (dReal stepsize) { dWorldStep (get_id(), stepsize); } void quickStep(dReal stepsize) { dWorldQuickStep (get_id(), stepsize); } void setQuickStepNumIterations(int num) { dWorldSetQuickStepNumIterations (get_id(), num); } int getQuickStepNumIterations() const { return dWorldGetQuickStepNumIterations (get_id()); } void setQuickStepW(dReal over_relaxation) { dWorldSetQuickStepW (get_id(), over_relaxation); } dReal getQuickStepW() const { return dWorldGetQuickStepW (get_id()); } void setAutoDisableLinearThreshold (dReal threshold) { dWorldSetAutoDisableLinearThreshold (get_id(), threshold); } dReal getAutoDisableLinearThreshold() const { return dWorldGetAutoDisableLinearThreshold (get_id()); } void setAutoDisableAngularThreshold (dReal threshold) { dWorldSetAutoDisableAngularThreshold (get_id(), threshold); } dReal getAutoDisableAngularThreshold() const { return dWorldGetAutoDisableAngularThreshold (get_id()); } void setAutoDisableSteps (int steps) { dWorldSetAutoDisableSteps (get_id(), steps); } int getAutoDisableSteps() const { return dWorldGetAutoDisableSteps (get_id()); } void setAutoDisableTime (dReal time) { dWorldSetAutoDisableTime (get_id(), time); } dReal getAutoDisableTime() const { return dWorldGetAutoDisableTime (get_id()); } void setAutoDisableFlag (int do_auto_disable) { dWorldSetAutoDisableFlag (get_id(), do_auto_disable); } int getAutoDisableFlag() const { return dWorldGetAutoDisableFlag (get_id()); } dReal getLinearDampingThreshold() const { return dWorldGetLinearDampingThreshold(get_id()); } void setLinearDampingThreshold(dReal threshold) { dWorldSetLinearDampingThreshold(get_id(), threshold); } dReal getAngularDampingThreshold() const { return dWorldGetAngularDampingThreshold(get_id()); } void setAngularDampingThreshold(dReal threshold) { dWorldSetAngularDampingThreshold(get_id(), threshold); } dReal getLinearDamping() const { return dWorldGetLinearDamping(get_id()); } void setLinearDamping(dReal scale) { dWorldSetLinearDamping(get_id(), scale); } dReal getAngularDamping() const { return dWorldGetAngularDamping(get_id()); } void setAngularDamping(dReal scale) { dWorldSetAngularDamping(get_id(), scale); } void setDamping(dReal linear_scale, dReal angular_scale) { dWorldSetDamping(get_id(), linear_scale, angular_scale); } dReal getMaxAngularSpeed() const { return dWorldGetMaxAngularSpeed(get_id()); } void setMaxAngularSpeed(dReal max_speed) { dWorldSetMaxAngularSpeed(get_id(), max_speed); } void setContactSurfaceLayer(dReal depth) { dWorldSetContactSurfaceLayer (get_id(), depth); } dReal getContactSurfaceLayer() const { return dWorldGetContactSurfaceLayer (get_id()); } void impulseToForce (dReal stepsize, dReal ix, dReal iy, dReal iz, dVector3 force) { dWorldImpulseToForce (get_id(), stepsize, ix, iy, iz, force); } }; class dBodySimpleIDContainer { protected: dBodyID _id; dBodySimpleIDContainer(): _id(0) {} ~dBodySimpleIDContainer() { destroy(); } void destroy() { if (_id) { dBodyDestroy(_id); _id = 0; } } }; class dBodyDynamicIDContainer: public dBodySimpleIDContainer { protected: virtual ~dBodyDynamicIDContainer() {} }; template class dBodyTemplate: public dBodyTemplateBase { // intentionally undefined, don't use these dBodyTemplate (const dBodyTemplate &); void operator= (const dBodyTemplate &); protected: dBodyID get_id() const { return dBodyTemplateBase::_id; } void set_id(dBodyID value) { dBodyTemplateBase::_id = value; } void destroy() { dBodyTemplateBase::destroy(); } public: dBodyTemplate() { } dBodyTemplate (dWorldID world) { set_id(dBodyCreate(world)); } dBodyTemplate (dWorldTemplate& world) { set_id(dBodyCreate(world.id())); } void create (dWorldID world) { destroy(); set_id(dBodyCreate(world)); } void create (dWorldTemplate& world) { create(world.id()); } dBodyID id() const { return get_id(); } operator dBodyID() const { return get_id(); } void setData (void *data) { dBodySetData (get_id(), data); } void *getData() const { return dBodyGetData (get_id()); } void setPosition (dReal x, dReal y, dReal z) { dBodySetPosition (get_id(), x, y, z); } void setPosition (const dVector3 p) { setPosition(p[0], p[1], p[2]); } void setRotation (const dMatrix3 R) { dBodySetRotation (get_id(), R); } void setQuaternion (const dQuaternion q) { dBodySetQuaternion (get_id(), q); } void setLinearVel (dReal x, dReal y, dReal z) { dBodySetLinearVel (get_id(), x, y, z); } void setLinearVel (const dVector3 v) { setLinearVel(v[0], v[1], v[2]); } void setAngularVel (dReal x, dReal y, dReal z) { dBodySetAngularVel (get_id(), x, y, z); } void setAngularVel (const dVector3 v) { setAngularVel (v[0], v[1], v[2]); } const dReal * getPosition() const { return dBodyGetPosition (get_id()); } const dReal * getRotation() const { return dBodyGetRotation (get_id()); } const dReal * getQuaternion() const { return dBodyGetQuaternion (get_id()); } const dReal * getLinearVel() const { return dBodyGetLinearVel (get_id()); } const dReal * getAngularVel() const { return dBodyGetAngularVel (get_id()); } void setMass (const dMass *mass) { dBodySetMass (get_id(), mass); } void setMass (const dMass &mass) { setMass (&mass); } dMass getMass () const { dMass mass; dBodyGetMass (get_id(), &mass); return mass; } void addForce (dReal fx, dReal fy, dReal fz) { dBodyAddForce (get_id(), fx, fy, fz); } void addForce (const dVector3 f) { addForce (f[0], f[1], f[2]); } void addTorque (dReal fx, dReal fy, dReal fz) { dBodyAddTorque (get_id(), fx, fy, fz); } void addTorque (const dVector3 t) { addTorque(t[0], t[1], t[2]); } void addRelForce (dReal fx, dReal fy, dReal fz) { dBodyAddRelForce (get_id(), fx, fy, fz); } void addRelForce (const dVector3 f) { addRelForce (f[0], f[1], f[2]); } void addRelTorque (dReal fx, dReal fy, dReal fz) { dBodyAddRelTorque (get_id(), fx, fy, fz); } void addRelTorque (const dVector3 t) { addRelTorque (t[0], t[1], t[2]); } void addForceAtPos (dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dBodyAddForceAtPos (get_id(), fx, fy, fz, px, py, pz); } void addForceAtPos (const dVector3 f, const dVector3 p) { addForceAtPos (f[0], f[1], f[2], p[0], p[1], p[2]); } void addForceAtRelPos (dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dBodyAddForceAtRelPos (get_id(), fx, fy, fz, px, py, pz); } void addForceAtRelPos (const dVector3 f, const dVector3 p) { addForceAtRelPos (f[0], f[1], f[2], p[0], p[1], p[2]); } void addRelForceAtPos (dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dBodyAddRelForceAtPos (get_id(), fx, fy, fz, px, py, pz); } void addRelForceAtPos (const dVector3 f, const dVector3 p) { addRelForceAtPos (f[0], f[1], f[2], p[0], p[1], p[2]); } void addRelForceAtRelPos (dReal fx, dReal fy, dReal fz, dReal px, dReal py, dReal pz) { dBodyAddRelForceAtRelPos (get_id(), fx, fy, fz, px, py, pz); } void addRelForceAtRelPos (const dVector3 f, const dVector3 p) { addRelForceAtRelPos (f[0], f[1], f[2], p[0], p[1], p[2]); } const dReal * getForce() const { return dBodyGetForce(get_id()); } const dReal * getTorque() const { return dBodyGetTorque(get_id()); } void setForce (dReal x, dReal y, dReal z) { dBodySetForce (get_id(), x, y, z); } void setForce (const dVector3 f) { setForce (f[0], f[1], f[2]); } void setTorque (dReal x, dReal y, dReal z) { dBodySetTorque (get_id(), x, y, z); } void setTorque (const dVector3 t) { setTorque (t[0], t[1], t[2]); } void setDynamic() { dBodySetDynamic (get_id()); } void setKinematic() { dBodySetKinematic (get_id()); } bool isKinematic() const { return dBodyIsKinematic (get_id()) != 0; } void enable() { dBodyEnable (get_id()); } void disable() { dBodyDisable (get_id()); } bool isEnabled() const { return dBodyIsEnabled (get_id()) != 0; } void getRelPointPos (dReal px, dReal py, dReal pz, dVector3 result) const { dBodyGetRelPointPos (get_id(), px, py, pz, result); } void getRelPointPos (const dVector3 p, dVector3 result) const { getRelPointPos (p[0], p[1], p[2], result); } void getRelPointVel (dReal px, dReal py, dReal pz, dVector3 result) const { dBodyGetRelPointVel (get_id(), px, py, pz, result); } void getRelPointVel (const dVector3 p, dVector3 result) const { getRelPointVel (p[0], p[1], p[2], result); } void getPointVel (dReal px, dReal py, dReal pz, dVector3 result) const { dBodyGetPointVel (get_id(), px, py, pz, result); } void getPointVel (const dVector3 p, dVector3 result) const { getPointVel (p[0], p[1], p[2], result); } void getPosRelPoint (dReal px, dReal py, dReal pz, dVector3 result) const { dBodyGetPosRelPoint (get_id(), px, py, pz, result); } void getPosRelPoint (const dVector3 p, dVector3 result) const { getPosRelPoint (p[0], p[1], p[2], result); } void vectorToWorld (dReal px, dReal py, dReal pz, dVector3 result) const { dBodyVectorToWorld (get_id(), px, py, pz, result); } void vectorToWorld (const dVector3 p, dVector3 result) const { vectorToWorld (p[0], p[1], p[2], result); } void vectorFromWorld (dReal px, dReal py, dReal pz, dVector3 result) const { dBodyVectorFromWorld (get_id(), px, py, pz, result); } void vectorFromWorld (const dVector3 p, dVector3 result) const { vectorFromWorld (p[0], p[1], p[2], result); } void setFiniteRotationMode (bool mode) { dBodySetFiniteRotationMode (get_id(), mode); } void setFiniteRotationAxis (dReal x, dReal y, dReal z) { dBodySetFiniteRotationAxis (get_id(), x, y, z); } void setFiniteRotationAxis (const dVector3 a) { setFiniteRotationAxis (a[0], a[1], a[2]); } bool getFiniteRotationMode() const { return dBodyGetFiniteRotationMode (get_id()) != 0; } void getFiniteRotationAxis (dVector3 result) const { dBodyGetFiniteRotationAxis (get_id(), result); } int getNumJoints() const { return dBodyGetNumJoints (get_id()); } dJointID getJoint (int index) const { return dBodyGetJoint (get_id(), index); } void setGravityMode (bool mode) { dBodySetGravityMode (get_id(), mode); } bool getGravityMode() const { return dBodyGetGravityMode (get_id()) != 0; } bool isConnectedTo (dBodyID body) const { return dAreConnected (get_id(), body) != 0; } void setAutoDisableLinearThreshold (dReal threshold) { dBodySetAutoDisableLinearThreshold (get_id(), threshold); } dReal getAutoDisableLinearThreshold() const { return dBodyGetAutoDisableLinearThreshold (get_id()); } void setAutoDisableAngularThreshold (dReal threshold) { dBodySetAutoDisableAngularThreshold (get_id(), threshold); } dReal getAutoDisableAngularThreshold() const { return dBodyGetAutoDisableAngularThreshold (get_id()); } void setAutoDisableSteps (int steps) { dBodySetAutoDisableSteps (get_id(), steps); } int getAutoDisableSteps() const { return dBodyGetAutoDisableSteps (get_id()); } void setAutoDisableTime (dReal time) { dBodySetAutoDisableTime (get_id(), time); } dReal getAutoDisableTime() const { return dBodyGetAutoDisableTime (get_id()); } void setAutoDisableFlag (bool do_auto_disable) { dBodySetAutoDisableFlag (get_id(), do_auto_disable); } bool getAutoDisableFlag() const { return dBodyGetAutoDisableFlag (get_id()) != 0; } dReal getLinearDamping() const { return dBodyGetLinearDamping(get_id()); } void setLinearDamping(dReal scale) { dBodySetLinearDamping(get_id(), scale); } dReal getAngularDamping() const { return dBodyGetAngularDamping(get_id()); } void setAngularDamping(dReal scale) { dBodySetAngularDamping(get_id(), scale); } void setDamping(dReal linear_scale, dReal angular_scale) { dBodySetDamping(get_id(), linear_scale, angular_scale); } dReal getLinearDampingThreshold() const { return dBodyGetLinearDampingThreshold(get_id()); } void setLinearDampingThreshold(dReal threshold) const { dBodySetLinearDampingThreshold(get_id(), threshold); } dReal getAngularDampingThreshold() const { return dBodyGetAngularDampingThreshold(get_id()); } void setAngularDampingThreshold(dReal threshold) { dBodySetAngularDampingThreshold(get_id(), threshold); } void setDampingDefaults() { dBodySetDampingDefaults(get_id()); } dReal getMaxAngularSpeed() const { return dBodyGetMaxAngularSpeed(get_id()); } void setMaxAngularSpeed(dReal max_speed) { dBodySetMaxAngularSpeed(get_id(), max_speed); } bool getGyroscopicMode() const { return dBodyGetGyroscopicMode(get_id()) != 0; } void setGyroscopicMode(bool mode) { dBodySetGyroscopicMode(get_id(), mode); } }; class dJointGroupSimpleIDContainer { protected: dJointGroupID _id; dJointGroupSimpleIDContainer(): _id(0) {} ~dJointGroupSimpleIDContainer() { destroy(); } void destroy() { if (_id) { dJointGroupDestroy(_id); _id = 0; } } }; class dJointGroupDynamicIDContainer: public dJointGroupSimpleIDContainer { protected: virtual ~dJointGroupDynamicIDContainer() {} }; template class dJointGroupTemplate: public dJointGroupTemplateBase { // intentionally undefined, don't use these dJointGroupTemplate (const dJointGroupTemplate &); void operator= (const dJointGroupTemplate &); protected: dJointGroupID get_id() const { return dJointGroupTemplateBase::_id; } void set_id(dJointGroupID value) { dJointGroupTemplateBase::_id = value; } void destroy() { dJointGroupTemplateBase::destroy(); } public: dJointGroupTemplate () { set_id(dJointGroupCreate(0)); } void create () { destroy(); set_id(dJointGroupCreate(0)); } dJointGroupID id() const { return get_id(); } operator dJointGroupID() const { return get_id(); } void empty() { dJointGroupEmpty (get_id()); } void clear() { empty(); } }; class dJointSimpleIDContainer { protected: dJointID _id; dJointSimpleIDContainer(): _id(0) {} ~dJointSimpleIDContainer() { destroy(); } void destroy() { if (_id) { dJointDestroy (_id); _id = 0; } } }; class dJointDynamicIDContainer: public dJointSimpleIDContainer { protected: virtual ~dJointDynamicIDContainer() {} }; template class dJointTemplate: public dJointTemplateBase { private: // intentionally undefined, don't use these dJointTemplate (const dJointTemplate &) ; void operator= (const dJointTemplate &); protected: dJointID get_id() const { return dJointTemplateBase::_id; } void set_id(dJointID value) { dJointTemplateBase::_id = value; } void destroy() { dJointTemplateBase::destroy(); } protected: dJointTemplate() // don't let user construct pure dJointTemplate objects { } public: dJointID id() const { return get_id(); } operator dJointID() const { return get_id(); } int getNumBodies() const { return dJointGetNumBodies(get_id()); } void attach (dBodyID body1, dBodyID body2) { dJointAttach (get_id(), body1, body2); } void attach (dBodyTemplate& body1, dBodyTemplate& body2) { attach(body1.id(), body2.id()); } void enable() { dJointEnable (get_id()); } void disable() { dJointDisable (get_id()); } bool isEnabled() const { return dJointIsEnabled (get_id()) != 0; } void setData (void *data) { dJointSetData (get_id(), data); } void *getData() const { return dJointGetData (get_id()); } dJointType getType() const { return dJointGetType (get_id()); } dBodyID getBody (int index) const { return dJointGetBody (get_id(), index); } void setFeedback(dJointFeedback *fb) { dJointSetFeedback(get_id(), fb); } dJointFeedback *getFeedback() const { return dJointGetFeedback(get_id()); } // If not implemented it will do nothing as describe in the doc virtual void setParam (int, dReal) {}; virtual dReal getParam (int) const { return 0; } }; template class dBallJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dBallJointTemplate (const dBallJointTemplate &); void operator= (const dBallJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dBallJointTemplate() { } dBallJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateBall(world, group)); } dBallJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateBall(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateBall(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAnchor (dReal x, dReal y, dReal z) { dJointSetBallAnchor (get_id(), x, y, z); } void setAnchor (const dVector3 a) { setAnchor (a[0], a[1], a[2]); } void getAnchor (dVector3 result) const { dJointGetBallAnchor (get_id(), result); } void getAnchor2 (dVector3 result) const { dJointGetBallAnchor2 (get_id(), result); } virtual void setParam (int parameter, dReal value) { dJointSetBallParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetBallParam (get_id(), parameter); } // TODO: expose params through methods } ; template class dHingeJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dHingeJointTemplate (const dHingeJointTemplate &); void operator = (const dHingeJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dHingeJointTemplate() { } dHingeJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateHinge(world, group)); } dHingeJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateHinge(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateHinge (world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAnchor (dReal x, dReal y, dReal z) { dJointSetHingeAnchor (get_id(), x, y, z); } void setAnchor (const dVector3 a) { setAnchor (a[0], a[1], a[2]); } void getAnchor (dVector3 result) const { dJointGetHingeAnchor (get_id(), result); } void getAnchor2 (dVector3 result) const { dJointGetHingeAnchor2 (get_id(), result); } void setAxis (dReal x, dReal y, dReal z) { dJointSetHingeAxis (get_id(), x, y, z); } void setAxis (const dVector3 a) { setAxis(a[0], a[1], a[2]); } void getAxis (dVector3 result) const { dJointGetHingeAxis (get_id(), result); } dReal getAngle() const { return dJointGetHingeAngle (get_id()); } dReal getAngleRate() const { return dJointGetHingeAngleRate (get_id()); } virtual void setParam (int parameter, dReal value) { dJointSetHingeParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetHingeParam (get_id(), parameter); } // TODO: expose params through methods void addTorque (dReal torque) { dJointAddHingeTorque(get_id(), torque); } }; template class dSliderJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dSliderJointTemplate (const dSliderJointTemplate &); void operator = (const dSliderJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dSliderJointTemplate() { } dSliderJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateSlider(world, group)); } dSliderJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateSlider(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateSlider(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAxis (dReal x, dReal y, dReal z) { dJointSetSliderAxis (get_id(), x, y, z); } void setAxis (const dVector3 a) { setAxis (a[0], a[1], a[2]); } void getAxis (dVector3 result) const { dJointGetSliderAxis (get_id(), result); } dReal getPosition() const { return dJointGetSliderPosition (get_id()); } dReal getPositionRate() const { return dJointGetSliderPositionRate (get_id()); } virtual void setParam (int parameter, dReal value) { dJointSetSliderParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetSliderParam (get_id(), parameter); } // TODO: expose params through methods void addForce (dReal force) { dJointAddSliderForce(get_id(), force); } }; template class dUniversalJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dUniversalJointTemplate (const dUniversalJointTemplate &); void operator = (const dUniversalJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dUniversalJointTemplate() { } dUniversalJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateUniversal(world, group)); } dUniversalJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateUniversal(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateUniversal(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAnchor (dReal x, dReal y, dReal z) { dJointSetUniversalAnchor (get_id(), x, y, z); } void setAnchor (const dVector3 a) { setAnchor(a[0], a[1], a[2]); } void setAxis1 (dReal x, dReal y, dReal z) { dJointSetUniversalAxis1 (get_id(), x, y, z); } void setAxis1 (const dVector3 a) { setAxis1 (a[0], a[1], a[2]); } void setAxis2 (dReal x, dReal y, dReal z) { dJointSetUniversalAxis2 (get_id(), x, y, z); } void setAxis2 (const dVector3 a) { setAxis2 (a[0], a[1], a[2]); } void getAnchor (dVector3 result) const { dJointGetUniversalAnchor (get_id(), result); } void getAnchor2 (dVector3 result) const { dJointGetUniversalAnchor2 (get_id(), result); } void getAxis1 (dVector3 result) const { dJointGetUniversalAxis1 (get_id(), result); } void getAxis2 (dVector3 result) const { dJointGetUniversalAxis2 (get_id(), result); } virtual void setParam (int parameter, dReal value) { dJointSetUniversalParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetUniversalParam (get_id(), parameter); } // TODO: expose params through methods void getAngles(dReal *angle1, dReal *angle2) const { dJointGetUniversalAngles (get_id(), angle1, angle2); } dReal getAngle1() const { return dJointGetUniversalAngle1 (get_id()); } dReal getAngle1Rate() const { return dJointGetUniversalAngle1Rate (get_id()); } dReal getAngle2() const { return dJointGetUniversalAngle2 (get_id()); } dReal getAngle2Rate() const { return dJointGetUniversalAngle2Rate (get_id()); } void addTorques (dReal torque1, dReal torque2) { dJointAddUniversalTorques(get_id(), torque1, torque2); } }; template class dHinge2JointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dHinge2JointTemplate (const dHinge2JointTemplate &); void operator = (const dHinge2JointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dHinge2JointTemplate() { } dHinge2JointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateHinge2(world, group)); } dHinge2JointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateHinge2(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateHinge2(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAnchor (dReal x, dReal y, dReal z) { dJointSetHinge2Anchor (get_id(), x, y, z); } void setAnchor (const dVector3 a) { setAnchor(a[0], a[1], a[2]); } void setAxis1 (dReal x, dReal y, dReal z) { dJointSetHinge2Axis1 (get_id(), x, y, z); } void setAxis1 (const dVector3 a) { setAxis1 (a[0], a[1], a[2]); } void setAxis2 (dReal x, dReal y, dReal z) { dJointSetHinge2Axis2 (get_id(), x, y, z); } void setAxis2 (const dVector3 a) { setAxis2 (a[0], a[1], a[2]); } void getAnchor (dVector3 result) const { dJointGetHinge2Anchor (get_id(), result); } void getAnchor2 (dVector3 result) const { dJointGetHinge2Anchor2 (get_id(), result); } void getAxis1 (dVector3 result) const { dJointGetHinge2Axis1 (get_id(), result); } void getAxis2 (dVector3 result) const { dJointGetHinge2Axis2 (get_id(), result); } dReal getAngle1() const { return dJointGetHinge2Angle1 (get_id()); } dReal getAngle1Rate() const { return dJointGetHinge2Angle1Rate (get_id()); } dReal getAngle2Rate() const { return dJointGetHinge2Angle2Rate (get_id()); } virtual void setParam (int parameter, dReal value) { dJointSetHinge2Param (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetHinge2Param (get_id(), parameter); } // TODO: expose params through methods void addTorques(dReal torque1, dReal torque2) { dJointAddHinge2Torques(get_id(), torque1, torque2); } }; template class dPRJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dPRJointTemplate (const dPRJointTemplate &); void operator = (const dPRJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dPRJointTemplate() { } dPRJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreatePR(world, group)); } dPRJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreatePR(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreatePR(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAnchor (dReal x, dReal y, dReal z) { dJointSetPRAnchor (get_id(), x, y, z); } void setAnchor (const dVector3 a) { setAnchor (a[0], a[1], a[2]); } void setAxis1 (dReal x, dReal y, dReal z) { dJointSetPRAxis1 (get_id(), x, y, z); } void setAxis1 (const dVector3 a) { setAxis1(a[0], a[1], a[2]); } void setAxis2 (dReal x, dReal y, dReal z) { dJointSetPRAxis2 (get_id(), x, y, z); } void setAxis2 (const dVector3 a) { setAxis2(a[0], a[1], a[2]); } void getAnchor (dVector3 result) const { dJointGetPRAnchor (get_id(), result); } void getAxis1 (dVector3 result) const { dJointGetPRAxis1 (get_id(), result); } void getAxis2 (dVector3 result) const { dJointGetPRAxis2 (get_id(), result); } dReal getPosition() const { return dJointGetPRPosition (get_id()); } dReal getPositionRate() const { return dJointGetPRPositionRate (get_id()); } dReal getAngle() const { return dJointGetPRAngle (get_id()); } dReal getAngleRate() const { return dJointGetPRAngleRate (get_id()); } virtual void setParam (int parameter, dReal value) { dJointSetPRParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetPRParam (get_id(), parameter); } }; template class dPUJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dPUJointTemplate (const dPUJointTemplate &); void operator = (const dPUJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dPUJointTemplate() { } dPUJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreatePU(world, group)); } dPUJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreatePU(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreatePU(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAnchor (dReal x, dReal y, dReal z) { dJointSetPUAnchor (get_id(), x, y, z); } void setAnchor (const dVector3 a) { setAnchor (a[0], a[1], a[2]); } void setAxis1 (dReal x, dReal y, dReal z) { dJointSetPUAxis1 (get_id(), x, y, z); } void setAxis1 (const dVector3 a) { setAxis1(a[0], a[1], a[2]); } void setAxis2 (dReal x, dReal y, dReal z) { dJointSetPUAxis2 (get_id(), x, y, z); } void setAxis3 (dReal x, dReal y, dReal z) { dJointSetPUAxis3 (get_id(), x, y, z); } void setAxis3 (const dVector3 a) { setAxis3(a[0], a[1], a[2]); } void setAxisP (dReal x, dReal y, dReal z) { dJointSetPUAxis3 (get_id(), x, y, z); } void setAxisP (const dVector3 a) { setAxisP(a[0], a[1], a[2]); } virtual void getAnchor (dVector3 result) const { dJointGetPUAnchor (get_id(), result); } void getAxis1 (dVector3 result) const { dJointGetPUAxis1 (get_id(), result); } void getAxis2 (dVector3 result) const { dJointGetPUAxis2 (get_id(), result); } void getAxis3 (dVector3 result) const { dJointGetPUAxis3 (get_id(), result); } void getAxisP (dVector3 result) const { dJointGetPUAxis3 (get_id(), result); } dReal getAngle1() const { return dJointGetPUAngle1 (get_id()); } dReal getAngle1Rate() const { return dJointGetPUAngle1Rate (get_id()); } dReal getAngle2() const { return dJointGetPUAngle2 (get_id()); } dReal getAngle2Rate() const { return dJointGetPUAngle2Rate (get_id()); } dReal getPosition() const { return dJointGetPUPosition (get_id()); } dReal getPositionRate() const { return dJointGetPUPositionRate (get_id()); } virtual void setParam (int parameter, dReal value) { dJointSetPUParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetPUParam (get_id(), parameter); } // TODO: expose params through methods }; template class dPistonJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dPistonJointTemplate (const dPistonJointTemplate &); void operator = (const dPistonJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dPistonJointTemplate() { } dPistonJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreatePiston(world, group)); } dPistonJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreatePiston(world, group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreatePiston(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setAnchor (dReal x, dReal y, dReal z) { dJointSetPistonAnchor (get_id(), x, y, z); } void setAnchor (const dVector3 a) { setAnchor (a[0], a[1], a[2]); } void getAnchor (dVector3 result) const { dJointGetPistonAnchor (get_id(), result); } void getAnchor2 (dVector3 result) const { dJointGetPistonAnchor2 (get_id(), result); } void setAxis (dReal x, dReal y, dReal z) { dJointSetPistonAxis (get_id(), x, y, z); } void setAxis (const dVector3 a) { setAxis(a[0], a[1], a[2]); } void getAxis (dVector3 result) const { dJointGetPistonAxis (get_id(), result); } dReal getPosition() const { return dJointGetPistonPosition (get_id()); } dReal getPositionRate() const { return dJointGetPistonPositionRate (get_id()); } virtual void setParam (int parameter, dReal value) { dJointSetPistonParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetPistonParam (get_id(), parameter); } // TODO: expose params through methods void addForce (dReal force) { dJointAddPistonForce (get_id(), force); } }; template class dFixedJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dFixedJointTemplate (const dFixedJointTemplate &); void operator = (const dFixedJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dFixedJointTemplate() { } dFixedJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateFixed(world, group)); } dFixedJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateFixed(world, group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateFixed(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void set() { dJointSetFixed (get_id()); } virtual void setParam (int parameter, dReal value) { dJointSetFixedParam (get_id(), parameter, value); } virtual dReal getParam (int parameter) const { return dJointGetFixedParam (get_id(), parameter); } // TODO: expose params through methods }; template class dContactJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dContactJointTemplate (const dContactJointTemplate &); void operator = (const dContactJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dContactJointTemplate() { } dContactJointTemplate (dWorldID world, dJointGroupID group, dContact *contact) { set_id(dJointCreateContact(world, group, contact)); } dContactJointTemplate (dWorldTemplate& world, dJointGroupID group, dContact *contact) { set_id(dJointCreateContact(world.id(), group, contact)); } void create (dWorldID world, dJointGroupID group, dContact *contact) { destroy(); set_id(dJointCreateContact(world, group, contact)); } void create (dWorldTemplate& world, dJointGroupID group, dContact *contact) { create(world.id(), group, contact); } }; template class dNullJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dNullJointTemplate (const dNullJointTemplate &); void operator = (const dNullJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dNullJointTemplate() { } dNullJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateNull(world, group)); } dNullJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateNull (world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateNull(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } }; template class dAMotorJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dAMotorJointTemplate (const dAMotorJointTemplate &); void operator = (const dAMotorJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dAMotorJointTemplate() { } dAMotorJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateAMotor(world, group)); } dAMotorJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateAMotor(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateAMotor(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setMode (int mode) { dJointSetAMotorMode (get_id(), mode); } int getMode() const { return dJointGetAMotorMode (get_id()); } void setNumAxes (int num) { dJointSetAMotorNumAxes (get_id(), num); } int getNumAxes() const { return dJointGetAMotorNumAxes (get_id()); } void setAxis (int anum, int rel, dReal x, dReal y, dReal z) { dJointSetAMotorAxis (get_id(), anum, rel, x, y, z); } void setAxis (int anum, int rel, const dVector3 a) { setAxis(anum, rel, a[0], a[1], a[2]); } void getAxis (int anum, dVector3 result) const { dJointGetAMotorAxis (get_id(), anum, result); } int getAxisRel (int anum) const { return dJointGetAMotorAxisRel (get_id(), anum); } void setAngle (int anum, dReal angle) { dJointSetAMotorAngle (get_id(), anum, angle); } dReal getAngle (int anum) const { return dJointGetAMotorAngle (get_id(), anum); } dReal getAngleRate (int anum) { return dJointGetAMotorAngleRate (get_id(), anum); } void setParam (int parameter, dReal value) { dJointSetAMotorParam (get_id(), parameter, value); } dReal getParam (int parameter) const { return dJointGetAMotorParam (get_id(), parameter); } // TODO: expose params through methods void addTorques(dReal torque1, dReal torque2, dReal torque3) { dJointAddAMotorTorques(get_id(), torque1, torque2, torque3); } }; template class dLMotorJointTemplate : public dJointTemplate { private: // intentionally undefined, don't use these dLMotorJointTemplate (const dLMotorJointTemplate &); void operator = (const dLMotorJointTemplate &); protected: typedef dJointTemplate dBaseTemplate; dJointID get_id() const { return dBaseTemplate::get_id(); } void set_id(dJointID value) { dBaseTemplate::set_id(value); } void destroy() { dBaseTemplate::destroy(); } public: dLMotorJointTemplate() { } dLMotorJointTemplate (dWorldID world, dJointGroupID group=0) { set_id(dJointCreateLMotor(world, group)); } dLMotorJointTemplate (dWorldTemplate& world, dJointGroupID group=0) { set_id(dJointCreateLMotor(world.id(), group)); } void create (dWorldID world, dJointGroupID group=0) { destroy(); set_id(dJointCreateLMotor(world, group)); } void create (dWorldTemplate& world, dJointGroupID group=0) { create(world.id(), group); } void setNumAxes (int num) { dJointSetLMotorNumAxes (get_id(), num); } int getNumAxes() const { return dJointGetLMotorNumAxes (get_id()); } void setAxis (int anum, int rel, dReal x, dReal y, dReal z) { dJointSetLMotorAxis (get_id(), anum, rel, x, y, z); } void setAxis (int anum, int rel, const dVector3 a) { setAxis(anum, rel, a[0], a[1], a[2]); } void getAxis (int anum, dVector3 result) const { dJointGetLMotorAxis (get_id(), anum, result); } void setParam (int parameter, dReal value) { dJointSetLMotorParam (get_id(), parameter, value); } dReal getParam (int parameter) const { return dJointGetLMotorParam (get_id(), parameter); } // TODO: expose params through methods }; //} #if !defined(dODECPP_WORLD_TEMPLATE_BASE) #if defined(dODECPP_BODY_TEMPLATE_BASE) || defined(dODECPP_JOINTGROUP_TEMPLATE_BASE) || defined(dODECPP_JOINT_TEMPLATE_BASE) #error All the odecpp template bases must be defined or not defined together #endif #define dODECPP_WORLD_TEMPLATE_BASE dWorldDynamicIDContainer #define dODECPP_BODY_TEMPLATE_BASE dBodyDynamicIDContainer #define dODECPP_JOINTGROUP_TEMPLATE_BASE dJointGroupDynamicIDContainer #define dODECPP_JOINT_TEMPLATE_BASE dJointDynamicIDContainer #else // #if defined(dODECPP_WORLD_TEMPLATE_BASE) #if !defined(dODECPP_BODY_TEMPLATE_BASE) || !defined(dODECPP_JOINTGROUP_TEMPLATE_BASE) || !defined(dODECPP_JOINT_TEMPLATE_BASE) #error All the odecpp template bases must be defined or not defined together #endif #endif // #if defined(dODECPP_WORLD_TEMPLATE_BASE) typedef dWorldTemplate dWorld; typedef dBodyTemplate dBody; typedef dJointGroupTemplate dJointGroup; typedef dJointTemplate dJoint; typedef dBallJointTemplate dBallJoint; typedef dHingeJointTemplate dHingeJoint; typedef dSliderJointTemplate dSliderJoint; typedef dUniversalJointTemplate dUniversalJoint; typedef dHinge2JointTemplate dHinge2Joint; typedef dPRJointTemplate dPRJoint; typedef dPUJointTemplate dPUJoint; typedef dPistonJointTemplate dPistonJoint; typedef dFixedJointTemplate dFixedJoint; typedef dContactJointTemplate dContactJoint; typedef dNullJointTemplate dNullJoint; typedef dAMotorJointTemplate dAMotorJoint; typedef dLMotorJointTemplate dLMotorJoint; #endif #endif // Local variables: // mode:c++ // c-basic-offset:2 // End: ode-0.14/include/ode/odecpp_collision.h0000644000000000000000000003332512635011627016604 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* C++ interface for new collision API */ #ifndef _ODE_ODECPP_COLLISION_H_ #define _ODE_ODECPP_COLLISION_H_ #ifdef __cplusplus //#include //namespace ode { class dGeom { // intentionally undefined, don't use these dGeom (dGeom &); void operator= (dGeom &); protected: dGeomID _id; dGeom() { _id = 0; } public: ~dGeom() { if (_id) dGeomDestroy (_id); } dGeomID id() const { return _id; } operator dGeomID() const { return _id; } void destroy() { if (_id) dGeomDestroy (_id); _id = 0; } int getClass() const { return dGeomGetClass (_id); } dSpaceID getSpace() const { return dGeomGetSpace (_id); } void setData (void *data) { dGeomSetData (_id,data); } void *getData() const { return dGeomGetData (_id); } void setBody (dBodyID b) { dGeomSetBody (_id,b); } dBodyID getBody() const { return dGeomGetBody (_id); } void setPosition (dReal x, dReal y, dReal z) { dGeomSetPosition (_id,x,y,z); } const dReal * getPosition() const { return dGeomGetPosition (_id); } void setRotation (const dMatrix3 R) { dGeomSetRotation (_id,R); } const dReal * getRotation() const { return dGeomGetRotation (_id); } void setQuaternion (const dQuaternion quat) { dGeomSetQuaternion (_id,quat); } void getQuaternion (dQuaternion quat) const { dGeomGetQuaternion (_id,quat); } void getAABB (dReal aabb[6]) const { dGeomGetAABB (_id, aabb); } int isSpace() { return dGeomIsSpace (_id); } void setCategoryBits (unsigned long bits) { dGeomSetCategoryBits (_id, bits); } void setCollideBits (unsigned long bits) { dGeomSetCollideBits (_id, bits); } unsigned long getCategoryBits() { return dGeomGetCategoryBits (_id); } unsigned long getCollideBits() { return dGeomGetCollideBits (_id); } void enable() { dGeomEnable (_id); } void disable() { dGeomDisable (_id); } int isEnabled() { return dGeomIsEnabled (_id); } void getRelPointPos (dReal px, dReal py, dReal pz, dVector3 result) const { dGeomGetRelPointPos (_id, px, py, pz, result); } void getRelPointPos (const dVector3 p, dVector3 result) const { getRelPointPos (p[0], p[1], p[2], result); } void getPosRelPoint (dReal px, dReal py, dReal pz, dVector3 result) const { dGeomGetPosRelPoint (_id, px, py, pz, result); } void getPosRelPoint (const dVector3 p, dVector3 result) const { getPosRelPoint (p[0], p[1], p[2], result); } void vectorToWorld (dReal px, dReal py, dReal pz, dVector3 result) const { dGeomVectorToWorld (_id, px, py, pz, result); } void vectorToWorld (const dVector3 p, dVector3 result) const { vectorToWorld (p[0], p[1], p[2], result); } void vectorFromWorld (dReal px, dReal py, dReal pz, dVector3 result) const { dGeomVectorFromWorld (_id, px, py, pz, result); } void vectorFromWorld (const dVector3 p, dVector3 result) const { vectorFromWorld (p[0], p[1], p[2], result); } void collide2 (dGeomID g, void *data, dNearCallback *callback) { dSpaceCollide2 (_id,g,data,callback); } }; class dSpace : public dGeom { // intentionally undefined, don't use these dSpace (dSpace &); void operator= (dSpace &); protected: // the default constructor is protected so that you // can't instance this class. you must instance one // of its subclasses instead. dSpace () { _id = 0; } public: dSpaceID id() const { return (dSpaceID) _id; } operator dSpaceID() const { return (dSpaceID) _id; } void setCleanup (int mode) { dSpaceSetCleanup (id(), mode); } int getCleanup() { return dSpaceGetCleanup (id()); } void add (dGeomID x) { dSpaceAdd (id(), x); } void remove (dGeomID x) { dSpaceRemove (id(), x); } int query (dGeomID x) { return dSpaceQuery (id(),x); } int getNumGeoms() { return dSpaceGetNumGeoms (id()); } dGeomID getGeom (int i) { return dSpaceGetGeom (id(),i); } void collide (void *data, dNearCallback *callback) { dSpaceCollide (id(),data,callback); } }; class dSimpleSpace : public dSpace { // intentionally undefined, don't use these dSimpleSpace (dSimpleSpace &); void operator= (dSimpleSpace &); public: dSimpleSpace () { _id = (dGeomID) dSimpleSpaceCreate (0); } dSimpleSpace (dSpace &space) { _id = (dGeomID) dSimpleSpaceCreate (space.id()); } dSimpleSpace (dSpaceID space) { _id = (dGeomID) dSimpleSpaceCreate (space); } }; class dHashSpace : public dSpace { // intentionally undefined, don't use these dHashSpace (dHashSpace &); void operator= (dHashSpace &); public: dHashSpace () { _id = (dGeomID) dHashSpaceCreate (0); } dHashSpace (dSpace &space) { _id = (dGeomID) dHashSpaceCreate (space.id()); } dHashSpace (dSpaceID space) { _id = (dGeomID) dHashSpaceCreate (space); } void setLevels (int minlevel, int maxlevel) { dHashSpaceSetLevels (id(),minlevel,maxlevel); } }; class dQuadTreeSpace : public dSpace { // intentionally undefined, don't use these dQuadTreeSpace (dQuadTreeSpace &); void operator= (dQuadTreeSpace &); public: dQuadTreeSpace (const dVector3 center, const dVector3 extents, int depth) { _id = (dGeomID) dQuadTreeSpaceCreate (0,center,extents,depth); } dQuadTreeSpace (dSpace &space, const dVector3 center, const dVector3 extents, int depth) { _id = (dGeomID) dQuadTreeSpaceCreate (space.id(),center,extents,depth); } dQuadTreeSpace (dSpaceID space, const dVector3 center, const dVector3 extents, int depth) { _id = (dGeomID) dQuadTreeSpaceCreate (space,center,extents,depth); } }; class dSphere : public dGeom { // intentionally undefined, don't use these dSphere (dSphere &); void operator= (dSphere &); public: dSphere () { } dSphere (dReal radius) { _id = dCreateSphere (0, radius); } dSphere (dSpace &space, dReal radius) { _id = dCreateSphere (space.id(), radius); } dSphere (dSpaceID space, dReal radius) { _id = dCreateSphere (space, radius); } void create (dSpaceID space, dReal radius) { if (_id) dGeomDestroy (_id); _id = dCreateSphere (space, radius); } void setRadius (dReal radius) { dGeomSphereSetRadius (_id, radius); } dReal getRadius() const { return dGeomSphereGetRadius (_id); } }; class dBox : public dGeom { // intentionally undefined, don't use these dBox (dBox &); void operator= (dBox &); public: dBox () { } dBox (dReal lx, dReal ly, dReal lz) { _id = dCreateBox (0,lx,ly,lz); } dBox (dSpace &space, dReal lx, dReal ly, dReal lz) { _id = dCreateBox (space,lx,ly,lz); } dBox (dSpaceID space, dReal lx, dReal ly, dReal lz) { _id = dCreateBox (space,lx,ly,lz); } void create (dSpaceID space, dReal lx, dReal ly, dReal lz) { if (_id) dGeomDestroy (_id); _id = dCreateBox (space,lx,ly,lz); } void setLengths (dReal lx, dReal ly, dReal lz) { dGeomBoxSetLengths (_id, lx, ly, lz); } void getLengths (dVector3 result) const { dGeomBoxGetLengths (_id,result); } }; class dPlane : public dGeom { // intentionally undefined, don't use these dPlane (dPlane &); void operator= (dPlane &); public: dPlane() { } dPlane (dReal a, dReal b, dReal c, dReal d) { _id = dCreatePlane (0,a,b,c,d); } dPlane (dSpace &space, dReal a, dReal b, dReal c, dReal d) { _id = dCreatePlane (space.id(),a,b,c,d); } dPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) { _id = dCreatePlane (space,a,b,c,d); } void create (dSpaceID space, dReal a, dReal b, dReal c, dReal d) { if (_id) dGeomDestroy (_id); _id = dCreatePlane (space,a,b,c,d); } void setParams (dReal a, dReal b, dReal c, dReal d) { dGeomPlaneSetParams (_id, a, b, c, d); } void getParams (dVector4 result) const { dGeomPlaneGetParams (_id,result); } }; class dCapsule : public dGeom { // intentionally undefined, don't use these dCapsule (dCapsule &); void operator= (dCapsule &); public: dCapsule() { } dCapsule (dReal radius, dReal length) { _id = dCreateCapsule (0,radius,length); } dCapsule (dSpace &space, dReal radius, dReal length) { _id = dCreateCapsule (space.id(),radius,length); } dCapsule (dSpaceID space, dReal radius, dReal length) { _id = dCreateCapsule (space,radius,length); } void create (dSpaceID space, dReal radius, dReal length) { if (_id) dGeomDestroy (_id); _id = dCreateCapsule (space,radius,length); } void setParams (dReal radius, dReal length) { dGeomCapsuleSetParams (_id, radius, length); } void getParams (dReal *radius, dReal *length) const { dGeomCapsuleGetParams (_id,radius,length); } }; class dCylinder : public dGeom { // intentionally undefined, don't use these dCylinder (dCylinder &); void operator= (dCylinder &); public: dCylinder() { } dCylinder (dReal radius, dReal length) { _id = dCreateCylinder (0,radius,length); } dCylinder (dSpace &space, dReal radius, dReal length) { _id = dCreateCylinder (space.id(),radius,length); } dCylinder (dSpaceID space, dReal radius, dReal length) { _id = dCreateCylinder (space,radius,length); } void create (dSpaceID space, dReal radius, dReal length) { if (_id) dGeomDestroy (_id); _id = dCreateCylinder (space,radius,length); } void setParams (dReal radius, dReal length) { dGeomCylinderSetParams (_id, radius, length); } void getParams (dReal *radius, dReal *length) const { dGeomCylinderGetParams (_id,radius,length); } }; class dRay : public dGeom { // intentionally undefined, don't use these dRay (dRay &); void operator= (dRay &); public: dRay() { } dRay (dReal length) { _id = dCreateRay (0,length); } dRay (dSpace &space, dReal length) { _id = dCreateRay (space.id(),length); } dRay (dSpaceID space, dReal length) { _id = dCreateRay (space,length); } void create (dSpaceID space, dReal length) { if (_id) dGeomDestroy (_id); _id = dCreateRay (space,length); } void setLength (dReal length) { dGeomRaySetLength (_id, length); } dReal getLength() { return dGeomRayGetLength (_id); } void set (dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz) { dGeomRaySet (_id, px, py, pz, dx, dy, dz); } void get (dVector3 start, dVector3 dir) { dGeomRayGet (_id, start, dir); } #ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4996 ) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif ODE_API_DEPRECATED void setParams (int firstContact, int backfaceCull) { dGeomRaySetParams (_id, firstContact, backfaceCull); } ODE_API_DEPRECATED void getParams (int *firstContact, int *backfaceCull) { dGeomRayGetParams (_id, firstContact, backfaceCull); } #ifdef WIN32 #pragma warning( pop ) #else #pragma GCC diagnostic pop #endif void setBackfaceCull (int backfaceCull) { dGeomRaySetBackfaceCull (_id, backfaceCull); } int getBackfaceCull() { return dGeomRayGetBackfaceCull (_id); } void setFirstContact (int firstContact) { dGeomRaySetFirstContact (_id, firstContact); } int getFirstContact() { return dGeomRayGetFirstContact (_id); } void setClosestHit (int closestHit) { dGeomRaySetClosestHit (_id, closestHit); } int getClosestHit() { return dGeomRayGetClosestHit (_id); } }; #ifdef WIN32 #pragma warning( push ) #pragma warning( disable : 4996 ) #else #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif class ODE_API_DEPRECATED dGeomTransform : public dGeom { // intentionally undefined, don't use these dGeomTransform (dGeomTransform &); void operator= (dGeomTransform &); public: dGeomTransform() { } dGeomTransform (dSpace &space) { _id = dCreateGeomTransform (space.id()); } dGeomTransform (dSpaceID space) { _id = dCreateGeomTransform (space); } void create (dSpaceID space=0) { if (_id) dGeomDestroy (_id); _id = dCreateGeomTransform (space); } void setGeom (dGeomID geom) { dGeomTransformSetGeom (_id, geom); } dGeomID getGeom() const { return dGeomTransformGetGeom (_id); } void setCleanup (int mode) { dGeomTransformSetCleanup (_id,mode); } int getCleanup () { return dGeomTransformGetCleanup (_id); } void setInfo (int mode) { dGeomTransformSetInfo (_id,mode); } int getInfo() { return dGeomTransformGetInfo (_id); } }; #ifdef WIN32 #pragma warning( pop ) #else #pragma GCC diagnostic pop #endif //} #endif #endif ode-0.14/include/ode/odeinit.h0000644000000000000000000002273412635011627014714 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* Library initialization/finalization functions. */ #ifndef _ODE_ODEINIT_H_ #define _ODE_ODEINIT_H_ #include #ifdef __cplusplus extern "C" { #endif /* ************************************************************************ */ /* Library initialization */ /** * @defgroup init Library Initialization * * Library initialization functions prepare ODE internal data structures for use * and release allocated resources after ODE is not needed any more. */ /** * @brief Library initialization flags. * * These flags define ODE library initialization options. * * @c dInitFlagManualThreadCleanup indicates that resources allocated in TLS for threads * using ODE are to be cleared by library client with explicit call to @c dCleanupODEAllDataForThread. * If this flag is not specified the automatic resource tracking algorithm is used. * * With automatic resource tracking, On Windows, memory allocated for a thread may * remain not freed for some time after the thread exits. The resources may be * released when one of other threads calls @c dAllocateODEDataForThread. Ultimately, * the resources are released when library is closed with @c dCloseODE. On other * operating systems resources are always released by the thread itself on its exit * or on library closure with @c dCloseODE. * * With manual thread data cleanup mode every collision space object must be * explicitly switched to manual cleanup mode with @c dSpaceSetManualCleanup * after creation. See description of the function for more details. * * If @c dInitFlagManualThreadCleanup was not specified during initialization, * calls to @c dCleanupODEAllDataForThread are not allowed. * * @see dInitODE2 * @see dAllocateODEDataForThread * @see dSpaceSetManualCleanup * @see dCloseODE * @ingroup init */ enum dInitODEFlags { dInitFlagManualThreadCleanup = 0x00000001 /*@< Thread local data is to be cleared explicitly on @c dCleanupODEAllDataForThread function call*/ }; /** * @brief Initializes ODE library. * * @c dInitODE is obsolete. @c dInitODE2 is to be used for library initialization. * * A call to @c dInitODE is equal to the following initialization sequence * @code * dInitODE2(0); * dAllocateODEDataForThread(dAllocateMaskAll); * @endcode * * @see dInitODE2 * @see dAllocateODEDataForThread * @ingroup init */ ODE_API void dInitODE(void); /** * @brief Initializes ODE library. * @param uiInitFlags Initialization options bitmask * @return A nonzero if initialization succeeded and zero otherwise. * * This function must be called to initialize ODE library before first use. If * initialization succeeds the function may not be called again until library is * closed with a call to @c dCloseODE. * * The @a uiInitFlags parameter specifies initialization options to be used. These * can be combination of zero or more @c dInitODEFlags flags. * * @note * If @c dInitFlagManualThreadCleanup flag is used for initialization, * @c dSpaceSetManualCleanup must be called to set manual cleanup mode for every * space object right after creation. Failure to do so may lead to resource leaks. * * @see dInitODEFlags * @see dCloseODE * @see dSpaceSetManualCleanup * @ingroup init */ ODE_API int dInitODE2(unsigned int uiInitFlags/*=0*/); /** * @brief ODE data allocation flags. * * These flags are used to indicate which data is to be pre-allocated in call to * @c dAllocateODEDataForThread. * * @c dAllocateFlagBasicData tells to allocate the basic data set required for * normal library operation. This flag is equal to zero and is always implicitly * included. * * @c dAllocateFlagCollisionData tells that collision detection data is to be allocated. * Collision detection functions may not be called if the data has not be allocated * in advance. If collision detection is not going to be used, it is not necessary * to specify this flag. * * @c dAllocateMaskAll is a mask that can be used for for allocating all possible * data in cases when it is not known what exactly features of ODE will be used. * The mask may not be used in combination with other flags. It is guaranteed to * include all the current and future legal allocation flags. However, mature * applications should use explicit flags they need rather than allocating everything. * * @see dAllocateODEDataForThread * @ingroup init */ enum dAllocateODEDataFlags { dAllocateFlagBasicData = 0, /*@< Allocate basic data required for library to operate*/ dAllocateFlagCollisionData = 0x00000001, /*@< Allocate data for collision detection*/ dAllocateMaskAll = ~0 /*@< Allocate all the possible data that is currently defined or will be defined in the future.*/ }; /** * @brief Allocate thread local data to allow the thread calling ODE. * @param uiAllocateFlags Allocation options bitmask. * @return A nonzero if allocation succeeded and zero otherwise. * * The function is required to be called for every thread that is going to use * ODE. This function allocates the data that is required for accessing ODE from * current thread along with optional data required for particular ODE subsystems. * * @a uiAllocateFlags parameter can contain zero or more flags from @c dAllocateODEDataFlags * enumerated type. Multiple calls with different allocation flags are allowed. * The flags that are already allocated are ignored in subsequent calls. If zero * is passed as the parameter, it means to only allocate the set of most important * data the library can not operate without. * * If the function returns failure status it means that none of the requested * data has been allocated. The client may retry allocation attempt with the same * flags when more system resources are available. * * @see dAllocateODEDataFlags * @see dCleanupODEAllDataForThread * @ingroup init */ ODE_API int dAllocateODEDataForThread(unsigned int uiAllocateFlags); /** * @brief Free thread local data that was allocated for current thread. * * If library was initialized with @c dInitFlagManualThreadCleanup flag the function * is required to be called on exit of every thread that was calling @c dAllocateODEDataForThread. * Failure to call @c dCleanupODEAllDataForThread may result in some resources remaining * not freed until program exit. The function may also be called when ODE is still * being used to release resources allocated for all the current subsystems and * possibly proceed with data pre-allocation for other subsystems. * * The function can safely be called several times in a row. The function can be * called without prior invocation of @c dAllocateODEDataForThread. The function * may not be called before ODE is initialized with @c dInitODE2 or after library * has been closed with @c dCloseODE. A call to @c dCloseODE implicitly releases * all the thread local resources that might be allocated for all the threads that * were using ODE. * * If library was initialized without @c dInitFlagManualThreadCleanup flag * @c dCleanupODEAllDataForThread must not be called. * * @see dAllocateODEDataForThread * @see dInitODE2 * @see dCloseODE * @ingroup init */ ODE_API void dCleanupODEAllDataForThread(); /** * @brief Close ODE after it is not needed any more. * * The function is required to be called when program does not need ODE features any more. * The call to @c dCloseODE releases all the resources allocated for library * including all the thread local data that might be allocated for all the threads * that were using ODE. * * @c dCloseODE is a paired function for @c dInitODE2 and must only be called * after successful library initialization. * * @note Important! * Make sure that all the threads that were using ODE have already terminated * before calling @c dCloseODE. In particular it is not allowed to call * @c dCleanupODEAllDataForThread after @c dCloseODE. * * @see dInitODE2 * @see dCleanupODEAllDataForThread * @ingroup init */ ODE_API void dCloseODE(void); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* _ODE_ODEINIT_H_ */ ode-0.14/include/ode/odemath.h0000644000000000000000000004210512635011627014674 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_ODEMATH_H_ #define _ODE_ODEMATH_H_ #include /* * macro to access elements i,j in an NxM matrix A, independent of the * matrix storage convention. */ #define dACCESS33(A,i,j) ((A)[(i)*4+(j)]) /* * Macro to test for valid floating point values */ #define dVALIDVEC3(v) (!(dIsNan(v[0]) || dIsNan(v[1]) || dIsNan(v[2]))) #define dVALIDVEC4(v) (!(dIsNan(v[0]) || dIsNan(v[1]) || dIsNan(v[2]) || dIsNan(v[3]))) #define dVALIDMAT3(m) (!(dIsNan(m[0]) || dIsNan(m[1]) || dIsNan(m[2]) || dIsNan(m[3]) || dIsNan(m[4]) || dIsNan(m[5]) || dIsNan(m[6]) || dIsNan(m[7]) || dIsNan(m[8]) || dIsNan(m[9]) || dIsNan(m[10]) || dIsNan(m[11]))) #define dVALIDMAT4(m) (!(dIsNan(m[0]) || dIsNan(m[1]) || dIsNan(m[2]) || dIsNan(m[3]) || dIsNan(m[4]) || dIsNan(m[5]) || dIsNan(m[6]) || dIsNan(m[7]) || dIsNan(m[8]) || dIsNan(m[9]) || dIsNan(m[10]) || dIsNan(m[11]) || dIsNan(m[12]) || dIsNan(m[13]) || dIsNan(m[14]) || dIsNan(m[15]) )) /* Some vector math */ ODE_PURE_INLINE void dAddVectors3(dReal *res, const dReal *a, const dReal *b) { const dReal res_0 = a[0] + b[0]; const dReal res_1 = a[1] + b[1]; const dReal res_2 = a[2] + b[2]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dSubtractVectors3(dReal *res, const dReal *a, const dReal *b) { const dReal res_0 = a[0] - b[0]; const dReal res_1 = a[1] - b[1]; const dReal res_2 = a[2] - b[2]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dAddScaledVectors3(dReal *res, const dReal *a, const dReal *b, dReal a_scale, dReal b_scale) { const dReal res_0 = a_scale * a[0] + b_scale * b[0]; const dReal res_1 = a_scale * a[1] + b_scale * b[1]; const dReal res_2 = a_scale * a[2] + b_scale * b[2]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dScaleVector3(dReal *res, dReal nScale) { res[0] *= nScale ; res[1] *= nScale ; res[2] *= nScale ; } ODE_PURE_INLINE void dNegateVector3(dReal *res) { res[0] = -res[0]; res[1] = -res[1]; res[2] = -res[2]; } ODE_PURE_INLINE void dCopyVector3(dReal *res, const dReal *a) { const dReal res_0 = a[0]; const dReal res_1 = a[1]; const dReal res_2 = a[2]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dCopyScaledVector3(dReal *res, const dReal *a, dReal nScale) { const dReal res_0 = a[0] * nScale; const dReal res_1 = a[1] * nScale; const dReal res_2 = a[2] * nScale; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dCopyNegatedVector3(dReal *res, const dReal *a) { const dReal res_0 = -a[0]; const dReal res_1 = -a[1]; const dReal res_2 = -a[2]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dCopyVector4(dReal *res, const dReal *a) { const dReal res_0 = a[0]; const dReal res_1 = a[1]; const dReal res_2 = a[2]; const dReal res_3 = a[3]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; res[3] = res_3; } ODE_PURE_INLINE void dCopyMatrix4x4(dReal *res, const dReal *a) { dCopyVector4(res + 0, a + 0); dCopyVector4(res + 4, a + 4); dCopyVector4(res + 8, a + 8); } ODE_PURE_INLINE void dCopyMatrix4x3(dReal *res, const dReal *a) { dCopyVector3(res + 0, a + 0); dCopyVector3(res + 4, a + 4); dCopyVector3(res + 8, a + 8); } ODE_PURE_INLINE void dGetMatrixColumn3(dReal *res, const dReal *a, unsigned n) { const dReal res_0 = a[n + 0]; const dReal res_1 = a[n + 4]; const dReal res_2 = a[n + 8]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE dReal dCalcVectorLength3(const dReal *a) { return dSqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); } ODE_PURE_INLINE dReal dCalcVectorLengthSquare3(const dReal *a) { return (a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); } ODE_PURE_INLINE dReal dCalcPointDepth3(const dReal *test_p, const dReal *plane_p, const dReal *plane_n) { return (plane_p[0] - test_p[0]) * plane_n[0] + (plane_p[1] - test_p[1]) * plane_n[1] + (plane_p[2] - test_p[2]) * plane_n[2]; } /* * 3-way dot product. _dCalcVectorDot3 means that elements of `a' and `b' are spaced * step_a and step_b indexes apart respectively. dCalcVectorDot3() means dDot311. */ ODE_PURE_INLINE dReal _dCalcVectorDot3(const dReal *a, const dReal *b, unsigned step_a, unsigned step_b) { return a[0] * b[0] + a[step_a] * b[step_b] + a[2 * step_a] * b[2 * step_b]; } ODE_PURE_INLINE dReal dCalcVectorDot3 (const dReal *a, const dReal *b) { return _dCalcVectorDot3(a,b,1,1); } ODE_PURE_INLINE dReal dCalcVectorDot3_13 (const dReal *a, const dReal *b) { return _dCalcVectorDot3(a,b,1,3); } ODE_PURE_INLINE dReal dCalcVectorDot3_31 (const dReal *a, const dReal *b) { return _dCalcVectorDot3(a,b,3,1); } ODE_PURE_INLINE dReal dCalcVectorDot3_33 (const dReal *a, const dReal *b) { return _dCalcVectorDot3(a,b,3,3); } ODE_PURE_INLINE dReal dCalcVectorDot3_14 (const dReal *a, const dReal *b) { return _dCalcVectorDot3(a,b,1,4); } ODE_PURE_INLINE dReal dCalcVectorDot3_41 (const dReal *a, const dReal *b) { return _dCalcVectorDot3(a,b,4,1); } ODE_PURE_INLINE dReal dCalcVectorDot3_44 (const dReal *a, const dReal *b) { return _dCalcVectorDot3(a,b,4,4); } /* * cross product, set res = a x b. _dCalcVectorCross3 means that elements of `res', `a' * and `b' are spaced step_res, step_a and step_b indexes apart respectively. * dCalcVectorCross3() means dCross3111. */ ODE_PURE_INLINE void _dCalcVectorCross3(dReal *res, const dReal *a, const dReal *b, unsigned step_res, unsigned step_a, unsigned step_b) { const dReal res_0 = a[ step_a]*b[2*step_b] - a[2*step_a]*b[ step_b]; const dReal res_1 = a[2*step_a]*b[ 0] - a[ 0]*b[2*step_b]; const dReal res_2 = a[ 0]*b[ step_b] - a[ step_a]*b[ 0]; /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[ 0] = res_0; res[ step_res] = res_1; res[2*step_res] = res_2; } ODE_PURE_INLINE void dCalcVectorCross3 (dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 1, 1, 1); } ODE_PURE_INLINE void dCalcVectorCross3_114(dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 1, 1, 4); } ODE_PURE_INLINE void dCalcVectorCross3_141(dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 1, 4, 1); } ODE_PURE_INLINE void dCalcVectorCross3_144(dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 1, 4, 4); } ODE_PURE_INLINE void dCalcVectorCross3_411(dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 4, 1, 1); } ODE_PURE_INLINE void dCalcVectorCross3_414(dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 4, 1, 4); } ODE_PURE_INLINE void dCalcVectorCross3_441(dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 4, 4, 1); } ODE_PURE_INLINE void dCalcVectorCross3_444(dReal *res, const dReal *a, const dReal *b) { _dCalcVectorCross3(res, a, b, 4, 4, 4); } ODE_PURE_INLINE void dAddVectorCross3(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dCalcVectorCross3(tmp, a, b); dAddVectors3(res, res, tmp); } ODE_PURE_INLINE void dSubtractVectorCross3(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dCalcVectorCross3(tmp, a, b); dSubtractVectors3(res, res, tmp); } /* * set a 3x3 submatrix of A to a matrix such that submatrix(A)*b = a x b. * A is stored by rows, and has `skip' elements per row. the matrix is * assumed to be already zero, so this does not write zero elements! * if (plus,minus) is (+,-) then a positive version will be written. * if (plus,minus) is (-,+) then a negative version will be written. */ ODE_PURE_INLINE void dSetCrossMatrixPlus(dReal *res, const dReal *a, unsigned skip) { const dReal a_0 = a[0], a_1 = a[1], a_2 = a[2]; res[1] = -a_2; res[2] = +a_1; res[skip+0] = +a_2; res[skip+2] = -a_0; res[2*skip+0] = -a_1; res[2*skip+1] = +a_0; } ODE_PURE_INLINE void dSetCrossMatrixMinus(dReal *res, const dReal *a, unsigned skip) { const dReal a_0 = a[0], a_1 = a[1], a_2 = a[2]; res[1] = +a_2; res[2] = -a_1; res[skip+0] = -a_2; res[skip+2] = +a_0; res[2*skip+0] = +a_1; res[2*skip+1] = -a_0; } /* * compute the distance between two 3D-vectors */ ODE_PURE_INLINE dReal dCalcPointsDistance3(const dReal *a, const dReal *b) { dReal res; dReal tmp[3]; dSubtractVectors3(tmp, a, b); res = dCalcVectorLength3(tmp); return res; } /* * special case matrix multiplication, with operator selection */ ODE_PURE_INLINE void dMultiplyHelper0_331(dReal *res, const dReal *a, const dReal *b) { const dReal res_0 = dCalcVectorDot3(a, b); const dReal res_1 = dCalcVectorDot3(a + 4, b); const dReal res_2 = dCalcVectorDot3(a + 8, b); /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dMultiplyHelper1_331(dReal *res, const dReal *a, const dReal *b) { const dReal res_0 = dCalcVectorDot3_41(a, b); const dReal res_1 = dCalcVectorDot3_41(a + 1, b); const dReal res_2 = dCalcVectorDot3_41(a + 2, b); /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } ODE_PURE_INLINE void dMultiplyHelper0_133(dReal *res, const dReal *a, const dReal *b) { dMultiplyHelper1_331(res, b, a); } ODE_PURE_INLINE void dMultiplyHelper1_133(dReal *res, const dReal *a, const dReal *b) { const dReal res_0 = dCalcVectorDot3_44(a, b); const dReal res_1 = dCalcVectorDot3_44(a + 1, b); const dReal res_2 = dCalcVectorDot3_44(a + 2, b); /* Only assign after all the calculations are over to avoid incurring memory aliasing*/ res[0] = res_0; res[1] = res_1; res[2] = res_2; } /* Note: NEVER call any of these functions/macros with the same variable for A and C, it is not equivalent to A*=B. */ ODE_PURE_INLINE void dMultiply0_331(dReal *res, const dReal *a, const dReal *b) { dMultiplyHelper0_331(res, a, b); } ODE_PURE_INLINE void dMultiply1_331(dReal *res, const dReal *a, const dReal *b) { dMultiplyHelper1_331(res, a, b); } ODE_PURE_INLINE void dMultiply0_133(dReal *res, const dReal *a, const dReal *b) { dMultiplyHelper0_133(res, a, b); } ODE_PURE_INLINE void dMultiply0_333(dReal *res, const dReal *a, const dReal *b) { dMultiplyHelper0_133(res + 0, a + 0, b); dMultiplyHelper0_133(res + 4, a + 4, b); dMultiplyHelper0_133(res + 8, a + 8, b); } ODE_PURE_INLINE void dMultiply1_333(dReal *res, const dReal *a, const dReal *b) { dMultiplyHelper1_133(res + 0, b, a + 0); dMultiplyHelper1_133(res + 4, b, a + 1); dMultiplyHelper1_133(res + 8, b, a + 2); } ODE_PURE_INLINE void dMultiply2_333(dReal *res, const dReal *a, const dReal *b) { dMultiplyHelper0_331(res + 0, b, a + 0); dMultiplyHelper0_331(res + 4, b, a + 4); dMultiplyHelper0_331(res + 8, b, a + 8); } ODE_PURE_INLINE void dMultiplyAdd0_331(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dMultiplyHelper0_331(tmp, a, b); dAddVectors3(res, res, tmp); } ODE_PURE_INLINE void dMultiplyAdd1_331(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dMultiplyHelper1_331(tmp, a, b); dAddVectors3(res, res, tmp); } ODE_PURE_INLINE void dMultiplyAdd0_133(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dMultiplyHelper0_133(tmp, a, b); dAddVectors3(res, res, tmp); } ODE_PURE_INLINE void dMultiplyAdd0_333(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dMultiplyHelper0_133(tmp, a + 0, b); dAddVectors3(res+ 0, res + 0, tmp); dMultiplyHelper0_133(tmp, a + 4, b); dAddVectors3(res + 4, res + 4, tmp); dMultiplyHelper0_133(tmp, a + 8, b); dAddVectors3(res + 8, res + 8, tmp); } ODE_PURE_INLINE void dMultiplyAdd1_333(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dMultiplyHelper1_133(tmp, b, a + 0); dAddVectors3(res + 0, res + 0, tmp); dMultiplyHelper1_133(tmp, b, a + 1); dAddVectors3(res + 4, res + 4, tmp); dMultiplyHelper1_133(tmp, b, a + 2); dAddVectors3(res + 8, res + 8, tmp); } ODE_PURE_INLINE void dMultiplyAdd2_333(dReal *res, const dReal *a, const dReal *b) { dReal tmp[3]; dMultiplyHelper0_331(tmp, b, a + 0); dAddVectors3(res + 0, res + 0, tmp); dMultiplyHelper0_331(tmp, b, a + 4); dAddVectors3(res + 4, res + 4, tmp); dMultiplyHelper0_331(tmp, b, a + 8); dAddVectors3(res + 8, res + 8, tmp); } ODE_PURE_INLINE dReal dCalcMatrix3Det( const dReal* mat ) { dReal det; det = mat[0] * ( mat[5]*mat[10] - mat[9]*mat[6] ) - mat[1] * ( mat[4]*mat[10] - mat[8]*mat[6] ) + mat[2] * ( mat[4]*mat[9] - mat[8]*mat[5] ); return( det ); } /** Closed form matrix inversion, copied from collision_util.h for use in the stepper. Returns the determinant. returns 0 and does nothing if the matrix is singular. */ ODE_PURE_INLINE dReal dInvertMatrix3(dReal *dst, const dReal *ma) { dReal det; dReal detRecip; det = dCalcMatrix3Det( ma ); /* Setting an arbitrary non-zero threshold for the determinant doesn't do anyone any favors. The condition number is the important thing. If all the eigen-values of the matrix are small, so is the determinant, but it can still be well conditioned. A single extremely large eigen-value could push the determinant over threshold, but produce a very unstable result if the other eigen-values are small. So we just say that the determinant must be non-zero and trust the caller to provide well-conditioned matrices. */ if ( det == 0 ) { return 0; } detRecip = dRecip(det); dst[0] = ( ma[5]*ma[10] - ma[6]*ma[9] ) * detRecip; dst[1] = ( ma[9]*ma[2] - ma[1]*ma[10] ) * detRecip; dst[2] = ( ma[1]*ma[6] - ma[5]*ma[2] ) * detRecip; dst[4] = ( ma[6]*ma[8] - ma[4]*ma[10] ) * detRecip; dst[5] = ( ma[0]*ma[10] - ma[8]*ma[2] ) * detRecip; dst[6] = ( ma[4]*ma[2] - ma[0]*ma[6] ) * detRecip; dst[8] = ( ma[4]*ma[9] - ma[8]*ma[5] ) * detRecip; dst[9] = ( ma[8]*ma[1] - ma[0]*ma[9] ) * detRecip; dst[10] = ( ma[0]*ma[5] - ma[1]*ma[4] ) * detRecip; return det; } /* Include legacy macros here */ #include #ifdef __cplusplus extern "C" { #endif /* * normalize 3x1 and 4x1 vectors (i.e. scale them to unit length) */ /* For DLL export*/ ODE_API int dSafeNormalize3 (dVector3 a); ODE_API int dSafeNormalize4 (dVector4 a); ODE_API void dNormalize3 (dVector3 a); /* Potentially asserts on zero vec*/ ODE_API void dNormalize4 (dVector4 a); /* Potentially asserts on zero vec*/ /* * given a unit length "normal" vector n, generate vectors p and q vectors * that are an orthonormal basis for the plane space perpendicular to n. * i.e. this makes p,q such that n,p,q are all perpendicular to each other. * q will equal n x p. if n is not unit length then p will be unit length but * q wont be. */ ODE_API void dPlaneSpace (const dVector3 n, dVector3 p, dVector3 q); /* Makes sure the matrix is a proper rotation */ ODE_API void dOrthogonalizeR(dMatrix3 m); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/odemath_legacy.h0000644000000000000000000001335112635011627016221 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_ODEMATH_LEGACY_H_ #define _ODE_ODEMATH_LEGACY_H_ /* * These macros are not used any more inside of ODE * They are kept for backward compatibility with external code that * might still be using them. */ /* * General purpose vector operations with other vectors or constants. */ #define dOP(a,op,b,c) do { \ (a)[0] = ((b)[0]) op ((c)[0]); \ (a)[1] = ((b)[1]) op ((c)[1]); \ (a)[2] = ((b)[2]) op ((c)[2]); \ } while (0) #define dOPC(a,op,b,c) do { \ (a)[0] = ((b)[0]) op (c); \ (a)[1] = ((b)[1]) op (c); \ (a)[2] = ((b)[2]) op (c); \ } while (0) #define dOPE(a,op,b) do {\ (a)[0] op ((b)[0]); \ (a)[1] op ((b)[1]); \ (a)[2] op ((b)[2]); \ } while (0) #define dOPEC(a,op,c) do { \ (a)[0] op (c); \ (a)[1] op (c); \ (a)[2] op (c); \ } while (0) /* Define an equation with operators * For example this function can be used to replace *
     * for (int i=0; i<3; ++i)
     *   a[i] += b[i] + c[i];
     * 
    */ #define dOPE2(a,op1,b,op2,c) do { \ (a)[0] op1 ((b)[0]) op2 ((c)[0]); \ (a)[1] op1 ((b)[1]) op2 ((c)[1]); \ (a)[2] op1 ((b)[2]) op2 ((c)[2]); \ } while (0) #define dLENGTHSQUARED(a) dCalcVectorLengthSquare3(a) #define dLENGTH(a) dCalcVectorLength3(a) #define dDISTANCE(a, b) dCalcPointsDistance3(a, b) #define dDOT(a, b) dCalcVectorDot3(a, b) #define dDOT13(a, b) dCalcVectorDot3_13(a, b) #define dDOT31(a, b) dCalcVectorDot3_31(a, b) #define dDOT33(a, b) dCalcVectorDot3_33(a, b) #define dDOT14(a, b) dCalcVectorDot3_14(a, b) #define dDOT41(a, b) dCalcVectorDot3_41(a, b) #define dDOT44(a, b) dCalcVectorDot3_44(a, b) /* * cross product, set a = b x c. dCROSSpqr means that elements of `a', `b' * and `c' are spaced p, q and r indexes apart respectively. * dCROSS() means dCROSS111. `op' is normally `=', but you can set it to * +=, -= etc to get other effects. */ #define dCROSS(a,op,b,c) \ do { \ (a)[0] op ((b)[1]*(c)[2] - (b)[2]*(c)[1]); \ (a)[1] op ((b)[2]*(c)[0] - (b)[0]*(c)[2]); \ (a)[2] op ((b)[0]*(c)[1] - (b)[1]*(c)[0]); \ } while(0) #define dCROSSpqr(a,op,b,c,p,q,r) \ do { \ (a)[ 0] op ((b)[ q]*(c)[2*r] - (b)[2*q]*(c)[ r]); \ (a)[ p] op ((b)[2*q]*(c)[ 0] - (b)[ 0]*(c)[2*r]); \ (a)[2*p] op ((b)[ 0]*(c)[ r] - (b)[ q]*(c)[ 0]); \ } while(0) #define dCROSS114(a,op,b,c) dCROSSpqr(a,op,b,c,1,1,4) #define dCROSS141(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,1) #define dCROSS144(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,4) #define dCROSS411(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,1) #define dCROSS414(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,4) #define dCROSS441(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,1) #define dCROSS444(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,4) /* * set a 3x3 submatrix of A to a matrix such that submatrix(A)*b = a x b. * A is stored by rows, and has `skip' elements per row. the matrix is * assumed to be already zero, so this does not write zero elements! * if (plus,minus) is (+,-) then a positive version will be written. * if (plus,minus) is (-,+) then a negative version will be written. */ #define dCROSSMAT(A,a,skip,plus,minus) \ do { \ (A)[1] = minus (a)[2]; \ (A)[2] = plus (a)[1]; \ (A)[(skip)+0] = plus (a)[2]; \ (A)[(skip)+2] = minus (a)[0]; \ (A)[2*(skip)+0] = minus (a)[1]; \ (A)[2*(skip)+1] = plus (a)[0]; \ } while(0) /* Note: NEVER call any of these functions/macros with the same variable for A and C, it is not equivalent to A*=B. */ #define dMULTIPLY0_331(A, B, C) dMultiply0_331(A, B, C) #define dMULTIPLY1_331(A, B, C) dMultiply1_331(A, B, C) #define dMULTIPLY0_133(A, B, C) dMultiply0_133(A, B, C) #define dMULTIPLY0_333(A, B, C) dMultiply0_333(A, B, C) #define dMULTIPLY1_333(A, B, C) dMultiply1_333(A, B, C) #define dMULTIPLY2_333(A, B, C) dMultiply2_333(A, B, C) #define dMULTIPLYADD0_331(A, B, C) dMultiplyAdd0_331(A, B, C) #define dMULTIPLYADD1_331(A, B, C) dMultiplyAdd1_331(A, B, C) #define dMULTIPLYADD0_133(A, B, C) dMultiplyAdd0_133(A, B, C) #define dMULTIPLYADD0_333(A, B, C) dMultiplyAdd0_333(A, B, C) #define dMULTIPLYADD1_333(A, B, C) dMultiplyAdd1_333(A, B, C) #define dMULTIPLYADD2_333(A, B, C) dMultiplyAdd2_333(A, B, C) /* * These macros are not used any more inside of ODE * They are kept for backward compatibility with external code that * might still be using them. */ #endif /* #ifndef _ODE_ODEMATH_LEGACY_H_ */ ode-0.14/include/ode/precision.h.in0000644000000000000000000000042212635011627015647 0ustar rootroot#ifndef _ODE_PRECISION_H_ #define _ODE_PRECISION_H_ /* Define dSINGLE for single precision, dDOUBLE for double precision, * but never both! */ #if defined(dIDESINGLE) #define dSINGLE #elif defined(dIDEDOUBLE) #define dDOUBLE #else #define @ODE_PRECISION@ #endif #endif ode-0.14/include/ode/rotation.h0000644000000000000000000000603412635011627015113 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_ROTATION_H_ #define _ODE_ROTATION_H_ #include #include #ifdef __cplusplus extern "C" { #endif ODE_API void dRSetIdentity (dMatrix3 R); ODE_API void dRFromAxisAndAngle (dMatrix3 R, dReal ax, dReal ay, dReal az, dReal angle); ODE_API void dRFromEulerAngles (dMatrix3 R, dReal phi, dReal theta, dReal psi); ODE_API void dRFrom2Axes (dMatrix3 R, dReal ax, dReal ay, dReal az, dReal bx, dReal by, dReal bz); ODE_API void dRFromZAxis (dMatrix3 R, dReal ax, dReal ay, dReal az); ODE_API void dQSetIdentity (dQuaternion q); ODE_API void dQFromAxisAndAngle (dQuaternion q, dReal ax, dReal ay, dReal az, dReal angle); /* Quaternion multiplication, analogous to the matrix multiplication routines. */ /* qa = rotate by qc, then qb */ ODE_API void dQMultiply0 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); /* qa = rotate by qc, then by inverse of qb */ ODE_API void dQMultiply1 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); /* qa = rotate by inverse of qc, then by qb */ ODE_API void dQMultiply2 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); /* qa = rotate by inverse of qc, then by inverse of qb */ ODE_API void dQMultiply3 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); ODE_API void dRfromQ (dMatrix3 R, const dQuaternion q); ODE_API void dQfromR (dQuaternion q, const dMatrix3 R); ODE_API void dDQfromW (dReal dq[4], const dVector3 w, const dQuaternion q); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/threading.h0000644000000000000000000004157612635011627015233 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * Threading support header file. * * Copyright (C) 2011-2012 Oleh Derevenko. All rights reserved. * * e-mail: odar@eleks.com (change all "a" to "e") * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* * ODE threading support interfaces */ #ifndef _ODE_THREADING_H_ #define _ODE_THREADING_H_ #include // Include since time_t is used and it is not available by default in some OSes #include #ifdef __cplusplus extern "C" { #endif struct dxThreadingImplementation; typedef struct dxThreadingImplementation *dThreadingImplementationID; typedef unsigned dmutexindex_t; struct dxMutexGroup; typedef struct dxMutexGroup *dMutexGroupID; /** * @brief Allocates a group of muteces. * * The Mutex allocated do not need to support recursive locking. * * The Mutex names are provided to aid in debugging and thread state tracking. * * @param impl Threading implementation ID * @param Mutex_count Number of Mutex to create * @Mutex_names_ptr Pointer to optional Mutex names array to be associated with individual Mutex * @returns MutexGroup ID or NULL if error occurred. * * @ingroup threading * @see dMutexGroupFreeFunction * @see dMutexGroupMutexLockFunction * @see dMutexGroupMutexUnlockFunction */ typedef dMutexGroupID dMutexGroupAllocFunction (dThreadingImplementationID impl, dmutexindex_t Mutex_count, const char *const *Mutex_names_ptr/*=NULL*/); /** * @brief Deletes a group of muteces. * * @param impl Threading implementation ID * @param mutex_group Mutex group to deallocate * * @ingroup threading * @see dMutexGroupAllocFunction * @see dMutexGroupMutexLockFunction * @see dMutexGroupMutexUnlockFunction */ typedef void dMutexGroupFreeFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group); /** * @brief Locks a mutex in a group of muteces. * * The function is to block execution until requested mutex can be locked. * * Note: Mutex provided may not support recursive locking. Calling this function * while mutex is already locked by current thread will result in unpredictable behavior. * * @param impl Threading implementation ID * @param mutex_group Mutex group to use for locking * @param mutex_index The index of mutex to be locked (0..Mutex_count - 1) * * @ingroup threading * @see dMutexGroupAllocFunction * @see dMutexGroupFreeFunction * @see dMutexGroupMutexUnlockFunction */ typedef void dMutexGroupMutexLockFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index); /** * @brief Attempts to lock a mutex in a group of muteces. * * The function is to lock the requested mutex if it is unoccupied or * immediately return failure if mutex is already locked by other thread. * * Note: Mutex provided may not support recursive locking. Calling this function * while mutex is already locked by current thread will result in unpredictable behavior. * * @param impl Threading implementation ID * @param mutex_group Mutex group to use for locking * @param mutex_index The index of mutex to be locked (0..Mutex_count - 1) * @returns 1 for success (mutex is locked) and 0 for failure (mutex is not locked) * * @ingroup threading * @see dMutexGroupAllocFunction * @see dMutexGroupFreeFunction * @see dMutexGroupMutexLockFunction * @see dMutexGroupMutexUnlockFunction */ /* typedef int dMutexGroupMutexTryLockFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index);*/ /** * @brief Unlocks a mutex in a group of muteces. * * The function is to unlock the given mutex provided it had been locked before. * * @param impl Threading implementation ID * @param mutex_group Mutex group to use for unlocking * @param mutex_index The index of mutex to be unlocked (0..Mutex_count - 1) * * @ingroup threading * @see dMutexGroupAllocFunction * @see dMutexGroupFreeFunction * @see dMutexGroupMutexLockFunction */ typedef void dMutexGroupMutexUnlockFunction (dThreadingImplementationID impl, dMutexGroupID mutex_group, dmutexindex_t mutex_index); struct dxCallReleasee; typedef struct dxCallReleasee *dCallReleaseeID; struct dxCallWait; typedef struct dxCallWait *dCallWaitID; typedef size_t ddependencycount_t; typedef ptrdiff_t ddependencychange_t; typedef size_t dcallindex_t; typedef int dThreadedCallFunction(void *call_context, dcallindex_t instance_index, dCallReleaseeID this_releasee); typedef struct dxThreadedWaitTime { time_t wait_sec; unsigned long wait_nsec; } dThreadedWaitTime; /** * @brief Allocates a Wait ID that can be used to wait for a call. * * @param impl Threading implementation ID * @returns Wait ID or NULL if error occurred * * @ingroup threading * @see dThreadedCallWaitResetFunction * @see dThreadedCallWaitFreeFunction * @see dThreadedCallPostFunction * @see dThreadedCallWaitFunction */ typedef dCallWaitID dThreadedCallWaitAllocFunction(dThreadingImplementationID impl); /** * @brief Resets a Wait ID so that it could be used to wait for another call. * * @param impl Threading implementation ID * @param call_wait Wait ID to reset * * @ingroup threading * @see dThreadedCallWaitAllocFunction * @see dThreadedCallWaitFreeFunction * @see dThreadedCallPostFunction * @see dThreadedCallWaitFunction */ typedef void dThreadedCallWaitResetFunction(dThreadingImplementationID impl, dCallWaitID call_wait); /** * @brief Frees a Wait ID. * * @param impl Threading implementation ID * @param call_wait Wait ID to delete * * @ingroup threading * @see dThreadedCallWaitAllocFunction * @see dThreadedCallPostFunction * @see dThreadedCallWaitFunction */ typedef void dThreadedCallWaitFreeFunction(dThreadingImplementationID impl, dCallWaitID call_wait); /** * @brief Post a function to be called in another thread. * * A call is scheduled to be executed asynchronously. * * A @a out_summary_fault variable can be provided for call to accumulate any * possible faults from its execution and execution of any possible sub-calls. * This variable gets result that @a call_func returns. Also, if dependent calls * are executed after the call already exits, the variable is also going to be * updated with results of all those calls before control is released to master. * * @a out_post_releasee parameter receives a value of @c dCallReleaseeID that can * later be used for @a dependent_releasee while scheduling sub-calls to make * current call depend on them. The value is only returned if @a dependencies_count * is not zero (i.e. if any dependencies are expected at all). The call is not going * to start until all its dependencies complete. * * In case if number of dependencies is unknown in advance 1 can be passed on call * scheduling. Then @c dThreadedCallDependenciesCountAlterFunction can be used to * add one more extra dependencies before scheduling each subcall. And then, after * all sub-calls had been scheduled, @c dThreadedCallDependenciesCountAlterFunction * can be used again to subtract initial extra dependency from total number. * Adding one dependency in advance is necessary to obtain releasee ID and to make * sure the call will not start and will not terminate before all sub-calls are scheduled. * * Extra dependencies can also be added from the call itself after it has already * been started (with parameter received in @c dThreadedCallFunction). * In that case those dependencies will start immediately or after call returns * but the call's master will not be released/notified until all additional * dependencies complete. This can be used to schedule sub-calls from a call and * then pass own job to another sub-call dependent on those initial sub-calls. * * By using @ call_wait it is possible to assign a Wait ID that can later * be passed into @c dThreadedCallWaitFunction to wait for call completion. * * If @a call_name is available (and it should!) the string must remain valid until * after call completion. In most cases this should be a static string literal. * * Since the function is an analogue of normal method call it is not supposed to fail. * Any complications with resource allocation on call scheduling should be * anticipated, avoided and worked around by implementation. * * @param impl Threading implementation ID * @param out_summary_fault Optional pointer to variable to be set to 1 if function * call (or any sub-call) fails internally, or 0 if all calls return success * @param out_post_releasee Optional pointer to variable to receive releasee ID * associated with the call * @param dependencies_count Number of dependencies that are going to reference * this call as dependent releasee * @param dependent_releasee Optional releasee ID to reference with this call * @param call_wait Optional Wait ID that can later be used to wait for the call * @param call_func Pointer to function to be called * @param call_context Context parameter to be passed into the call * @param instance_index Index parameter to be passed into the call * @param call_name Optional name to be associated with the call (for debugging and state tracking) * * @ingroup threading * @see dThreadedCallWaitFunction * @see dThreadedCallDependenciesCountAlterFunction * @see dThreadingImplResourcesForCallsPreallocateFunction */ typedef void dThreadedCallPostFunction(dThreadingImplementationID impl, int *out_summary_fault/*=NULL*/, dCallReleaseeID *out_post_releasee/*=NULL*/, ddependencycount_t dependencies_count, dCallReleaseeID dependent_releasee/*=NULL*/, dCallWaitID call_wait/*=NULL*/, dThreadedCallFunction *call_func, void *call_context, dcallindex_t instance_index, const char *call_name/*=NULL*/); /** * @brief Add or remove extra dependencies from call that has been scheduled * or is in process of execution. * * Extra dependencies can be added to a call if exact number of sub-calls is * not known in advance at the moment the call is scheduled. Also, some dependencies * can be removed if sub-calls were planned but then dropped. * * In case if total dependency count of a call reaches zero by result of invoking * this function, the call is free to start executing immediately. * * After the call execution had been started, any additional dependencies can only * be added from the call function itself! * * @param impl Threading implementation ID * @param target_releasee ID of releasee to apply dependencies count change to * @param dependencies_count_change Number of dependencies to add or remove * * @ingroup threading * @see dThreadedCallPostFunction */ typedef void dThreadedCallDependenciesCountAlterFunction(dThreadingImplementationID impl, dCallReleaseeID target_releasee, ddependencychange_t dependencies_count_change); /** * @brief Wait for a posted call to complete. * * Function blocks until a call identified by @a call_wait completes or * timeout elapses. * * IT IS ILLEGAL TO INVOKE THIS FUNCTION FROM WITHIN A THREADED CALL! * This is because doing so will block a physical thread and will require * increasing worker thread count to avoid starvation. Use call dependencies * if it is necessary make sure sub-calls have been completed instead! * * If @a timeout_time_ptr is NULL, the function waits without time limit. If @a timeout_time_ptr * points to zero value, the function only checks status and does not block. * * If @a wait_name is available (and it should!) the string must remain valid for * the duration of wait. In most cases this should be a static string literal. * * Function is not expected to return failures caused by system call faults as * those are hardly ever possible to be handled in this case anyway. In event of * system call fault the function is supposed to terminate application. * * @param impl Threading implementation ID * @param out_wait_status Optional pointer to variable to receive 1 if waiting succeeded * or 0 in case of timeout * @param call_wait Wait ID that had been passed to scheduling a call that needs to be waited for * @param timeout_time_ptr Optional pointer to time specification the wait must not * last longer than (pass NULL for infinite timeout) * @param wait_name Optional name to be associated with the wait (for debugging and state tracking) * * @ingroup threading * @see dThreadedCallPostFunction */ typedef void dThreadedCallWaitFunction(dThreadingImplementationID impl, int *out_wait_status/*=NULL*/, dCallWaitID call_wait, const dThreadedWaitTime *timeout_time_ptr/*=NULL*/, const char *wait_name/*=NULL*/); /** * @brief Retrieve number of active threads that serve the implementation. * * @param impl Threading implementation ID * @returns Number of active threads * * @ingroup threading */ typedef unsigned dThreadingImplThreadCountRetrieveFunction(dThreadingImplementationID impl); /** * @brief Preallocate resources to handle posted calls. * * The function is intended to make sure enough resources is preallocated for the * implementation to be able to handle posted calls. Then @c max_simultaneous_calls_estimate * is an estimate of how many posted calls can potentially be active or scheduled * at the same time. The value is usually derived from the way the calls are posted * in library code and dependencies between them. * * @warning While working on an implementation be prepared that the estimate provided * yet rarely but theoretically can be exceeded due to unpredictability of thread execution. * * This function is normally going to be invoked by library each time it is entered * from outside to do the job but before any threaded calls are going to be posted. * * @param impl Threading implementation ID * @param max_simultaneous_calls_estimate An estimated number of calls that can be posted simultaneously * @returns 1 or 0 to indicate success or failure * * @ingroup threading * @see dThreadedCallPostFunction */ typedef int dThreadingImplResourcesForCallsPreallocateFunction(dThreadingImplementationID impl, ddependencycount_t max_simultaneous_calls_estimate); /** * @brief An interface structure with function pointers to be provided by threading implementation. */ typedef struct dxThreadingFunctionsInfo { unsigned struct_size; dMutexGroupAllocFunction *alloc_mutex_group; dMutexGroupFreeFunction *free_mutex_group; dMutexGroupMutexLockFunction *lock_group_mutex; dMutexGroupMutexUnlockFunction *unlock_group_mutex; dThreadedCallWaitAllocFunction *alloc_call_wait; dThreadedCallWaitResetFunction *reset_call_wait; dThreadedCallWaitFreeFunction *free_call_wait; dThreadedCallPostFunction *post_call; dThreadedCallDependenciesCountAlterFunction *alter_call_dependencies_count; dThreadedCallWaitFunction *wait_call; dThreadingImplThreadCountRetrieveFunction *retrieve_thread_count; dThreadingImplResourcesForCallsPreallocateFunction *preallocate_resources_for_calls; /* * Beware of Jon Watte's anger if you dare to uncomment this! * May cryptic text below be you a warning! * Стародавні легенди розказують, що кожного сміливця, хто наважиться порушити табу * і відкрити заборонений код, спіткає страшне прокляття і він відразу почне робити * одні лиш помилки. * * dMutexGroupMutexTryLockFunction *trylock_group_mutex; */ } dThreadingFunctionsInfo; #ifdef __cplusplus } #endif #endif /* #ifndef _ODE_THREADING_H_ */ ode-0.14/include/ode/threading_impl.h0000644000000000000000000002660112635011627016244 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * Builtin ODE threading implementation header. * * Copyright (C) 2011-2012 Oleh Derevenko. All rights reserved. * * e-mail: odar@eleks.com (change all "a" to "e") * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* * A threading implementation built into ODE for those who does not care to * or can't implement an own one. */ #ifndef _ODE_THREADING_IMPL_H_ #define _ODE_THREADING_IMPL_H_ #include #include #ifdef __cplusplus extern "C" { #endif struct dxThreadingThreadPool; typedef struct dxThreadingThreadPool *dThreadingThreadPoolID; /** * @brief Allocates built-in multi-threaded threading implementation object. * * A multi-threaded implementation is a type of implementation that has to be * served with a thread pool. The thread pool can be either the built-in ODE object * or set of external threads that dedicate themselves to this purpose and stay * in ODE until implementation releases them. * * @returns ID of object allocated or NULL on failure * * @ingroup threading * @see dThreadingThreadPoolServeMultiThreadedImplementation * @see dExternalThreadingServeMultiThreadedImplementation * @see dThreadingFreeImplementation */ ODE_API dThreadingImplementationID dThreadingAllocateMultiThreadedImplementation(); /** * @brief Retrieves the functions record of a built-in threading implementation. * * The implementation can be the one allocated by ODE (from @c dThreadingAllocateMultiThreadedImplementation). * Do not use this function with self-made custom implementations - * they should be bundled with their own set of functions. * * @param impl Threading implementation ID * @returns Pointer to associated functions structure * * @ingroup threading * @see dThreadingAllocateMultiThreadedImplementation */ ODE_API const dThreadingFunctionsInfo *dThreadingImplementationGetFunctions(dThreadingImplementationID impl); /** * @brief Requests a built-in implementation to release threads serving it. * * The function unblocks threads employed in implementation serving and lets them * return to from where they originate. It's the responsibility of external code * to make sure all the calls to ODE that might be dependent on given threading * implementation object had already returned before this call is made. If threading * implementation is still processing some posted calls while this function is * invoked the behavior is implementation dependent. * * This call is to be used to request the threads to be released before waiting * for them in host pool or before waiting for them to exit. Implementation object * must not be destroyed before it is known that all the serving threads have already * returned from it. If implementation needs to be reused after this function is called * and all the threads have exited from it a call to @c dThreadingImplementationCleanupForRestart * must be made to restore internal state of the object. * * If this function is called for self-threaded built-in threading implementation * the call has no effect. * * @param impl Threading implementation ID * * @ingroup threading * @see dThreadingAllocateMultiThreadedImplementation * @see dThreadingImplementationCleanupForRestart */ ODE_API void dThreadingImplementationShutdownProcessing(dThreadingImplementationID impl); /** * @brief Restores built-in implementation's state to let it be reused after shutdown. * * If a multi-threaded built-in implementation needs to be reused after a call * to @c dThreadingImplementationShutdownProcessing this call is to be made to * restore object's internal state. After that the implementation can be served again. * * If this function is called for self-threaded built-in threading implementation * the call has no effect. * * @param impl Threading implementation ID * * @ingroup threading * @see dThreadingAllocateMultiThreadedImplementation * @see dThreadingImplementationShutdownProcessing */ ODE_API void dThreadingImplementationCleanupForRestart(dThreadingImplementationID impl); /** * @brief Deletes an instance of built-in threading implementation. * * @warning A care must be taken to make sure the implementation is unassigned * from all the objects it was assigned to and that there are no more threads * serving it before attempting to call this function. * * @param impl Threading implementation ID * * @ingroup threading * @see dThreadingAllocateMultiThreadedImplementation */ ODE_API void dThreadingFreeImplementation(dThreadingImplementationID impl); typedef void (dThreadReadyToServeCallback)(void *callback_context); /** * @brief An entry point for external threads that would like to serve a built-in * threading implementation object. * * A thread that calls this function remains blocked in ODE and serves implementation * object @p impl until being released with @c dThreadingImplementationShutdownProcessing call. * This function can be used to provide external threads instead of ODE's built-in * thread pools. * * The optional callback @readiness_callback is called after the thread has reached * and has registered within the implementation. The implementation should not * be used until all dedicated threads register within it as otherwise it will not * have accurate view of the execution resources available. * * @param impl Threading implementation ID * @param readiness_callback Optional readiness callback to be called after thread enters the implementation * @param callback_context A value to be passed as parameter to readiness callback * * @ingroup threading * @see dThreadingAllocateMultiThreadedImplementation * @see dThreadingImplementationShutdownProcessing */ ODE_API void dExternalThreadingServeMultiThreadedImplementation(dThreadingImplementationID impl, dThreadReadyToServeCallback *readiness_callback/*=NULL*/, void *callback_context/*=NULL*/); /** * @brief Creates an instance of built-in thread pool object that can be used to serve * multi-threaded threading implementations. * * The threads allocated inherit priority of caller thread. Their affinity is not * explicitly adjusted and gets the value the system assigns by default. Threads * have their stack memory fully committed immediately on start. On POSIX platforms * threads are started with all the possible signals blocked. Threads execute * calls to @c dAllocateODEDataForThread with @p ode_data_allocate_flags * on initialization. * * On POSIX platforms this function must be called with signals masked * or other measures must be taken to prevent reception of signals by calling thread * for the duration of the call. * * @param thread_count Number of threads to start in pool * @param stack_size Size of stack to be used for every thread or 0 for system default value * @param ode_data_allocate_flags Flags to be passed to @c dAllocateODEDataForThread on behalf of each thread * @returns ID of object allocated or NULL on failure * * @ingroup threading * @see dThreadingAllocateMultiThreadedImplementation * @see dThreadingImplementationShutdownProcessing * @see dThreadingFreeThreadPool */ ODE_API dThreadingThreadPoolID dThreadingAllocateThreadPool(unsigned thread_count, size_t stack_size, unsigned int ode_data_allocate_flags, void *reserved/*=NULL*/); /** * @brief Commands an instance of built-in thread pool to serve a built-in multi-threaded * threading implementation. * * A pool can only serve one threading implementation at a time. * Call @c dThreadingImplementationShutdownProcessing to release pool threads * from implementation serving and make them idle. Pool threads must be released * from any implementations before pool is attempted to be deleted. * * This function waits for threads to register within implementation before returning. * So, after the function call exits the implementation can be used immediately. * * @param pool Thread pool ID to serve the implementation * @param impl Implementation ID of implementation to be served * * @ingroup threading * @see dThreadingAllocateThreadPool * @see dThreadingAllocateMultiThreadedImplementation * @see dThreadingImplementationShutdownProcessing */ ODE_API void dThreadingThreadPoolServeMultiThreadedImplementation(dThreadingThreadPoolID pool, dThreadingImplementationID impl); /** * @brief Waits until all pool threads are released from threading implementation * they might be serving. * * The function can be used after a call to @c dThreadingImplementationShutdownProcessing * to make sure all the threads have already been released by threading implementation * and it can be deleted or it can be cleaned up for restart and served by another pool * or this pool's threads can be used to serve another threading implementation. * * Note that is it not necessary to call this function before pool destruction * since @c dThreadingFreeThreadPool performs similar wait operation implicitly on its own. * * It is OK to call this function even if pool was not serving any threading implementation * in which case the call exits immediately with minimal delay. * * @param pool Thread pool ID to wait for * * @ingroup threading * @see dThreadingAllocateThreadPool * @see dThreadingImplementationShutdownProcessing * @see dThreadingFreeThreadPool */ ODE_API void dThreadingThreadPoolWaitIdleState(dThreadingThreadPoolID pool); /** * @brief Deletes a built-in thread pool instance. * * The pool threads must be released from any implementations they might be serving * before this function is called. Otherwise the call is going to block * and wait until pool's threads return. * * @param pool Thread pool ID to delete * * @ingroup threading * @see dThreadingAllocateThreadPool * @see dThreadingImplementationShutdownProcessing */ ODE_API void dThreadingFreeThreadPool(dThreadingThreadPoolID pool); #ifdef __cplusplus } #endif #endif /* #ifndef _ODE_THREADING_IMPL_H_ */ ode-0.14/include/ode/timer.h0000644000000000000000000000556312635011627014402 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef _ODE_TIMER_H_ #define _ODE_TIMER_H_ #include #ifdef __cplusplus extern "C" { #endif /* stop watch objects */ typedef struct dStopwatch { double time; /* total clock count */ unsigned long cc[2]; /* clock count since last `start' */ } dStopwatch; ODE_API void dStopwatchReset (dStopwatch *); ODE_API void dStopwatchStart (dStopwatch *); ODE_API void dStopwatchStop (dStopwatch *); ODE_API double dStopwatchTime (dStopwatch *); /* returns total time in secs */ /* code timers */ ODE_API void dTimerStart (const char *description); /* pass a static string here */ ODE_API void dTimerNow (const char *description); /* pass a static string here */ ODE_API void dTimerEnd(void); /* print out a timer report. if `average' is nonzero, print out the average * time for each slot (this is only meaningful if the same start-now-end * calls are being made repeatedly. */ ODE_API void dTimerReport (FILE *fout, int average); /* resolution */ /* returns the timer ticks per second implied by the timing hardware or API. * the actual timer resolution may not be this great. */ ODE_API double dTimerTicksPerSecond(void); /* returns an estimate of the actual timer resolution, in seconds. this may * be greater than 1/ticks_per_second. */ ODE_API double dTimerResolution(void); #ifdef __cplusplus } #endif #endif ode-0.14/include/ode/version.h.in0000644000000000000000000000013612635011627015343 0ustar rootroot#ifndef _ODE_VERSION_H_ #define _ODE_VERSION_H_ #define dODE_VERSION "@ODE_VERSION@" #endif ode-0.14/libccd/0000775000000000000000000000000012635012023012117 5ustar rootrootode-0.14/libccd/BSD-LICENSE0000644000000000000000000000402112635011627013536 0ustar rootrootlibccd ------- Copyright (c)2010 Daniel Fiser , Intelligent and Mobile Robotics Group, Department of Cybernetics, Faculty of Electrical Engineering, Czech Technical University in Prague. All rights reserved. This work was supported by SYMBRION and REPLICATOR projects. The SYMBRION project is funded by European Commission within the work "Future and Emergent Technologies Proactive" under grant agreement no. 216342. The REPLICATOR project is funded within the work programme "Cognitive Systems, Interaction, Robotics" under grant agreement no. 216240. http://www.symbrion.eu/ http://www.replicators.eu/ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ode-0.14/libccd/Makefile.am0000644000000000000000000000011312635011627014155 0ustar rootrootSUBDIRS = src EXTRA_DIST = \ bootstrap \ BSD-LICENSE \ README ode-0.14/libccd/README0000644000000000000000000000444312635011627013013 0ustar rootrootlibccd is library for a collision detection between two convex shapes. libccd implements variation on Gilbert–Johnson–Keerthi algorithm plus Expand Polytope Algorithm (EPA) and also implements algorithm Minkowski Portal Refinement (MPR, a.k.a. XenoCollide) as described in Game Programming Gems 7. For more info see home of libccd: http://libccd.danfis.cz. Dependencies ------------- This library is currently based only on standard libraries. The only exception are testsuites that are built on top of CU (cu.danfis.cz) library licensed under LGPL, however only testing depends on it and libccd library itself can be distributed without it. License -------- libccd is licensed under OSI-approved 3-clause BSD License, text of license is distributed along with source code in BSD-LICENSE file. Each file should include license notice, the rest should be considered as licensed under 3-clause BSD License. Compile And Install -------------------- Simply type 'make' and 'make install' in src/ directory. Library libccd is by default compiled in double precision of floating point numbers - you can controll this by options USE_SINGLE/USE_DOUBLE, i.e.: $ make USE_SINGLE=yes will compile library in single precision. Installation directory can be changed by options PREFIX, INCLUDEDIR and LIBDIR. For more info type 'make help'. Compile And Install Using Autotools ------------------------------------ libccd also contains support for autotools: 1) Generate configure script etc.: $ ./bootstrap 2) Create new build/ directory: $ mkdir build && cd build 3) Run configure script: $ ../configure 4) Run make and make install: $ make && make install configure script can change the way libccd is compiled and installed, most significant option is --enable-double-precision which enables double precision (single is default in this case). Usage ------ See ccd.h for public API. In your application include , setup ccd_t structure and run some of functions (all functions are reentrant). Then link with libccd.a. Directories ------------ src/ - contains source files of libccd. src/testsuites - testsuites - libccd must be compiled before compiling this. src/testsuites/cu - CU unit testing framework src/testsuites/regressions - files ready for regression tests doc/ - some documentation. ode-0.14/libccd/bootstrap0000755000000000000000000000033112635011627014066 0ustar rootroot#!/bin/sh # on Mac libtoolize is called glibtoolize LIBTOOLIZE=libtoolize if [ `uname -s` = Darwin ]; then LIBTOOLIZE=glibtoolize fi $LIBTOOLIZE -c --automake aclocal autoheader autoconf automake -a --foreign -c ode-0.14/libccd/configure.ac0000644000000000000000000000243412635011627014417 0ustar rootroot# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. #AC_PREREQ([2.65]) AC_INIT([libccd], [1.0], [danfis@danfis.cz]) AC_CONFIG_SRCDIR([src/ccd.c]) AC_CONFIG_HEADERS([src/config.h]) AM_INIT_AUTOMAKE(foreign) # Checks for programs. AC_PROG_CXX AC_PROG_CC AC_PROG_INSTALL AC_DISABLE_SHARED LT_INIT # Checks for libraries. AC_CHECK_LIB([m], [main]) # FIXME: Replace `main' with a function in `-lrt': AC_CHECK_LIB([rt], [main]) # Checks for header files. AC_CHECK_HEADERS([float.h stdlib.h string.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T # Checks for library functions. AC_FUNC_FORK AC_CHECK_FUNCS([clock_gettime]) use_double=no AC_ARG_ENABLE(double-precision, AS_HELP_STRING([--enable-double-precision], [enable double precision computations instead of single precision]), [use_double=$enableval]) if test x$use_double = xno then CCD_PRECISION=CCD_SINGLE else CCD_PRECISION=CCD_DOUBLE fi AC_SUBST(CCD_PRECISION) AC_CONFIG_FILES([Makefile src/Makefile src/ccd/precision.h src/testsuites/Makefile src/testsuites/cu/Makefile]) AC_OUTPUT ode-0.14/libccd/src/0000775000000000000000000000000012635012023012706 5ustar rootrootode-0.14/libccd/src/Makefile.am0000644000000000000000000000061012635011627014746 0ustar rootrootSUBDIRS = . testsuites AM_CFLAGS = -std=c99 noinst_LTLIBRARIES = libccd.la libccd_la_SOURCES = alloc.c ccd/alloc.h \ ccd/compiler.h \ ccd/dbg.h \ ccd.c ccd/ccd.h \ ccd/list.h \ polytope.c ccd/polytope.h \ ccd/quat.h \ ccd/simplex.h \ support.c ccd/support.h \ vec3.c ccd/vec3.h \ mpr.c nodist_libccd_la_SOURCES = ccd/precision.h EXTRA_DIST = ccd/precision.h.in ode-0.14/libccd/src/Makefile.include0000644000000000000000000000361012635011627015777 0ustar rootroot### # libccd # --------------------------------- # Copyright (c)2010 Daniel Fiser # # # This file is part of libccd. # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file BDS-LICENSE for details or see # . # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. ## CC ?= gcc M4 ?= m4 PYTHON ?= python SYSTEM = $(shell uname) SYSTEM_CXXFLAGS = SYSTEM_LDFLAGS = ifeq '$(SYSTEM)' 'FreeBSD' SYSTEM_CXXFLAGS = -Wno-long-long else endif NOWALL ?= no NOPEDANTIC ?= no DEBUG ?= no PROFIL ?= no ifeq '$(PROFIL)' 'yes' DEBUG = yes endif ifeq '$(DEBUG)' 'yes' CFLAGS = -g endif ifeq '$(PROFIL)' 'yes' CFLAGS += -pg endif ifneq '$(NOWALL)' 'yes' CFLAGS += -Wall endif ifneq '$(NOPEDANTIC)' 'yes' CFLAGS += -pedantic endif CONFIG_FLAGS = USE_DOUBLE ?= yes USE_SINGLE ?= no ifeq '$(USE_SINGLE)' 'yes' CONFIG_FLAGS += -DUSE_SINGLE USE_DOUBLE = no endif ifeq '$(USE_DOUBLE)' 'yes' CONFIG_FLAGS += -DUSE_DOUBLE endif CFLAGS += --std=gnu99 LDFLAGS += $(SYSTEM_LDFLAGS) CHECKTARGETS = check-dep: $(CHECKTARGETS) PREFIX ?= /usr/local INCLUDEDIR ?= include LIBDIR ?= lib showvars: @echo "SYSTEM = "$(SYSTEM) @echo "" @echo "CC = $(CC)" @echo "M4 = $(M4)" @echo "" @echo "DEBUG = $(DEBUG)" @echo "PROFIL = $(PROFIL)" @echo "NOWALL = $(NOWALL)" @echo "NOPEDANTIC = $(NOPEDANTIC)" @echo "USE_SINGLE = $(USE_SINGLE)" @echo "USE_DOUBLE = $(USE_DOUBLE)" @echo "" @echo "CFLAGS = $(CFLAGS)" @echo "LDFLAGS = $(LDFLAGS)" @echo "CONFIG_FLAGS = $(CONFIG_FLAGS)" @echo "" @echo "PREFIX = $(PREFIX)" @echo "INCLUDEDIR = $(INCLUDEDIR)" @echo "LIBDIR = $(LIBDIR)" @echo "" .DEFAULT_GOAL := all .PHONY: showvars ode-0.14/libccd/src/alloc.c0000644000000000000000000000155512635011627014161 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif void *ccdRealloc(void *ptr, size_t size) { void *ret = realloc(ptr, size); if (ret == NULL && size != 0){ fprintf(stderr, "Fatal error: Allocation of memory failed!\n"); fflush(stderr); exit(-1); } return ret; } ode-0.14/libccd/src/ccd.c0000644000000000000000000007275212635011627013627 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif /** Performs GJK algorithm. Returns 0 if intersection was found and simplex * is filled with resulting polytope. */ static int __ccdGJK(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *simplex); /** Performs GJK+EPA algorithm. Returns 0 if intersection was found and * pt is filled with resulting polytope and nearest with pointer to * nearest element (vertex, edge, face) of polytope to origin. */ static int __ccdGJKEPA(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_pt_t *pt, ccd_pt_el_t **nearest); /** Returns true if simplex contains origin. * This function also alteres simplex and dir according to further * processing of GJK algorithm. */ static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir); static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir); static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir); static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir); /** d = a x b x c */ _ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b, const ccd_vec3_t *c, ccd_vec3_t *d); /** Transforms simplex to polytope. It is assumed that simplex has 4 * vertices. */ static int simplexToPolytope4(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *simplex, ccd_pt_t *pt, ccd_pt_el_t **nearest); /** Transforms simplex to polytope, three vertices required */ static int simplexToPolytope3(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_simplex_t *simplex, ccd_pt_t *pt, ccd_pt_el_t **nearest); /** Transforms simplex to polytope, two vertices required */ static int simplexToPolytope2(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_simplex_t *simplex, ccd_pt_t *pt, ccd_pt_el_t **nearest); /** Expands polytope using new vertex v. */ static void expandPolytope(ccd_pt_t *pt, ccd_pt_el_t *el, const ccd_support_t *newv); /** Finds next support point (at stores it in out argument). * Returns 0 on success, -1 otherwise */ static int nextSupport(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_pt_el_t *el, ccd_support_t *out); void ccdFirstDirDefault(const void *o1, const void *o2, ccd_vec3_t *dir) { ccdVec3Set(dir, CCD_ONE, CCD_ZERO, CCD_ZERO); } int ccdGJKIntersect(const void *obj1, const void *obj2, const ccd_t *ccd) { ccd_simplex_t simplex; return __ccdGJK(obj1, obj2, ccd, &simplex) == 0; } int ccdGJKSeparate(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_vec3_t *sep) { ccd_pt_t polytope; ccd_pt_el_t *nearest; int ret; ccdPtInit(&polytope); ret = __ccdGJKEPA(obj1, obj2, ccd, &polytope, &nearest); // set separation vector if (nearest) ccdVec3Copy(sep, &nearest->witness); ccdPtDestroy(&polytope); return ret; } static int penEPAPosCmp(const void *a, const void *b) { ccd_pt_vertex_t *v1, *v2; v1 = *(ccd_pt_vertex_t **)a; v2 = *(ccd_pt_vertex_t **)b; if (ccdEq(v1->dist, v2->dist)){ return 0; }else if (v1->dist < v2->dist){ return -1; }else{ return 1; } } static void penEPAPos(const ccd_pt_t *pt, const ccd_pt_el_t *nearest, ccd_vec3_t *pos) { ccd_pt_vertex_t *v; ccd_pt_vertex_t **vs; size_t i, len; ccd_real_t scale; // compute median len = 0; ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ len++; } vs = CCD_ALLOC_ARR(ccd_pt_vertex_t *, len); i = 0; ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ vs[i++] = v; } qsort(vs, len, sizeof(ccd_pt_vertex_t *), penEPAPosCmp); ccdVec3Set(pos, CCD_ZERO, CCD_ZERO, CCD_ZERO); scale = CCD_ZERO; if (len % 2 == 1) len++; for (i = 0; i < len / 2; i++){ ccdVec3Add(pos, &vs[i]->v.v1); ccdVec3Add(pos, &vs[i]->v.v2); scale += CCD_REAL(2.); } ccdVec3Scale(pos, CCD_ONE / scale); free(vs); } int ccdGJKPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) { ccd_pt_t polytope; ccd_pt_el_t *nearest; int ret; ccdPtInit(&polytope); ret = __ccdGJKEPA(obj1, obj2, ccd, &polytope, &nearest); // set separation vector if (ret == 0 && nearest){ // compute depth of penetration *depth = CCD_SQRT(nearest->dist); // store normalized direction vector ccdVec3Copy(dir, &nearest->witness); ccdVec3Normalize(dir); // compute position penEPAPos(&polytope, nearest, pos); } ccdPtDestroy(&polytope); return ret; } static int __ccdGJK(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *simplex) { unsigned long iterations; ccd_vec3_t dir; // direction vector ccd_support_t last; // last support point int do_simplex_res; // initialize simplex struct ccdSimplexInit(simplex); // get first direction ccd->first_dir(obj1, obj2, &dir); // get first support point __ccdSupport(obj1, obj2, &dir, ccd, &last); // and add this point to simplex as last one ccdSimplexAdd(simplex, &last); // set up direction vector to as (O - last) which is exactly -last ccdVec3Copy(&dir, &last.v); ccdVec3Scale(&dir, -CCD_ONE); // start iterations for (iterations = 0UL; iterations < ccd->max_iterations; ++iterations) { // obtain support point __ccdSupport(obj1, obj2, &dir, ccd, &last); // check if farthest point in Minkowski difference in direction dir // isn't somewhere before origin (the test on negative dot product) // - because if it is, objects are not intersecting at all. if (ccdVec3Dot(&last.v, &dir) < CCD_ZERO){ return -1; // intersection not found } // add last support vector to simplex ccdSimplexAdd(simplex, &last); // if doSimplex returns 1 if objects intersect, -1 if objects don't // intersect and 0 if algorithm should continue do_simplex_res = doSimplex(simplex, &dir); if (do_simplex_res == 1){ return 0; // intersection found }else if (do_simplex_res == -1){ return -1; // intersection not found } if (ccdIsZero(ccdVec3Len2(&dir))){ return -1; // intersection not found } } // intersection wasn't found return -1; } static int __ccdGJKEPA(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_pt_t *polytope, ccd_pt_el_t **nearest) { ccd_simplex_t simplex; ccd_support_t supp; // support point int ret, size; *nearest = NULL; // run GJK and obtain terminal simplex ret = __ccdGJK(obj1, obj2, ccd, &simplex); if (ret != 0) return -1; // transform simplex to polytope - simplex won't be used anymore size = ccdSimplexSize(&simplex); if (size == 4){ if (simplexToPolytope4(obj1, obj2, ccd, &simplex, polytope, nearest) != 0){ return 0;// touch contact } }else if (size == 3){ if (simplexToPolytope3(obj1, obj2, ccd, &simplex, polytope, nearest) != 0){ return 0; // touch contact } }else{ // size == 2 if (simplexToPolytope2(obj1, obj2, ccd, &simplex, polytope, nearest) != 0){ return 0; // touch contact } } while (1){ // get triangle nearest to origin *nearest = ccdPtNearest(polytope); // get next support point if (nextSupport(obj1, obj2, ccd, *nearest, &supp) != 0) break; // expand nearest triangle using new point - supp expandPolytope(polytope, *nearest, &supp); } return 0; } static int doSimplex2(ccd_simplex_t *simplex, ccd_vec3_t *dir) { const ccd_support_t *A, *B; ccd_vec3_t AB, AO, tmp; ccd_real_t dot; // get last added as A A = ccdSimplexLast(simplex); // get the other point B = ccdSimplexPoint(simplex, 0); // compute AB oriented segment ccdVec3Sub2(&AB, &B->v, &A->v); // compute AO vector ccdVec3Copy(&AO, &A->v); ccdVec3Scale(&AO, -CCD_ONE); // dot product AB . AO dot = ccdVec3Dot(&AB, &AO); // check if origin doesn't lie on AB segment ccdVec3Cross(&tmp, &AB, &AO); if (ccdIsZero(ccdVec3Len2(&tmp)) && dot > CCD_ZERO){ return 1; } // check if origin is in area where AB segment is if (ccdIsZero(dot) || dot < CCD_ZERO){ // origin is in outside are of A ccdSimplexSet(simplex, 0, A); ccdSimplexSetSize(simplex, 1); ccdVec3Copy(dir, &AO); }else{ // origin is in area where AB segment is // keep simplex untouched and set direction to // AB x AO x AB tripleCross(&AB, &AO, &AB, dir); } return 0; } static int doSimplex3(ccd_simplex_t *simplex, ccd_vec3_t *dir) { const ccd_support_t *A, *B, *C; ccd_vec3_t AO, AB, AC, ABC, tmp; ccd_real_t dot, dist; // get last added as A A = ccdSimplexLast(simplex); // get the other points B = ccdSimplexPoint(simplex, 1); C = ccdSimplexPoint(simplex, 0); // check touching contact dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL); if (ccdIsZero(dist)){ return 1; } // check if triangle is really triangle (has area > 0) // if not simplex can't be expanded and thus no itersection is found if (ccdVec3Eq(&A->v, &B->v) || ccdVec3Eq(&A->v, &C->v)){ return -1; } // compute AO vector ccdVec3Copy(&AO, &A->v); ccdVec3Scale(&AO, -CCD_ONE); // compute AB and AC segments and ABC vector (perpendircular to triangle) ccdVec3Sub2(&AB, &B->v, &A->v); ccdVec3Sub2(&AC, &C->v, &A->v); ccdVec3Cross(&ABC, &AB, &AC); ccdVec3Cross(&tmp, &ABC, &AC); dot = ccdVec3Dot(&tmp, &AO); if (ccdIsZero(dot) || dot > CCD_ZERO){ dot = ccdVec3Dot(&AC, &AO); if (ccdIsZero(dot) || dot > CCD_ZERO){ // C is already in place ccdSimplexSet(simplex, 1, A); ccdSimplexSetSize(simplex, 2); tripleCross(&AC, &AO, &AC, dir); }else{ ccd_do_simplex3_45: dot = ccdVec3Dot(&AB, &AO); if (ccdIsZero(dot) || dot > CCD_ZERO){ ccdSimplexSet(simplex, 0, B); ccdSimplexSet(simplex, 1, A); ccdSimplexSetSize(simplex, 2); tripleCross(&AB, &AO, &AB, dir); }else{ ccdSimplexSet(simplex, 0, A); ccdSimplexSetSize(simplex, 1); ccdVec3Copy(dir, &AO); } } }else{ ccdVec3Cross(&tmp, &AB, &ABC); dot = ccdVec3Dot(&tmp, &AO); if (ccdIsZero(dot) || dot > CCD_ZERO){ goto ccd_do_simplex3_45; }else{ dot = ccdVec3Dot(&ABC, &AO); if (ccdIsZero(dot) || dot > CCD_ZERO){ ccdVec3Copy(dir, &ABC); }else{ ccd_support_t Ctmp; ccdSupportCopy(&Ctmp, C); ccdSimplexSet(simplex, 0, B); ccdSimplexSet(simplex, 1, &Ctmp); ccdVec3Copy(dir, &ABC); ccdVec3Scale(dir, -CCD_ONE); } } } return 0; } static int doSimplex4(ccd_simplex_t *simplex, ccd_vec3_t *dir) { const ccd_support_t *A, *B, *C, *D; ccd_vec3_t AO, AB, AC, AD, ABC, ACD, ADB; int B_on_ACD, C_on_ADB, D_on_ABC; int AB_O, AC_O, AD_O; ccd_real_t dist; // get last added as A A = ccdSimplexLast(simplex); // get the other points B = ccdSimplexPoint(simplex, 2); C = ccdSimplexPoint(simplex, 1); D = ccdSimplexPoint(simplex, 0); // check if tetrahedron is really tetrahedron (has volume > 0) // if it is not simplex can't be expanded and thus no intersection is // found dist = ccdVec3PointTriDist2(&A->v, &B->v, &C->v, &D->v, NULL); if (ccdIsZero(dist)){ return -1; } // check if origin lies on some of tetrahedron's face - if so objects // intersect dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &C->v, NULL); if (ccdIsZero(dist)) return 1; dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &C->v, &D->v, NULL); if (ccdIsZero(dist)) return 1; dist = ccdVec3PointTriDist2(ccd_vec3_origin, &A->v, &B->v, &D->v, NULL); if (ccdIsZero(dist)) return 1; dist = ccdVec3PointTriDist2(ccd_vec3_origin, &B->v, &C->v, &D->v, NULL); if (ccdIsZero(dist)) return 1; // compute AO, AB, AC, AD segments and ABC, ACD, ADB normal vectors ccdVec3Copy(&AO, &A->v); ccdVec3Scale(&AO, -CCD_ONE); ccdVec3Sub2(&AB, &B->v, &A->v); ccdVec3Sub2(&AC, &C->v, &A->v); ccdVec3Sub2(&AD, &D->v, &A->v); ccdVec3Cross(&ABC, &AB, &AC); ccdVec3Cross(&ACD, &AC, &AD); ccdVec3Cross(&ADB, &AD, &AB); // side (positive or negative) of B, C, D relative to planes ACD, ADB // and ABC respectively B_on_ACD = ccdSign(ccdVec3Dot(&ACD, &AB)); C_on_ADB = ccdSign(ccdVec3Dot(&ADB, &AC)); D_on_ABC = ccdSign(ccdVec3Dot(&ABC, &AD)); // whether origin is on same side of ACD, ADB, ABC as B, C, D // respectively AB_O = ccdSign(ccdVec3Dot(&ACD, &AO)) == B_on_ACD; AC_O = ccdSign(ccdVec3Dot(&ADB, &AO)) == C_on_ADB; AD_O = ccdSign(ccdVec3Dot(&ABC, &AO)) == D_on_ABC; if (AB_O && AC_O && AD_O){ // origin is in tetrahedron return 1; // rearrange simplex to triangle and call doSimplex3() }else if (!AB_O){ // B is farthest from the origin among all of the tetrahedron's // points, so remove it from the list and go on with the triangle // case // D and C are in place ccdSimplexSet(simplex, 2, A); ccdSimplexSetSize(simplex, 3); }else if (!AC_O){ // C is farthest ccdSimplexSet(simplex, 1, D); ccdSimplexSet(simplex, 0, B); ccdSimplexSet(simplex, 2, A); ccdSimplexSetSize(simplex, 3); }else{ // (!AD_O) ccdSimplexSet(simplex, 0, C); ccdSimplexSet(simplex, 1, B); ccdSimplexSet(simplex, 2, A); ccdSimplexSetSize(simplex, 3); } return doSimplex3(simplex, dir); } static int doSimplex(ccd_simplex_t *simplex, ccd_vec3_t *dir) { if (ccdSimplexSize(simplex) == 2){ // simplex contains segment only one segment return doSimplex2(simplex, dir); }else if (ccdSimplexSize(simplex) == 3){ // simplex contains triangle return doSimplex3(simplex, dir); }else{ // ccdSimplexSize(simplex) == 4 // tetrahedron - this is the only shape which can encapsule origin // so doSimplex4() also contains test on it return doSimplex4(simplex, dir); } } _ccd_inline void tripleCross(const ccd_vec3_t *a, const ccd_vec3_t *b, const ccd_vec3_t *c, ccd_vec3_t *d) { ccd_vec3_t e; ccdVec3Cross(&e, a, b); ccdVec3Cross(d, &e, c); } /** Transforms simplex to polytope. It is assumed that simplex has 4 * vertices! */ static int simplexToPolytope4(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *simplex, ccd_pt_t *pt, ccd_pt_el_t **nearest) { const ccd_support_t *a, *b, *c, *d; int use_polytope3; ccd_real_t dist; ccd_pt_vertex_t *v[4]; ccd_pt_edge_t *e[6]; size_t i; a = ccdSimplexPoint(simplex, 0); b = ccdSimplexPoint(simplex, 1); c = ccdSimplexPoint(simplex, 2); d = ccdSimplexPoint(simplex, 3); // check if origin lies on some of tetrahedron's face - if so use // simplexToPolytope3() use_polytope3 = 0; dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &c->v, NULL); if (ccdIsZero(dist)){ use_polytope3 = 1; } dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &c->v, &d->v, NULL); if (ccdIsZero(dist)){ use_polytope3 = 1; ccdSimplexSet(simplex, 1, c); ccdSimplexSet(simplex, 2, d); } dist = ccdVec3PointTriDist2(ccd_vec3_origin, &a->v, &b->v, &d->v, NULL); if (ccdIsZero(dist)){ use_polytope3 = 1; ccdSimplexSet(simplex, 2, d); } dist = ccdVec3PointTriDist2(ccd_vec3_origin, &b->v, &c->v, &d->v, NULL); if (ccdIsZero(dist)){ use_polytope3 = 1; ccdSimplexSet(simplex, 0, b); ccdSimplexSet(simplex, 1, c); ccdSimplexSet(simplex, 2, d); } if (use_polytope3){ ccdSimplexSetSize(simplex, 3); return simplexToPolytope3(obj1, obj2, ccd, simplex, pt, nearest); } // no touching contact - simply create tetrahedron for (i = 0; i < 4; i++){ v[i] = ccdPtAddVertex(pt, ccdSimplexPoint(simplex, i)); } e[0] = ccdPtAddEdge(pt, v[0], v[1]); e[1] = ccdPtAddEdge(pt, v[1], v[2]); e[2] = ccdPtAddEdge(pt, v[2], v[0]); e[3] = ccdPtAddEdge(pt, v[3], v[0]); e[4] = ccdPtAddEdge(pt, v[3], v[1]); e[5] = ccdPtAddEdge(pt, v[3], v[2]); ccdPtAddFace(pt, e[0], e[1], e[2]); ccdPtAddFace(pt, e[3], e[4], e[0]); ccdPtAddFace(pt, e[4], e[5], e[1]); ccdPtAddFace(pt, e[5], e[3], e[2]); return 0; } /** Transforms simplex to polytope, three vertices required */ static int simplexToPolytope3(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_simplex_t *simplex, ccd_pt_t *pt, ccd_pt_el_t **nearest) { const ccd_support_t *a, *b, *c; ccd_support_t d, d2; ccd_vec3_t ab, ac, dir; ccd_pt_vertex_t *v[5]; ccd_pt_edge_t *e[9]; ccd_real_t dist, dist2; *nearest = NULL; a = ccdSimplexPoint(simplex, 0); b = ccdSimplexPoint(simplex, 1); c = ccdSimplexPoint(simplex, 2); // If only one triangle left from previous GJK run origin lies on this // triangle. So it is necessary to expand triangle into two // tetrahedrons connected with base (which is exactly abc triangle). // get next support point in direction of normal of triangle ccdVec3Sub2(&ab, &b->v, &a->v); ccdVec3Sub2(&ac, &c->v, &a->v); ccdVec3Cross(&dir, &ab, &ac); __ccdSupport(obj1, obj2, &dir, ccd, &d); dist = ccdVec3PointTriDist2(&d.v, &a->v, &b->v, &c->v, NULL); // and second one take in opposite direction ccdVec3Scale(&dir, -CCD_ONE); __ccdSupport(obj1, obj2, &dir, ccd, &d2); dist2 = ccdVec3PointTriDist2(&d2.v, &a->v, &b->v, &c->v, NULL); // check if face isn't already on edge of minkowski sum and thus we // have touching contact if (ccdIsZero(dist) || ccdIsZero(dist2)){ v[0] = ccdPtAddVertex(pt, a); v[1] = ccdPtAddVertex(pt, b); v[2] = ccdPtAddVertex(pt, c); e[0] = ccdPtAddEdge(pt, v[0], v[1]); e[1] = ccdPtAddEdge(pt, v[1], v[2]); e[2] = ccdPtAddEdge(pt, v[2], v[0]); *nearest = (ccd_pt_el_t *)ccdPtAddFace(pt, e[0], e[1], e[2]); return -1; } // form polyhedron v[0] = ccdPtAddVertex(pt, a); v[1] = ccdPtAddVertex(pt, b); v[2] = ccdPtAddVertex(pt, c); v[3] = ccdPtAddVertex(pt, &d); v[4] = ccdPtAddVertex(pt, &d2); e[0] = ccdPtAddEdge(pt, v[0], v[1]); e[1] = ccdPtAddEdge(pt, v[1], v[2]); e[2] = ccdPtAddEdge(pt, v[2], v[0]); e[3] = ccdPtAddEdge(pt, v[3], v[0]); e[4] = ccdPtAddEdge(pt, v[3], v[1]); e[5] = ccdPtAddEdge(pt, v[3], v[2]); e[6] = ccdPtAddEdge(pt, v[4], v[0]); e[7] = ccdPtAddEdge(pt, v[4], v[1]); e[8] = ccdPtAddEdge(pt, v[4], v[2]); ccdPtAddFace(pt, e[3], e[4], e[0]); ccdPtAddFace(pt, e[4], e[5], e[1]); ccdPtAddFace(pt, e[5], e[3], e[2]); ccdPtAddFace(pt, e[6], e[7], e[0]); ccdPtAddFace(pt, e[7], e[8], e[1]); ccdPtAddFace(pt, e[8], e[6], e[2]); return 0; } /** Transforms simplex to polytope, two vertices required */ static int simplexToPolytope2(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_simplex_t *simplex, ccd_pt_t *pt, ccd_pt_el_t **nearest) { const ccd_support_t *a, *b; ccd_vec3_t ab, ac, dir; ccd_support_t supp[4]; ccd_pt_vertex_t *v[6]; ccd_pt_edge_t *e[12]; size_t i; int found; a = ccdSimplexPoint(simplex, 0); b = ccdSimplexPoint(simplex, 1); // This situation is a bit tricky. If only one segment comes from // previous run of GJK - it means that either this segment is on // minkowski edge (and thus we have touch contact) or it it isn't and // therefore segment is somewhere *inside* minkowski sum and it *must* // be possible to fully enclose this segment with polyhedron formed by // at least 8 triangle faces. // get first support point (any) found = 0; for (i = 0; i < ccd_points_on_sphere_len; i++){ __ccdSupport(obj1, obj2, &ccd_points_on_sphere[i], ccd, &supp[0]); if (!ccdVec3Eq(&a->v, &supp[0].v) && !ccdVec3Eq(&b->v, &supp[0].v)){ found = 1; break; } } if (!found) goto simplexToPolytope2_touching_contact; // get second support point in opposite direction than supp[0] ccdVec3Copy(&dir, &supp[0].v); ccdVec3Scale(&dir, -CCD_ONE); __ccdSupport(obj1, obj2, &dir, ccd, &supp[1]); if (ccdVec3Eq(&a->v, &supp[1].v) || ccdVec3Eq(&b->v, &supp[1].v)) goto simplexToPolytope2_touching_contact; // next will be in direction of normal of triangle a,supp[0],supp[1] ccdVec3Sub2(&ab, &supp[0].v, &a->v); ccdVec3Sub2(&ac, &supp[1].v, &a->v); ccdVec3Cross(&dir, &ab, &ac); __ccdSupport(obj1, obj2, &dir, ccd, &supp[2]); if (ccdVec3Eq(&a->v, &supp[2].v) || ccdVec3Eq(&b->v, &supp[2].v)) goto simplexToPolytope2_touching_contact; // and last one will be in opposite direction ccdVec3Scale(&dir, -CCD_ONE); __ccdSupport(obj1, obj2, &dir, ccd, &supp[3]); if (ccdVec3Eq(&a->v, &supp[3].v) || ccdVec3Eq(&b->v, &supp[3].v)) goto simplexToPolytope2_touching_contact; goto simplexToPolytope2_not_touching_contact; simplexToPolytope2_touching_contact: v[0] = ccdPtAddVertex(pt, a); v[1] = ccdPtAddVertex(pt, b); *nearest = (ccd_pt_el_t *)ccdPtAddEdge(pt, v[0], v[1]); return -1; simplexToPolytope2_not_touching_contact: // form polyhedron v[0] = ccdPtAddVertex(pt, a); v[1] = ccdPtAddVertex(pt, &supp[0]); v[2] = ccdPtAddVertex(pt, b); v[3] = ccdPtAddVertex(pt, &supp[1]); v[4] = ccdPtAddVertex(pt, &supp[2]); v[5] = ccdPtAddVertex(pt, &supp[3]); e[0] = ccdPtAddEdge(pt, v[0], v[1]); e[1] = ccdPtAddEdge(pt, v[1], v[2]); e[2] = ccdPtAddEdge(pt, v[2], v[3]); e[3] = ccdPtAddEdge(pt, v[3], v[0]); e[4] = ccdPtAddEdge(pt, v[4], v[0]); e[5] = ccdPtAddEdge(pt, v[4], v[1]); e[6] = ccdPtAddEdge(pt, v[4], v[2]); e[7] = ccdPtAddEdge(pt, v[4], v[3]); e[8] = ccdPtAddEdge(pt, v[5], v[0]); e[9] = ccdPtAddEdge(pt, v[5], v[1]); e[10] = ccdPtAddEdge(pt, v[5], v[2]); e[11] = ccdPtAddEdge(pt, v[5], v[3]); ccdPtAddFace(pt, e[4], e[5], e[0]); ccdPtAddFace(pt, e[5], e[6], e[1]); ccdPtAddFace(pt, e[6], e[7], e[2]); ccdPtAddFace(pt, e[7], e[4], e[3]); ccdPtAddFace(pt, e[8], e[9], e[0]); ccdPtAddFace(pt, e[9], e[10], e[1]); ccdPtAddFace(pt, e[10], e[11], e[2]); ccdPtAddFace(pt, e[11], e[8], e[3]); return 0; } /** Expands polytope's tri by new vertex v. Triangle tri is replaced by * three triangles each with one vertex in v. */ static void expandPolytope(ccd_pt_t *pt, ccd_pt_el_t *el, const ccd_support_t *newv) { ccd_pt_vertex_t *v[5]; ccd_pt_edge_t *e[8] = {0}; ccd_pt_face_t *f[2]; // element can be either segment or triangle if (el->type == CCD_PT_EDGE){ // In this case, segment should be replaced by new point. // Simpliest case is when segment stands alone and in this case // this segment is replaced by two other segments both connected to // newv. // Segment can be also connected to max two faces and in that case // each face must be replaced by two other faces. To do this // correctly it is necessary to have correctly ordered edges and // vertices which is exactly what is done in following code. // ccdPtEdgeVertices((const ccd_pt_edge_t *)el, &v[0], &v[2]); ccdPtEdgeFaces((ccd_pt_edge_t *)el, &f[0], &f[1]); if (f[0]){ ccdPtFaceEdges(f[0], &e[0], &e[1], &e[2]); if (e[0] == (ccd_pt_edge_t *)el){ e[0] = e[2]; }else if (e[1] == (ccd_pt_edge_t *)el){ e[1] = e[2]; } ccdPtEdgeVertices(e[0], &v[1], &v[3]); if (v[1] != v[0] && v[3] != v[0]){ e[2] = e[0]; e[0] = e[1]; e[1] = e[2]; if (v[1] == v[2]) v[1] = v[3]; }else{ if (v[1] == v[0]) v[1] = v[3]; } if (f[1]){ ccdPtFaceEdges(f[1], &e[2], &e[3], &e[4]); if (e[2] == (ccd_pt_edge_t *)el){ e[2] = e[4]; }else if (e[3] == (ccd_pt_edge_t *)el){ e[3] = e[4]; } ccdPtEdgeVertices(e[2], &v[3], &v[4]); if (v[3] != v[2] && v[4] != v[2]){ e[4] = e[2]; e[2] = e[3]; e[3] = e[4]; if (v[3] == v[0]) v[3] = v[4]; }else{ if (v[3] == v[2]) v[3] = v[4]; } } v[4] = ccdPtAddVertex(pt, newv); ccdPtDelFace(pt, f[0]); if (f[1]){ ccdPtDelFace(pt, f[1]); ccdPtDelEdge(pt, (ccd_pt_edge_t *)el); } e[4] = ccdPtAddEdge(pt, v[4], v[2]); e[5] = ccdPtAddEdge(pt, v[4], v[0]); e[6] = ccdPtAddEdge(pt, v[4], v[1]); if (f[1]) e[7] = ccdPtAddEdge(pt, v[4], v[3]); ccdPtAddFace(pt, e[1], e[4], e[6]); ccdPtAddFace(pt, e[0], e[6], e[5]); if (f[1]){ ccdPtAddFace(pt, e[3], e[5], e[7]); ccdPtAddFace(pt, e[4], e[7], e[2]); }else{ ccdPtAddFace(pt, e[4], e[5], (ccd_pt_edge_t *)el); } } }else{ // el->type == CCD_PT_FACE // replace triangle by tetrahedron without base (base would be the // triangle that will be removed) // get triplet of surrounding edges and vertices of triangle face ccdPtFaceEdges((const ccd_pt_face_t *)el, &e[0], &e[1], &e[2]); ccdPtEdgeVertices(e[0], &v[0], &v[1]); ccdPtEdgeVertices(e[1], &v[2], &v[3]); // following code sorts edges to have e[0] between vertices 0-1, // e[1] between 1-2 and e[2] between 2-0 if (v[2] != v[1] && v[3] != v[1]){ // swap e[1] and e[2] e[3] = e[1]; e[1] = e[2]; e[2] = e[3]; } if (v[3] != v[0] && v[3] != v[1]) v[2] = v[3]; // remove triangle face ccdPtDelFace(pt, (ccd_pt_face_t *)el); // expand triangle to tetrahedron v[3] = ccdPtAddVertex(pt, newv); e[3] = ccdPtAddEdge(pt, v[3], v[0]); e[4] = ccdPtAddEdge(pt, v[3], v[1]); e[5] = ccdPtAddEdge(pt, v[3], v[2]); ccdPtAddFace(pt, e[3], e[4], e[0]); ccdPtAddFace(pt, e[4], e[5], e[1]); ccdPtAddFace(pt, e[5], e[3], e[2]); } } /** Finds next support point (at stores it in out argument). * Returns 0 on success, -1 otherwise */ static int nextSupport(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_pt_el_t *el, ccd_support_t *out) { ccd_vec3_t *a, *b, *c; ccd_real_t dist; if (el->type == CCD_PT_VERTEX) return -1; // touch contact if (ccdIsZero(el->dist)) return -1; __ccdSupport(obj1, obj2, &el->witness, ccd, out); if (el->type == CCD_PT_EDGE){ // fetch end points of edge ccdPtEdgeVec3((ccd_pt_edge_t *)el, &a, &b); // get distance from segment dist = ccdVec3PointSegmentDist2(&out->v, a, b, NULL); }else{ // el->type == CCD_PT_FACE // fetch vertices of triangle face ccdPtFaceVec3((ccd_pt_face_t *)el, &a, &b, &c); // check if new point can significantly expand polytope dist = ccdVec3PointTriDist2(&out->v, a, b, c, NULL); } if (dist < ccd->epa_tolerance) return -1; return 0; } ode-0.14/libccd/src/ccd/0000775000000000000000000000000012635012023013437 5ustar rootrootode-0.14/libccd/src/ccd/alloc.h0000644000000000000000000000256312635011627014717 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_ALLOC_H__ #define __CCD_ALLOC_H__ #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * Functions and macros required for memory allocation. */ /* Memory allocation: */ #define __CCD_ALLOC_MEMORY(type, ptr_old, size) \ (type *)ccdRealloc((void *)ptr_old, (size)) /** Allocate memory for one element of type. */ #define CCD_ALLOC(type) \ __CCD_ALLOC_MEMORY(type, NULL, sizeof(type)) /** Allocate memory for array of elements of type type. */ #define CCD_ALLOC_ARR(type, num_elements) \ __CCD_ALLOC_MEMORY(type, NULL, sizeof(type) * (num_elements)) #define CCD_REALLOC_ARR(ptr, type, num_elements) \ __CCD_ALLOC_MEMORY(type, ptr, sizeof(type) * (num_elements)) void *ccdRealloc(void *ptr, size_t size); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_ALLOC_H__ */ ode-0.14/libccd/src/ccd/ccd.h0000644000000000000000000001143212635011627014351 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010,2011 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_H__ #define __CCD_H__ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * Type of *support* function that takes pointer to 3D object and direction * and returns (via vec argument) furthest point from object in specified * direction. */ typedef void (*ccd_support_fn)(const void *obj, const ccd_vec3_t *dir, ccd_vec3_t *vec); /** * Returns (via dir argument) first direction vector that will be used in * initialization of algorithm. */ typedef void (*ccd_first_dir_fn)(const void *obj1, const void *obj2, ccd_vec3_t *dir); /** * Returns (via center argument) geometric center (some point near center) * of given object. */ typedef void (*ccd_center_fn)(const void *obj1, ccd_vec3_t *center); /** * Main structure of CCD algorithm. */ struct _ccd_t { ccd_first_dir_fn first_dir; /*!< Returns initial direction where first !< support point will be searched*/ ccd_support_fn support1; /*!< Function that returns support point of !< first object*/ ccd_support_fn support2; /*!< Function that returns support point of !< second object*/ ccd_center_fn center1; /*!< Function that returns geometric center of !< first object*/ ccd_center_fn center2; /*!< Function that returns geometric center of !< second object*/ unsigned long max_iterations; /*!< Maximal number of iterations*/ ccd_real_t epa_tolerance; ccd_real_t mpr_tolerance; /*!< Boundary tolerance for MPR algorithm*/ }; typedef struct _ccd_t ccd_t; /** * Default first direction. */ void ccdFirstDirDefault(const void *o1, const void *o2, ccd_vec3_t *dir); #define CCD_INIT(ccd) \ do { \ (ccd)->first_dir = ccdFirstDirDefault; \ (ccd)->support1 = NULL; \ (ccd)->support2 = NULL; \ (ccd)->center1 = NULL; \ (ccd)->center2 = NULL; \ \ (ccd)->max_iterations = (unsigned long)-1; \ (ccd)->epa_tolerance = CCD_REAL(0.0001); \ (ccd)->mpr_tolerance = CCD_REAL(0.0001); \ } while(0) /** * Returns true if two given objects interest. */ int ccdGJKIntersect(const void *obj1, const void *obj2, const ccd_t *ccd); /** * This function computes separation vector of two objects. Separation * vector is minimal translation of obj2 to get obj1 and obj2 speparated * (without intersection). * Returns 0 if obj1 and obj2 intersect and sep is filled with translation * vector. If obj1 and obj2 don't intersect -1 is returned. */ int ccdGJKSeparate(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_vec3_t *sep); /** * Computes penetration of obj2 into obj1. * Depth of penetration, direction and position is returned. It means that * if obj2 is translated by distance depth in direction dir objects will * have touching contact, pos should be position in global coordinates * where force should take a place. * * CCD+EPA algorithm is used. * * Returns 0 if obj1 and obj2 intersect and depth, dir and pos are filled * if given non-NULL pointers. * If obj1 and obj2 don't intersect -1 is returned. */ int ccdGJKPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); /** * Returns true if two given objects intersect - MPR algorithm is used. */ int ccdMPRIntersect(const void *obj1, const void *obj2, const ccd_t *ccd); /** * Computes penetration of obj2 into obj1. * Depth of penetration, direction and position is returned, i.e. if obj2 * is translated by computed depth in resulting direction obj1 and obj2 * would have touching contact. Position is point in global coordinates * where force should be take a place. * * Minkowski Portal Refinement algorithm is used (MPR, a.k.a. XenoCollide, * see Game Programming Gem 7). * * Returns 0 if obj1 and obj2 intersect, otherwise -1 is returned. */ int ccdMPRPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_H__ */ ode-0.14/libccd/src/ccd/compiler.h0000644000000000000000000000311312635011627015427 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_COMPILER_H__ #define __CCD_COMPILER_H__ #include #define ccd_offsetof(TYPE, MEMBER) offsetof(TYPE, MEMBER) #define ccd_container_of(ptr, type, member) \ (type *)( (char *)ptr - ccd_offsetof(type, member)) /** * Marks inline function. */ #ifdef __GNUC__ /*# define _ccd_inline static inline __attribute__((always_inline))*/ # define _ccd_inline static inline #else /* __GNUC__ */ # define _ccd_inline static __inline #endif /* __GNUC__ */ /** * __prefetch(x) - prefetches the cacheline at "x" for read * __prefetchw(x) - prefetches the cacheline at "x" for write */ #ifdef __GNUC__ # define _ccd_prefetch(x) __builtin_prefetch(x) # define _ccd_prefetchw(x) __builtin_prefetch(x,1) #else /* __GNUC__ */ # define _ccd_prefetch(x) ((void)0) # define _ccd_prefetchw(x) ((void)0) #endif /* __GNUC__ */ #ifdef __ICC /* disable unused parameter warning */ # pragma warning(disable:869) /* disable annoying "operands are evaluated in unspecified order" warning */ # pragma warning(disable:981) #endif /* __ICC */ #endif /* __CCD_COMPILER_H__ */ ode-0.14/libccd/src/ccd/dbg.h0000644000000000000000000000326112635011627014355 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_DBG_H__ #define __CCD_DBG_H__ /** * Some macros which can be used for printing debug info to stderr if macro * NDEBUG not defined. * * DBG_PROLOGUE can be specified as string and this string will be * prepended to output text */ #ifndef NDEBUG #include #ifndef DBG_PROLOGUE # define DBG_PROLOGUE #endif # define DBG(format, ...) do { \ fprintf(stderr, DBG_PROLOGUE "%s :: " format "\n", __func__, ## __VA_ARGS__); \ fflush(stderr); \ } while (0) # define DBG2(str) do { \ fprintf(stderr, DBG_PROLOGUE "%s :: " str "\n", __func__); \ fflush(stderr); \ } while (0) # define DBG_VEC3(vec, prefix) do {\ fprintf(stderr, DBG_PROLOGUE "%s :: %s[%lf %lf %lf]\n", \ __func__, prefix, ccdVec3X(vec), ccdVec3Y(vec), ccdVec3Z(vec)); \ fflush(stderr); \ } while (0) /* # define DBG_VEC3(vec, prefix) do {\ fprintf(stderr, DBG_PROLOGUE "%s :: %s[%.20lf %.20lf %.20lf]\n", \ __func__, prefix, ccdVec3X(vec), ccdVec3Y(vec), ccdVec3Z(vec)); \ fflush(stderr); \ } while (0) */ #else # define DBG(format, ...) # define DBG2(str) # define DBG_VEC3(v, prefix) #endif #endif /* __CCD_DBG_H__ */ ode-0.14/libccd/src/ccd/list.h0000644000000000000000000000726512635011627014604 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_LIST_H__ #define __CCD_LIST_H__ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct _ccd_list_t { struct _ccd_list_t *next, *prev; }; typedef struct _ccd_list_t ccd_list_t; /** * Get the struct for this entry. * @ptr: the &ccd_list_t pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define ccdListEntry(ptr, type, member) \ ccd_container_of(ptr, type, member) /** * Iterates over list. */ #define ccdListForEach(list, item) \ for (item = (list)->next; \ _ccd_prefetch((item)->next), item != (list); \ item = (item)->next) /** * Iterates over list safe against remove of list entry */ #define ccdListForEachSafe(list, item, tmp) \ for (item = (list)->next, tmp = (item)->next; \ item != (list); \ item = tmp, tmp = (item)->next) /** * Iterates over list of given type. * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define ccdListForEachEntry(head, pos, postype, member) \ for (pos = ccdListEntry((head)->next, postype, member); \ _ccd_prefetch(pos->member.next), &pos->member != (head); \ pos = ccdListEntry(pos->member.next, postype, member)) /** * Iterates over list of given type safe against removal of list entry * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define ccdListForEachEntrySafe(head, pos, postype, n, ntype, member) \ for (pos = ccdListEntry((head)->next, postype, member), \ n = ccdListEntry(pos->member.next, postype, member); \ &pos->member != (head); \ pos = n, n = ccdListEntry(n->member.next, ntype, member)) /** * Initialize list. */ _ccd_inline void ccdListInit(ccd_list_t *l); _ccd_inline ccd_list_t *ccdListNext(ccd_list_t *l); _ccd_inline ccd_list_t *ccdListPrev(ccd_list_t *l); /** * Returns true if list is empty. */ _ccd_inline int ccdListEmpty(const ccd_list_t *head); /** * Appends item to end of the list l. */ _ccd_inline void ccdListAppend(ccd_list_t *l, ccd_list_t *item); /** * Removes item from list. */ _ccd_inline void ccdListDel(ccd_list_t *item); /// /// INLINES: /// _ccd_inline void ccdListInit(ccd_list_t *l) { l->next = l; l->prev = l; } _ccd_inline ccd_list_t *ccdListNext(ccd_list_t *l) { return l->next; } _ccd_inline ccd_list_t *ccdListPrev(ccd_list_t *l) { return l->prev; } _ccd_inline int ccdListEmpty(const ccd_list_t *head) { return head->next == head; } _ccd_inline void ccdListAppend(ccd_list_t *l, ccd_list_t *newccd) { newccd->prev = l->prev; newccd->next = l; l->prev->next = newccd; l->prev = newccd; } _ccd_inline void ccdListDel(ccd_list_t *item) { item->next->prev = item->prev; item->prev->next = item->next; item->next = item; item->prev = item; } #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_LIST_H__ */ ode-0.14/libccd/src/ccd/polytope.h0000644000000000000000000002043612635011627015477 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_POLYTOPE_H__ #define __CCD_POLYTOPE_H__ #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define CCD_PT_VERTEX 1 #define CCD_PT_EDGE 2 #define CCD_PT_FACE 3 #define __CCD_PT_EL \ int type; /*! type of element */ \ ccd_real_t dist; /*! distance from origin */ \ ccd_vec3_t witness; /*! witness point of projection of origin */ \ ccd_list_t list; /*! list of elements of same type */ /** * General polytope element. * Could be vertex, edge or triangle. */ struct _ccd_pt_el_t { __CCD_PT_EL }; typedef struct _ccd_pt_el_t ccd_pt_el_t; struct _ccd_pt_edge_t; struct _ccd_pt_face_t; /** * Polytope's vertex. */ struct _ccd_pt_vertex_t { __CCD_PT_EL int id; ccd_support_t v; ccd_list_t edges; //!< List of edges }; typedef struct _ccd_pt_vertex_t ccd_pt_vertex_t; /** * Polytope's edge. */ struct _ccd_pt_edge_t { __CCD_PT_EL ccd_pt_vertex_t *vertex[2]; //!< Reference to vertices struct _ccd_pt_face_t *faces[2]; //!< Reference to faces ccd_list_t vertex_list[2]; //!< List items in vertices' lists }; typedef struct _ccd_pt_edge_t ccd_pt_edge_t; /** * Polytope's triangle faces. */ struct _ccd_pt_face_t { __CCD_PT_EL ccd_pt_edge_t *edge[3]; //!< Reference to surrounding edges }; typedef struct _ccd_pt_face_t ccd_pt_face_t; /** * Struct containing polytope. */ struct _ccd_pt_t { ccd_list_t vertices; //!< List of vertices ccd_list_t edges; //!< List of edges ccd_list_t faces; //!< List of faces ccd_pt_el_t *nearest; ccd_real_t nearest_dist; int nearest_type; }; typedef struct _ccd_pt_t ccd_pt_t; void ccdPtInit(ccd_pt_t *pt); void ccdPtDestroy(ccd_pt_t *pt); /** * Returns vertices surrounding given triangle face. */ _ccd_inline void ccdPtFaceVec3(const ccd_pt_face_t *face, ccd_vec3_t **a, ccd_vec3_t **b, ccd_vec3_t **c); _ccd_inline void ccdPtFaceVertices(const ccd_pt_face_t *face, ccd_pt_vertex_t **a, ccd_pt_vertex_t **b, ccd_pt_vertex_t **c); _ccd_inline void ccdPtFaceEdges(const ccd_pt_face_t *f, ccd_pt_edge_t **a, ccd_pt_edge_t **b, ccd_pt_edge_t **c); _ccd_inline void ccdPtEdgeVec3(const ccd_pt_edge_t *e, ccd_vec3_t **a, ccd_vec3_t **b); _ccd_inline void ccdPtEdgeVertices(const ccd_pt_edge_t *e, ccd_pt_vertex_t **a, ccd_pt_vertex_t **b); _ccd_inline void ccdPtEdgeFaces(const ccd_pt_edge_t *e, ccd_pt_face_t **f1, ccd_pt_face_t **f2); /** * Adds vertex to polytope and returns pointer to newly created vertex. */ ccd_pt_vertex_t *ccdPtAddVertex(ccd_pt_t *pt, const ccd_support_t *v); _ccd_inline ccd_pt_vertex_t *ccdPtAddVertexCoords(ccd_pt_t *pt, ccd_real_t x, ccd_real_t y, ccd_real_t z); /** * Adds edge to polytope. */ ccd_pt_edge_t *ccdPtAddEdge(ccd_pt_t *pt, ccd_pt_vertex_t *v1, ccd_pt_vertex_t *v2); /** * Adds face to polytope. */ ccd_pt_face_t *ccdPtAddFace(ccd_pt_t *pt, ccd_pt_edge_t *e1, ccd_pt_edge_t *e2, ccd_pt_edge_t *e3); /** * Deletes vertex from polytope. * Returns 0 on success, -1 otherwise. */ _ccd_inline int ccdPtDelVertex(ccd_pt_t *pt, ccd_pt_vertex_t *); _ccd_inline int ccdPtDelEdge(ccd_pt_t *pt, ccd_pt_edge_t *); _ccd_inline int ccdPtDelFace(ccd_pt_t *pt, ccd_pt_face_t *); /** * Recompute distances from origin for all elements in pt. */ void ccdPtRecomputeDistances(ccd_pt_t *pt); /** * Returns nearest element to origin. */ ccd_pt_el_t *ccdPtNearest(ccd_pt_t *pt); void ccdPtDumpSVT(ccd_pt_t *pt, const char *fn); void ccdPtDumpSVT2(ccd_pt_t *pt, FILE *); /**** INLINES ****/ _ccd_inline ccd_pt_vertex_t *ccdPtAddVertexCoords(ccd_pt_t *pt, ccd_real_t x, ccd_real_t y, ccd_real_t z) { ccd_support_t s; ccdVec3Set(&s.v, x, y, z); return ccdPtAddVertex(pt, &s); } _ccd_inline int ccdPtDelVertex(ccd_pt_t *pt, ccd_pt_vertex_t *v) { // test if any edge is connected to this vertex if (!ccdListEmpty(&v->edges)) return -1; // delete vertex from main list ccdListDel(&v->list); if ((void *)pt->nearest == (void *)v){ pt->nearest = NULL; } free(v); return 0; } _ccd_inline int ccdPtDelEdge(ccd_pt_t *pt, ccd_pt_edge_t *e) { // text if any face is connected to this edge (faces[] is always // aligned to lower indices) if (e->faces[0] != NULL) return -1; // disconnect edge from lists of edges in vertex struct ccdListDel(&e->vertex_list[0]); ccdListDel(&e->vertex_list[1]); // disconnect edge from main list ccdListDel(&e->list); if ((void *)pt->nearest == (void *)e){ pt->nearest = NULL; } free(e); return 0; } _ccd_inline int ccdPtDelFace(ccd_pt_t *pt, ccd_pt_face_t *f) { ccd_pt_edge_t *e; size_t i; // remove face from edges' recerence lists for (i = 0; i < 3; i++){ e = f->edge[i]; if (e->faces[0] == f){ e->faces[0] = e->faces[1]; } e->faces[1] = NULL; } // remove face from list of all faces ccdListDel(&f->list); if ((void *)pt->nearest == (void *)f){ pt->nearest = NULL; } free(f); return 0; } _ccd_inline void ccdPtFaceVec3(const ccd_pt_face_t *face, ccd_vec3_t **a, ccd_vec3_t **b, ccd_vec3_t **c) { *a = &face->edge[0]->vertex[0]->v.v; *b = &face->edge[0]->vertex[1]->v.v; if (face->edge[1]->vertex[0] != face->edge[0]->vertex[0] && face->edge[1]->vertex[0] != face->edge[0]->vertex[1]){ *c = &face->edge[1]->vertex[0]->v.v; }else{ *c = &face->edge[1]->vertex[1]->v.v; } } _ccd_inline void ccdPtFaceVertices(const ccd_pt_face_t *face, ccd_pt_vertex_t **a, ccd_pt_vertex_t **b, ccd_pt_vertex_t **c) { *a = face->edge[0]->vertex[0]; *b = face->edge[0]->vertex[1]; if (face->edge[1]->vertex[0] != face->edge[0]->vertex[0] && face->edge[1]->vertex[0] != face->edge[0]->vertex[1]){ *c = face->edge[1]->vertex[0]; }else{ *c = face->edge[1]->vertex[1]; } } _ccd_inline void ccdPtFaceEdges(const ccd_pt_face_t *f, ccd_pt_edge_t **a, ccd_pt_edge_t **b, ccd_pt_edge_t **c) { *a = f->edge[0]; *b = f->edge[1]; *c = f->edge[2]; } _ccd_inline void ccdPtEdgeVec3(const ccd_pt_edge_t *e, ccd_vec3_t **a, ccd_vec3_t **b) { *a = &e->vertex[0]->v.v; *b = &e->vertex[1]->v.v; } _ccd_inline void ccdPtEdgeVertices(const ccd_pt_edge_t *e, ccd_pt_vertex_t **a, ccd_pt_vertex_t **b) { *a = e->vertex[0]; *b = e->vertex[1]; } _ccd_inline void ccdPtEdgeFaces(const ccd_pt_edge_t *e, ccd_pt_face_t **f1, ccd_pt_face_t **f2) { *f1 = e->faces[0]; *f2 = e->faces[1]; } #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_POLYTOPE_H__ */ ode-0.14/libccd/src/ccd/precision.h.in0000644000000000000000000000036212635011627016220 0ustar rootroot#ifndef __CCD_PRECISION_H__ #define __CCD_PRECISION_H__ /* define either CCD_SINGLE or CCD_DOUBLE */ #if defined(CCD_IDESINGLE) #define CCD_SINGLE #elif defined(CCD_IDEDOUBLE) #define CCD_DOUBLE #else #define @CCD_PRECISION@ #endif #endif ode-0.14/libccd/src/ccd/quat.h0000644000000000000000000001326612635011627014601 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_QUAT_H__ #define __CCD_QUAT_H__ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct _ccd_quat_t { ccd_real_t q[4]; //!< x, y, z, w }; typedef struct _ccd_quat_t ccd_quat_t; #define CCD_QUAT(name, x, y, z, w) \ ccd_quat_t name = { {x, y, z, w} } _ccd_inline ccd_real_t ccdQuatLen2(const ccd_quat_t *q); _ccd_inline ccd_real_t ccdQuatLen(const ccd_quat_t *q); _ccd_inline void ccdQuatSet(ccd_quat_t *q, ccd_real_t x, ccd_real_t y, ccd_real_t z, ccd_real_t w); _ccd_inline void ccdQuatCopy(ccd_quat_t *dest, const ccd_quat_t *src); _ccd_inline int ccdQuatNormalize(ccd_quat_t *q); _ccd_inline void ccdQuatSetAngleAxis(ccd_quat_t *q, ccd_real_t angle, const ccd_vec3_t *axis); _ccd_inline void ccdQuatScale(ccd_quat_t *q, ccd_real_t k); /** * q = q * q2 */ _ccd_inline void ccdQuatMul(ccd_quat_t *q, const ccd_quat_t *q2); /** * q = a * b */ _ccd_inline void ccdQuatMul2(ccd_quat_t *q, const ccd_quat_t *a, const ccd_quat_t *b); /** * Inverts quaternion. * Returns 0 on success. */ _ccd_inline int ccdQuatInvert(ccd_quat_t *q); _ccd_inline int ccdQuatInvert2(ccd_quat_t *dest, const ccd_quat_t *src); /** * Rotate vector v by quaternion q. */ _ccd_inline void ccdQuatRotVec(ccd_vec3_t *v, const ccd_quat_t *q); /**** INLINES ****/ _ccd_inline ccd_real_t ccdQuatLen2(const ccd_quat_t *q) { ccd_real_t len; len = q->q[0] * q->q[0]; len += q->q[1] * q->q[1]; len += q->q[2] * q->q[2]; len += q->q[3] * q->q[3]; return len; } _ccd_inline ccd_real_t ccdQuatLen(const ccd_quat_t *q) { return CCD_SQRT(ccdQuatLen2(q)); } _ccd_inline void ccdQuatSet(ccd_quat_t *q, ccd_real_t x, ccd_real_t y, ccd_real_t z, ccd_real_t w) { q->q[0] = x; q->q[1] = y; q->q[2] = z; q->q[3] = w; } _ccd_inline void ccdQuatCopy(ccd_quat_t *dest, const ccd_quat_t *src) { *dest = *src; } _ccd_inline int ccdQuatNormalize(ccd_quat_t *q) { ccd_real_t len = ccdQuatLen(q); if (len < CCD_EPS) return 0; ccdQuatScale(q, CCD_ONE / len); return 1; } _ccd_inline void ccdQuatSetAngleAxis(ccd_quat_t *q, ccd_real_t angle, const ccd_vec3_t *axis) { ccd_real_t a, x, y, z, n, s; a = angle/2; x = ccdVec3X(axis); y = ccdVec3Y(axis); z = ccdVec3Z(axis); n = CCD_SQRT(x*x + y*y + z*z); // axis==0? (treat this the same as angle==0 with an arbitrary axis) if (n < CCD_EPS){ q->q[0] = q->q[1] = q->q[2] = CCD_ZERO; q->q[3] = CCD_ONE; }else{ s = sin(a)/n; q->q[3] = cos(a); q->q[0] = x*s; q->q[1] = y*s; q->q[2] = z*s; ccdQuatNormalize(q); } } _ccd_inline void ccdQuatScale(ccd_quat_t *q, ccd_real_t k) { size_t i; for (i = 0; i < 4; i++) q->q[i] *= k; } _ccd_inline void ccdQuatMul(ccd_quat_t *q, const ccd_quat_t *q2) { ccd_quat_t a; ccdQuatCopy(&a, q); ccdQuatMul2(q, &a, q2); } _ccd_inline void ccdQuatMul2(ccd_quat_t *q, const ccd_quat_t *a, const ccd_quat_t *b) { q->q[0] = a->q[3] * b->q[0] + a->q[0] * b->q[3] + a->q[1] * b->q[2] - a->q[2] * b->q[1]; q->q[1] = a->q[3] * b->q[1] + a->q[1] * b->q[3] - a->q[0] * b->q[2] + a->q[2] * b->q[0]; q->q[2] = a->q[3] * b->q[2] + a->q[2] * b->q[3] + a->q[0] * b->q[1] - a->q[1] * b->q[0]; q->q[3] = a->q[3] * b->q[3] - a->q[0] * b->q[0] - a->q[1] * b->q[1] - a->q[2] * b->q[2]; } _ccd_inline int ccdQuatInvert(ccd_quat_t *q) { ccd_real_t len2 = ccdQuatLen2(q); if (len2 < CCD_EPS) return -1; len2 = CCD_ONE / len2; q->q[0] = -q->q[0] * len2; q->q[1] = -q->q[1] * len2; q->q[2] = -q->q[2] * len2; q->q[3] = q->q[3] * len2; return 0; } _ccd_inline int ccdQuatInvert2(ccd_quat_t *dest, const ccd_quat_t *src) { ccdQuatCopy(dest, src); return ccdQuatInvert(dest); } _ccd_inline void ccdQuatRotVec(ccd_vec3_t *v, const ccd_quat_t *q) { ccd_real_t w, x, y, z, ww, xx, yy, zz, wx, wy, wz, xy, xz, yz; ccd_real_t vx, vy, vz; w = q->q[3]; x = q->q[0]; y = q->q[1]; z = q->q[2]; ww = w*w; xx = x*x; yy = y*y; zz = z*z; wx = w*x; wy = w*y; wz = w*z; xy = x*y; xz = x*z; yz = y*z; vx = ww * ccdVec3X(v) + xx * ccdVec3X(v) - yy * ccdVec3X(v) - zz * ccdVec3X(v) + 2 * ((xy - wz) * ccdVec3Y(v) + (xz + wy) * ccdVec3Z(v)); vy = ww * ccdVec3Y(v) - xx * ccdVec3Y(v) + yy * ccdVec3Y(v) - zz * ccdVec3Y(v) + 2 * ((xy + wz) * ccdVec3X(v) + (yz - wx) * ccdVec3Z(v)); vz = ww * ccdVec3Z(v) - xx * ccdVec3Z(v) - yy * ccdVec3Z(v) + zz * ccdVec3Z(v) + 2 * ((xz - wy) * ccdVec3X(v) + (yz + wx) * ccdVec3Y(v)); ccdVec3Set(v, vx, vy, vz); } #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_QUAT_H__ */ ode-0.14/libccd/src/ccd/simplex.h0000644000000000000000000000531312635011627015302 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_SIMPLEX_H__ #define __CCD_SIMPLEX_H__ #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct _ccd_simplex_t { ccd_support_t ps[4]; int last; /*!< index of last added point*/ }; typedef struct _ccd_simplex_t ccd_simplex_t; _ccd_inline void ccdSimplexInit(ccd_simplex_t *s); _ccd_inline int ccdSimplexSize(const ccd_simplex_t *s); _ccd_inline const ccd_support_t *ccdSimplexLast(const ccd_simplex_t *s); _ccd_inline const ccd_support_t *ccdSimplexPoint(const ccd_simplex_t *s, int idx); _ccd_inline ccd_support_t *ccdSimplexPointW(ccd_simplex_t *s, int idx); _ccd_inline void ccdSimplexAdd(ccd_simplex_t *s, const ccd_support_t *v); _ccd_inline void ccdSimplexSet(ccd_simplex_t *s, size_t pos, const ccd_support_t *a); _ccd_inline void ccdSimplexSetSize(ccd_simplex_t *s, int size); _ccd_inline void ccdSimplexSwap(ccd_simplex_t *s, size_t pos1, size_t pos2); /**** INLINES ****/ _ccd_inline void ccdSimplexInit(ccd_simplex_t *s) { s->last = -1; } _ccd_inline int ccdSimplexSize(const ccd_simplex_t *s) { return s->last + 1; } _ccd_inline const ccd_support_t *ccdSimplexLast(const ccd_simplex_t *s) { return ccdSimplexPoint(s, s->last); } _ccd_inline const ccd_support_t *ccdSimplexPoint(const ccd_simplex_t *s, int idx) { /* here is no check on boundaries */ return &s->ps[idx]; } _ccd_inline ccd_support_t *ccdSimplexPointW(ccd_simplex_t *s, int idx) { return &s->ps[idx]; } _ccd_inline void ccdSimplexAdd(ccd_simplex_t *s, const ccd_support_t *v) { /* here is no check on boundaries in sake of speed */ ++s->last; ccdSupportCopy(s->ps + s->last, v); } _ccd_inline void ccdSimplexSet(ccd_simplex_t *s, size_t pos, const ccd_support_t *a) { ccdSupportCopy(s->ps + pos, a); } _ccd_inline void ccdSimplexSetSize(ccd_simplex_t *s, int size) { s->last = size - 1; } _ccd_inline void ccdSimplexSwap(ccd_simplex_t *s, size_t pos1, size_t pos2) { ccd_support_t supp; ccdSupportCopy(&supp, &s->ps[pos1]); ccdSupportCopy(&s->ps[pos1], &s->ps[pos2]); ccdSupportCopy(&s->ps[pos2], &supp); } #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_SIMPLEX_H__ */ ode-0.14/libccd/src/ccd/support.h0000644000000000000000000000271112635011627015334 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_SUPPORT_H__ #define __CCD_SUPPORT_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct _ccd_support_t { ccd_vec3_t v; /*!< Support point in minkowski sum*/ ccd_vec3_t v1; /*!< Support point in obj1*/ ccd_vec3_t v2; /*!< Support point in obj2*/ }; typedef struct _ccd_support_t ccd_support_t; _ccd_inline void ccdSupportCopy(ccd_support_t *, const ccd_support_t *s); /** * Computes support point of obj1 and obj2 in direction dir. * Support point is returned via supp. */ void __ccdSupport(const void *obj1, const void *obj2, const ccd_vec3_t *dir, const ccd_t *ccd, ccd_support_t *supp); /**** INLINES ****/ _ccd_inline void ccdSupportCopy(ccd_support_t *d, const ccd_support_t *s) { *d = *s; } #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_SUPPORT_H__ */ ode-0.14/libccd/src/ccd/vec3.h0000644000000000000000000002001212635011627014452 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010,2011 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #ifndef __CCD_VEC3_H__ #define __CCD_VEC3_H__ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef CCD_SINGLE # ifndef CCD_DOUBLE # error You must define CCD_SINGLE or CCD_DOUBLE # endif /* CCD_DOUBLE */ #endif /* CCD_SINGLE */ #if defined(_MSC_VER) /* Define fmin, fmax, fminf, fmaxf which are missing from MSVC (up to VS2005 at least) */ static __inline double fmin(double x, double y) { return __min(x, y); } static __inline double fmax(double x, double y) { return __max(x, y); } static __inline float fminf(float x, float y) { return __min(x, y); } static __inline float fmaxf(float x, float y) { return __max(x, y); } #endif /* #if defined(_MSC_VER) */ #ifdef CCD_SINGLE # ifdef CCD_DOUBLE # error You can define either CCD_SINGLE or CCD_DOUBLE, not both! # endif /* CCD_DOUBLE */ typedef float ccd_real_t; /*# define CCD_EPS 1E-6*/ # define CCD_EPS FLT_EPSILON # define CCD_REAL_MAX FLT_MAX # define CCD_REAL(x) (x ## f) /*!< form a constant */ # define CCD_SQRT(x) (sqrtf(x)) /*!< square root */ # define CCD_FABS(x) (fabsf(x)) /*!< absolute value */ # define CCD_FMAX(x, y) (fmaxf((x), (y))) /*!< maximum of two floats */ # define CCD_FMIN(x, y) (fminf((x), (y))) /*!< minimum of two floats */ #endif /* CCD_SINGLE */ #ifdef CCD_DOUBLE typedef double ccd_real_t; /*# define CCD_EPS 1E-10*/ # define CCD_EPS DBL_EPSILON # define CCD_REAL_MAX DBL_MAX # define CCD_REAL(x) (x) /*!< form a constant */ # define CCD_SQRT(x) (sqrt(x)) /*!< square root */ # define CCD_FABS(x) (fabs(x)) /*!< absolute value */ # define CCD_FMAX(x, y) (fmax((x), (y))) /*!< maximum of two floats */ # define CCD_FMIN(x, y) (fmin((x), (y))) /*!< minimum of two floats */ #endif /* CCD_DOUBLE */ #define CCD_ONE CCD_REAL(1.) #define CCD_ZERO CCD_REAL(0.) struct _ccd_vec3_t { ccd_real_t v[3]; }; typedef struct _ccd_vec3_t ccd_vec3_t; /** * Holds origin (0,0,0) - this variable is meant to be read-only! */ extern ccd_vec3_t *ccd_vec3_origin; /** * Array of points uniformly distributed on unit sphere. */ extern ccd_vec3_t *ccd_points_on_sphere; extern size_t ccd_points_on_sphere_len; /** Returns sign of value. */ _ccd_inline int ccdSign(ccd_real_t val); /** Returns true if val is zero. **/ _ccd_inline int ccdIsZero(ccd_real_t val); /** Returns true if a and b equal. **/ _ccd_inline int ccdEq(ccd_real_t a, ccd_real_t b); #define CCD_VEC3_STATIC(x, y, z) \ { { (x), (y), (z) } } #define CCD_VEC3(name, x, y, z) \ ccd_vec3_t name = CCD_VEC3_STATIC((x), (y), (z)) _ccd_inline ccd_real_t ccdVec3X(const ccd_vec3_t *v); _ccd_inline ccd_real_t ccdVec3Y(const ccd_vec3_t *v); _ccd_inline ccd_real_t ccdVec3Z(const ccd_vec3_t *v); /** * Returns true if a and b equal. */ _ccd_inline int ccdVec3Eq(const ccd_vec3_t *a, const ccd_vec3_t *b); /** * Returns squared length of vector. */ _ccd_inline ccd_real_t ccdVec3Len2(const ccd_vec3_t *v); /** * Returns distance between a and b. */ _ccd_inline ccd_real_t ccdVec3Dist2(const ccd_vec3_t *a, const ccd_vec3_t *b); _ccd_inline void ccdVec3Set(ccd_vec3_t *v, ccd_real_t x, ccd_real_t y, ccd_real_t z); /** * v = w */ _ccd_inline void ccdVec3Copy(ccd_vec3_t *v, const ccd_vec3_t *w); /** * Substracts coordinates of vector w from vector v. v = v - w */ _ccd_inline void ccdVec3Sub(ccd_vec3_t *v, const ccd_vec3_t *w); /** * Adds coordinates of vector w to vector v. v = v + w */ _ccd_inline void ccdVec3Add(ccd_vec3_t *v, const ccd_vec3_t *w); /** * d = v - w */ _ccd_inline void ccdVec3Sub2(ccd_vec3_t *d, const ccd_vec3_t *v, const ccd_vec3_t *w); /** * d = d * k; */ _ccd_inline void ccdVec3Scale(ccd_vec3_t *d, ccd_real_t k); /** * Normalizes given vector to unit length. */ _ccd_inline void ccdVec3Normalize(ccd_vec3_t *d); /** * Dot product of two vectors. */ _ccd_inline ccd_real_t ccdVec3Dot(const ccd_vec3_t *a, const ccd_vec3_t *b); /** * Cross product: d = a x b. */ _ccd_inline void ccdVec3Cross(ccd_vec3_t *d, const ccd_vec3_t *a, const ccd_vec3_t *b); /** * Returns distance2 of point P to segment ab. * If witness is non-NULL it is filled with coordinates of point from which * was computaed distance to point P. */ ccd_real_t ccdVec3PointSegmentDist2(const ccd_vec3_t *P, const ccd_vec3_t *a, const ccd_vec3_t *b, ccd_vec3_t *witness); /** * Returns distance2 of point P from triangle formed by triplet a, b, c. * If witness vector is provided it is filled with coordinates of point * from which was computed distance to point P. */ ccd_real_t ccdVec3PointTriDist2(const ccd_vec3_t *P, const ccd_vec3_t *a, const ccd_vec3_t *b, const ccd_vec3_t *c, ccd_vec3_t *witness); /**** INLINES ****/ _ccd_inline int ccdSign(ccd_real_t val) { if (ccdIsZero(val)){ return 0; }else if (val < CCD_ZERO){ return -1; } return 1; } _ccd_inline int ccdIsZero(ccd_real_t val) { return CCD_FABS(val) < CCD_EPS; } _ccd_inline int ccdEq(ccd_real_t _a, ccd_real_t _b) { ccd_real_t ab; ccd_real_t a, b; ab = CCD_FABS(_a - _b); if (CCD_FABS(ab) < CCD_EPS) return 1; a = CCD_FABS(_a); b = CCD_FABS(_b); if (b > a){ return ab < CCD_EPS * b; }else{ return ab < CCD_EPS * a; } } _ccd_inline ccd_real_t ccdVec3X(const ccd_vec3_t *v) { return v->v[0]; } _ccd_inline ccd_real_t ccdVec3Y(const ccd_vec3_t *v) { return v->v[1]; } _ccd_inline ccd_real_t ccdVec3Z(const ccd_vec3_t *v) { return v->v[2]; } _ccd_inline int ccdVec3Eq(const ccd_vec3_t *a, const ccd_vec3_t *b) { return ccdEq(ccdVec3X(a), ccdVec3X(b)) && ccdEq(ccdVec3Y(a), ccdVec3Y(b)) && ccdEq(ccdVec3Z(a), ccdVec3Z(b)); } _ccd_inline ccd_real_t ccdVec3Len2(const ccd_vec3_t *v) { return ccdVec3Dot(v, v); } _ccd_inline ccd_real_t ccdVec3Dist2(const ccd_vec3_t *a, const ccd_vec3_t *b) { ccd_vec3_t ab; ccdVec3Sub2(&ab, a, b); return ccdVec3Len2(&ab); } _ccd_inline void ccdVec3Set(ccd_vec3_t *v, ccd_real_t x, ccd_real_t y, ccd_real_t z) { v->v[0] = x; v->v[1] = y; v->v[2] = z; } _ccd_inline void ccdVec3Copy(ccd_vec3_t *v, const ccd_vec3_t *w) { *v = *w; } _ccd_inline void ccdVec3Sub(ccd_vec3_t *v, const ccd_vec3_t *w) { v->v[0] -= w->v[0]; v->v[1] -= w->v[1]; v->v[2] -= w->v[2]; } _ccd_inline void ccdVec3Sub2(ccd_vec3_t *d, const ccd_vec3_t *v, const ccd_vec3_t *w) { d->v[0] = v->v[0] - w->v[0]; d->v[1] = v->v[1] - w->v[1]; d->v[2] = v->v[2] - w->v[2]; } _ccd_inline void ccdVec3Add(ccd_vec3_t *v, const ccd_vec3_t *w) { v->v[0] += w->v[0]; v->v[1] += w->v[1]; v->v[2] += w->v[2]; } _ccd_inline void ccdVec3Scale(ccd_vec3_t *d, ccd_real_t k) { d->v[0] *= k; d->v[1] *= k; d->v[2] *= k; } _ccd_inline void ccdVec3Normalize(ccd_vec3_t *d) { ccd_real_t k = CCD_ONE / CCD_SQRT(ccdVec3Len2(d)); ccdVec3Scale(d, k); } _ccd_inline ccd_real_t ccdVec3Dot(const ccd_vec3_t *a, const ccd_vec3_t *b) { ccd_real_t dot; dot = a->v[0] * b->v[0]; dot += a->v[1] * b->v[1]; dot += a->v[2] * b->v[2]; return dot; } _ccd_inline void ccdVec3Cross(ccd_vec3_t *d, const ccd_vec3_t *a, const ccd_vec3_t *b) { d->v[0] = (a->v[1] * b->v[2]) - (a->v[2] * b->v[1]); d->v[1] = (a->v[2] * b->v[0]) - (a->v[0] * b->v[2]); d->v[2] = (a->v[0] * b->v[1]) - (a->v[1] * b->v[0]); } #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_VEC3_H__ */ ode-0.14/libccd/src/mpr.c0000644000000000000000000004356512635011627013674 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010,2011 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif /** Finds origin (center) of Minkowski difference (actually it can be any * interior point of Minkowski difference. */ _ccd_inline void findOrigin(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_support_t *center); /** Discovers initial portal - that is tetrahedron that intersects with * origin ray (ray from center of Minkowski diff to (0,0,0). * * Returns -1 if already recognized that origin is outside Minkowski * portal. * Returns 1 if origin lies on v1 of simplex (only v0 and v1 are present * in simplex). * Returns 2 if origin lies on v0-v1 segment. * Returns 0 if portal was built. */ static int discoverPortal(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal); /** Expands portal towards origin and determine if objects intersect. * Already established portal must be given as argument. * If intersection is found 0 is returned, -1 otherwise */ static int refinePortal(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal); /** Finds penetration info by expanding provided portal. */ static void findPenetr(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); /** Finds penetration info if origin lies on portal's v1 */ static void findPenetrTouch(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); /** Find penetration info if origin lies on portal's segment v0-v1 */ static void findPenetrSegment(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos); /** Finds position vector from fully established portal */ static void findPos(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_simplex_t *portal, ccd_vec3_t *pos); /** Extends portal with new support point. * Portal must have face v1-v2-v3 arranged to face outside portal. */ _ccd_inline void expandPortal(ccd_simplex_t *portal, const ccd_support_t *v4); /** Fill dir with direction outside portal. Portal's v1-v2-v3 face must be * arranged in correct order! */ _ccd_inline void portalDir(const ccd_simplex_t *portal, ccd_vec3_t *dir); /** Returns true if portal encapsules origin (0,0,0), dir is direction of * v1-v2-v3 face. */ _ccd_inline int portalEncapsulesOrigin(const ccd_simplex_t *portal, const ccd_vec3_t *dir); /** Returns true if portal with new point v4 would reach specified * tolerance (i.e. returns true if portal can _not_ significantly expand * within Minkowski difference). * * v4 is candidate for new point in portal, dir is direction in which v4 * was obtained. */ _ccd_inline int portalReachTolerance(const ccd_simplex_t *portal, const ccd_support_t *v4, const ccd_vec3_t *dir, const ccd_t *ccd); /** Returns true if portal expanded by new point v4 could possibly contain * origin, dir is direction in which v4 was obtained. */ _ccd_inline int portalCanEncapsuleOrigin(const ccd_simplex_t *portal, const ccd_support_t *v4, const ccd_vec3_t *dir); int ccdMPRIntersect(const void *obj1, const void *obj2, const ccd_t *ccd) { ccd_simplex_t portal; int res; // Phase 1: Portal discovery - find portal that intersects with origin // ray (ray from center of Minkowski diff to origin of coordinates) res = discoverPortal(obj1, obj2, ccd, &portal); if (res < 0) return 0; if (res > 0) return 1; // Phase 2: Portal refinement res = refinePortal(obj1, obj2, ccd, &portal); return (res == 0 ? 1 : 0); } int ccdMPRPenetration(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) { ccd_simplex_t portal; int res; // Phase 1: Portal discovery res = discoverPortal(obj1, obj2, ccd, &portal); if (res < 0){ // Origin isn't inside portal - no collision. return -1; }else if (res == 1){ // Touching contact on portal's v1. findPenetrTouch(obj1, obj2, ccd, &portal, depth, dir, pos); }else if (res == 2){ // Origin lies on v0-v1 segment. findPenetrSegment(obj1, obj2, ccd, &portal, depth, dir, pos); }else if (res == 0){ // Phase 2: Portal refinement res = refinePortal(obj1, obj2, ccd, &portal); if (res < 0) return -1; // Phase 3. Penetration info findPenetr(obj1, obj2, ccd, &portal, depth, dir, pos); } return 0; } _ccd_inline void findOrigin(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_support_t *center) { ccd->center1(obj1, ¢er->v1); ccd->center2(obj2, ¢er->v2); ccdVec3Sub2(¢er->v, ¢er->v1, ¢er->v2); } static int discoverPortal(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal) { ccd_vec3_t dir, va, vb; ccd_real_t dot; int cont; // vertex 0 is center of portal findOrigin(obj1, obj2, ccd, ccdSimplexPointW(portal, 0)); ccdSimplexSetSize(portal, 1); if (ccdVec3Eq(&ccdSimplexPoint(portal, 0)->v, ccd_vec3_origin)){ // Portal's center lies on origin (0,0,0) => we know that objects // intersect but we would need to know penetration info. // So move center little bit... ccdVec3Set(&va, CCD_EPS * CCD_REAL(10.), CCD_ZERO, CCD_ZERO); ccdVec3Add(&ccdSimplexPointW(portal, 0)->v, &va); } // vertex 1 = support in direction of origin ccdVec3Copy(&dir, &ccdSimplexPoint(portal, 0)->v); ccdVec3Scale(&dir, CCD_REAL(-1.)); ccdVec3Normalize(&dir); __ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 1)); ccdSimplexSetSize(portal, 2); // test if origin isn't outside of v1 dot = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, &dir); if (ccdIsZero(dot) || dot < CCD_ZERO) return -1; // vertex 2 ccdVec3Cross(&dir, &ccdSimplexPoint(portal, 0)->v, &ccdSimplexPoint(portal, 1)->v); if (ccdIsZero(ccdVec3Len2(&dir))){ if (ccdVec3Eq(&ccdSimplexPoint(portal, 1)->v, ccd_vec3_origin)){ // origin lies on v1 return 1; }else{ // origin lies on v0-v1 segment return 2; } } ccdVec3Normalize(&dir); __ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 2)); dot = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, &dir); if (ccdIsZero(dot) || dot < CCD_ZERO) return -1; ccdSimplexSetSize(portal, 3); // vertex 3 direction ccdVec3Sub2(&va, &ccdSimplexPoint(portal, 1)->v, &ccdSimplexPoint(portal, 0)->v); ccdVec3Sub2(&vb, &ccdSimplexPoint(portal, 2)->v, &ccdSimplexPoint(portal, 0)->v); ccdVec3Cross(&dir, &va, &vb); ccdVec3Normalize(&dir); // it is better to form portal faces to be oriented "outside" origin dot = ccdVec3Dot(&dir, &ccdSimplexPoint(portal, 0)->v); if (dot > CCD_ZERO){ ccdSimplexSwap(portal, 1, 2); ccdVec3Scale(&dir, CCD_REAL(-1.)); } while (ccdSimplexSize(portal) < 4){ __ccdSupport(obj1, obj2, &dir, ccd, ccdSimplexPointW(portal, 3)); dot = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, &dir); if (ccdIsZero(dot) || dot < CCD_ZERO) return -1; cont = 0; // test if origin is outside (v1, v0, v3) - set v2 as v3 and // continue ccdVec3Cross(&va, &ccdSimplexPoint(portal, 1)->v, &ccdSimplexPoint(portal, 3)->v); dot = ccdVec3Dot(&va, &ccdSimplexPoint(portal, 0)->v); if (dot < CCD_ZERO && !ccdIsZero(dot)){ ccdSimplexSet(portal, 2, ccdSimplexPoint(portal, 3)); cont = 1; } if (!cont){ // test if origin is outside (v3, v0, v2) - set v1 as v3 and // continue ccdVec3Cross(&va, &ccdSimplexPoint(portal, 3)->v, &ccdSimplexPoint(portal, 2)->v); dot = ccdVec3Dot(&va, &ccdSimplexPoint(portal, 0)->v); if (dot < CCD_ZERO && !ccdIsZero(dot)){ ccdSimplexSet(portal, 1, ccdSimplexPoint(portal, 3)); cont = 1; } } if (cont){ ccdVec3Sub2(&va, &ccdSimplexPoint(portal, 1)->v, &ccdSimplexPoint(portal, 0)->v); ccdVec3Sub2(&vb, &ccdSimplexPoint(portal, 2)->v, &ccdSimplexPoint(portal, 0)->v); ccdVec3Cross(&dir, &va, &vb); ccdVec3Normalize(&dir); }else{ ccdSimplexSetSize(portal, 4); } } return 0; } static int refinePortal(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal) { ccd_vec3_t dir; ccd_support_t v4; while (1){ // compute direction outside the portal (from v0 throught v1,v2,v3 // face) portalDir(portal, &dir); // test if origin is inside the portal if (portalEncapsulesOrigin(portal, &dir)) return 0; // get next support point __ccdSupport(obj1, obj2, &dir, ccd, &v4); // test if v4 can expand portal to contain origin and if portal // expanding doesn't reach given tolerance if (!portalCanEncapsuleOrigin(portal, &v4, &dir) || portalReachTolerance(portal, &v4, &dir, ccd)){ return -1; } // v1-v2-v3 triangle must be rearranged to face outside Minkowski // difference (direction from v0). expandPortal(portal, &v4); } return -1; } static void findPenetr(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal, ccd_real_t *depth, ccd_vec3_t *pdir, ccd_vec3_t *pos) { ccd_vec3_t dir; ccd_support_t v4; unsigned long iterations; iterations = 0UL; while (1){ // compute portal direction and obtain next support point portalDir(portal, &dir); __ccdSupport(obj1, obj2, &dir, ccd, &v4); // reached tolerance -> find penetration info if (portalReachTolerance(portal, &v4, &dir, ccd) || iterations > ccd->max_iterations){ *depth = ccdVec3PointTriDist2(ccd_vec3_origin, &ccdSimplexPoint(portal, 1)->v, &ccdSimplexPoint(portal, 2)->v, &ccdSimplexPoint(portal, 3)->v, pdir); *depth = CCD_SQRT(*depth); ccdVec3Normalize(pdir); // barycentric coordinates: findPos(obj1, obj2, ccd, portal, pos); return; } expandPortal(portal, &v4); iterations++; } } static void findPenetrTouch(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) { // Touching contact on portal's v1 - so depth is zero and direction // is unimportant and pos can be guessed *depth = CCD_REAL(0.); ccdVec3Copy(dir, ccd_vec3_origin); ccdVec3Copy(pos, &ccdSimplexPoint(portal, 1)->v1); ccdVec3Add(pos, &ccdSimplexPoint(portal, 1)->v2); ccdVec3Scale(pos, 0.5); } static void findPenetrSegment(const void *obj1, const void *obj2, const ccd_t *ccd, ccd_simplex_t *portal, ccd_real_t *depth, ccd_vec3_t *dir, ccd_vec3_t *pos) { /* ccd_vec3_t vec; ccd_real_t k; */ // Origin lies on v0-v1 segment. // Depth is distance to v1, direction also and position must be // computed ccdVec3Copy(pos, &ccdSimplexPoint(portal, 1)->v1); ccdVec3Add(pos, &ccdSimplexPoint(portal, 1)->v2); ccdVec3Scale(pos, CCD_REAL(0.5)); /* ccdVec3Sub2(&vec, &ccdSimplexPoint(portal, 1)->v, &ccdSimplexPoint(portal, 0)->v); k = CCD_SQRT(ccdVec3Len2(&ccdSimplexPoint(portal, 0)->v)); k /= CCD_SQRT(ccdVec3Len2(&vec)); ccdVec3Scale(&vec, -k); ccdVec3Add(pos, &vec); */ ccdVec3Copy(dir, &ccdSimplexPoint(portal, 1)->v); *depth = CCD_SQRT(ccdVec3Len2(dir)); ccdVec3Normalize(dir); } static void findPos(const void *obj1, const void *obj2, const ccd_t *ccd, const ccd_simplex_t *portal, ccd_vec3_t *pos) { ccd_vec3_t dir; size_t i; ccd_real_t b[4], sum, inv; ccd_vec3_t vec, p1, p2; portalDir(portal, &dir); // use barycentric coordinates of tetrahedron to find origin ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 1)->v, &ccdSimplexPoint(portal, 2)->v); b[0] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 3)->v); ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 3)->v, &ccdSimplexPoint(portal, 2)->v); b[1] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 0)->v); ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 0)->v, &ccdSimplexPoint(portal, 1)->v); b[2] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 3)->v); ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 2)->v, &ccdSimplexPoint(portal, 1)->v); b[3] = ccdVec3Dot(&vec, &ccdSimplexPoint(portal, 0)->v); sum = b[0] + b[1] + b[2] + b[3]; if (ccdIsZero(sum) || sum < CCD_ZERO){ b[0] = CCD_REAL(0.); ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 2)->v, &ccdSimplexPoint(portal, 3)->v); b[1] = ccdVec3Dot(&vec, &dir); ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 3)->v, &ccdSimplexPoint(portal, 1)->v); b[2] = ccdVec3Dot(&vec, &dir); ccdVec3Cross(&vec, &ccdSimplexPoint(portal, 1)->v, &ccdSimplexPoint(portal, 2)->v); b[3] = ccdVec3Dot(&vec, &dir); sum = b[1] + b[2] + b[3]; } inv = CCD_REAL(1.) / sum; ccdVec3Copy(&p1, ccd_vec3_origin); ccdVec3Copy(&p2, ccd_vec3_origin); for (i = 0; i < 4; i++){ ccdVec3Copy(&vec, &ccdSimplexPoint(portal, i)->v1); ccdVec3Scale(&vec, b[i]); ccdVec3Add(&p1, &vec); ccdVec3Copy(&vec, &ccdSimplexPoint(portal, i)->v2); ccdVec3Scale(&vec, b[i]); ccdVec3Add(&p2, &vec); } ccdVec3Scale(&p1, inv); ccdVec3Scale(&p2, inv); ccdVec3Copy(pos, &p1); ccdVec3Add(pos, &p2); ccdVec3Scale(pos, 0.5); } _ccd_inline void expandPortal(ccd_simplex_t *portal, const ccd_support_t *v4) { ccd_real_t dot; ccd_vec3_t v4v0; ccdVec3Cross(&v4v0, &v4->v, &ccdSimplexPoint(portal, 0)->v); dot = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, &v4v0); if (dot > CCD_ZERO){ dot = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, &v4v0); if (dot > CCD_ZERO){ ccdSimplexSet(portal, 1, v4); }else{ ccdSimplexSet(portal, 3, v4); } }else{ dot = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, &v4v0); if (dot > CCD_ZERO){ ccdSimplexSet(portal, 2, v4); }else{ ccdSimplexSet(portal, 1, v4); } } } _ccd_inline void portalDir(const ccd_simplex_t *portal, ccd_vec3_t *dir) { ccd_vec3_t v2v1, v3v1; ccdVec3Sub2(&v2v1, &ccdSimplexPoint(portal, 2)->v, &ccdSimplexPoint(portal, 1)->v); ccdVec3Sub2(&v3v1, &ccdSimplexPoint(portal, 3)->v, &ccdSimplexPoint(portal, 1)->v); ccdVec3Cross(dir, &v2v1, &v3v1); ccdVec3Normalize(dir); } _ccd_inline int portalEncapsulesOrigin(const ccd_simplex_t *portal, const ccd_vec3_t *dir) { ccd_real_t dot; dot = ccdVec3Dot(dir, &ccdSimplexPoint(portal, 1)->v); return ccdIsZero(dot) || dot > CCD_ZERO; } _ccd_inline int portalReachTolerance(const ccd_simplex_t *portal, const ccd_support_t *v4, const ccd_vec3_t *dir, const ccd_t *ccd) { ccd_real_t dv1, dv2, dv3, dv4; ccd_real_t dot1, dot2, dot3; // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4} dv1 = ccdVec3Dot(&ccdSimplexPoint(portal, 1)->v, dir); dv2 = ccdVec3Dot(&ccdSimplexPoint(portal, 2)->v, dir); dv3 = ccdVec3Dot(&ccdSimplexPoint(portal, 3)->v, dir); dv4 = ccdVec3Dot(&v4->v, dir); dot1 = dv4 - dv1; dot2 = dv4 - dv2; dot3 = dv4 - dv3; dot1 = CCD_FMIN(dot1, dot2); dot1 = CCD_FMIN(dot1, dot3); return ccdEq(dot1, ccd->mpr_tolerance) || dot1 < ccd->mpr_tolerance; } _ccd_inline int portalCanEncapsuleOrigin(const ccd_simplex_t *portal, const ccd_support_t *v4, const ccd_vec3_t *dir) { ccd_real_t dot; dot = ccdVec3Dot(&v4->v, dir); return ccdIsZero(dot) || dot > CCD_ZERO; } ode-0.14/libccd/src/polytope.c0000644000000000000000000001615312635011627014742 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif _ccd_inline void _ccdPtNearestUpdate(ccd_pt_t *pt, ccd_pt_el_t *el) { if (ccdEq(pt->nearest_dist, el->dist)){ if (el->type < pt->nearest_type){ pt->nearest = el; pt->nearest_dist = el->dist; pt->nearest_type = el->type; } }else if (el->dist < pt->nearest_dist){ pt->nearest = el; pt->nearest_dist = el->dist; pt->nearest_type = el->type; } } static void _ccdPtNearestRenew(ccd_pt_t *pt) { ccd_pt_vertex_t *v; ccd_pt_edge_t *e; ccd_pt_face_t *f; pt->nearest_dist = CCD_REAL_MAX; pt->nearest_type = 3; pt->nearest = NULL; ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)v); } ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){ _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)e); } ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){ _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)f); } } void ccdPtInit(ccd_pt_t *pt) { ccdListInit(&pt->vertices); ccdListInit(&pt->edges); ccdListInit(&pt->faces); pt->nearest = NULL; pt->nearest_dist = CCD_REAL_MAX; pt->nearest_type = 3; } void ccdPtDestroy(ccd_pt_t *pt) { ccd_pt_face_t *f, *f2; ccd_pt_edge_t *e, *e2; ccd_pt_vertex_t *v, *v2; // first delete all faces ccdListForEachEntrySafe(&pt->faces, f, ccd_pt_face_t, f2, ccd_pt_face_t, list){ ccdPtDelFace(pt, f); } // delete all edges ccdListForEachEntrySafe(&pt->edges, e, ccd_pt_edge_t, e2, ccd_pt_edge_t, list){ ccdPtDelEdge(pt, e); } // delete all vertices ccdListForEachEntrySafe(&pt->vertices, v, ccd_pt_vertex_t, v2, ccd_pt_vertex_t, list){ ccdPtDelVertex(pt, v); } } ccd_pt_vertex_t *ccdPtAddVertex(ccd_pt_t *pt, const ccd_support_t *v) { ccd_pt_vertex_t *vert; vert = CCD_ALLOC(ccd_pt_vertex_t); vert->type = CCD_PT_VERTEX; ccdSupportCopy(&vert->v, v); vert->dist = ccdVec3Len2(&vert->v.v); ccdVec3Copy(&vert->witness, &vert->v.v); ccdListInit(&vert->edges); // add vertex to list ccdListAppend(&pt->vertices, &vert->list); // update position in .nearest array _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)vert); return vert; } ccd_pt_edge_t *ccdPtAddEdge(ccd_pt_t *pt, ccd_pt_vertex_t *v1, ccd_pt_vertex_t *v2) { const ccd_vec3_t *a, *b; ccd_pt_edge_t *edge; edge = CCD_ALLOC(ccd_pt_edge_t); edge->type = CCD_PT_EDGE; edge->vertex[0] = v1; edge->vertex[1] = v2; edge->faces[0] = edge->faces[1] = NULL; a = &edge->vertex[0]->v.v; b = &edge->vertex[1]->v.v; edge->dist = ccdVec3PointSegmentDist2(ccd_vec3_origin, a, b, &edge->witness); ccdListAppend(&edge->vertex[0]->edges, &edge->vertex_list[0]); ccdListAppend(&edge->vertex[1]->edges, &edge->vertex_list[1]); ccdListAppend(&pt->edges, &edge->list); // update position in .nearest array _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)edge); return edge; } ccd_pt_face_t *ccdPtAddFace(ccd_pt_t *pt, ccd_pt_edge_t *e1, ccd_pt_edge_t *e2, ccd_pt_edge_t *e3) { const ccd_vec3_t *a, *b, *c; ccd_pt_face_t *face; ccd_pt_edge_t *e; size_t i; face = CCD_ALLOC(ccd_pt_face_t); face->type = CCD_PT_FACE; face->edge[0] = e1; face->edge[1] = e2; face->edge[2] = e3; // obtain triplet of vertices a = &face->edge[0]->vertex[0]->v.v; b = &face->edge[0]->vertex[1]->v.v; e = face->edge[1]; if (e->vertex[0] != face->edge[0]->vertex[0] && e->vertex[0] != face->edge[0]->vertex[1]){ c = &e->vertex[0]->v.v; }else{ c = &e->vertex[1]->v.v; } face->dist = ccdVec3PointTriDist2(ccd_vec3_origin, a, b, c, &face->witness); for (i = 0; i < 3; i++){ if (face->edge[i]->faces[0] == NULL){ face->edge[i]->faces[0] = face; }else{ face->edge[i]->faces[1] = face; } } ccdListAppend(&pt->faces, &face->list); // update position in .nearest array _ccdPtNearestUpdate(pt, (ccd_pt_el_t *)face); return face; } void ccdPtRecomputeDistances(ccd_pt_t *pt) { ccd_pt_vertex_t *v; ccd_pt_edge_t *e; ccd_pt_face_t *f; const ccd_vec3_t *a, *b, *c; ccd_real_t dist; ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ dist = ccdVec3Len2(&v->v.v); v->dist = dist; ccdVec3Copy(&v->witness, &v->v.v); } ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){ a = &e->vertex[0]->v.v; b = &e->vertex[1]->v.v; dist = ccdVec3PointSegmentDist2(ccd_vec3_origin, a, b, &e->witness); e->dist = dist; } ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){ // obtain triplet of vertices a = &f->edge[0]->vertex[0]->v.v; b = &f->edge[0]->vertex[1]->v.v; e = f->edge[1]; if (e->vertex[0] != f->edge[0]->vertex[0] && e->vertex[0] != f->edge[0]->vertex[1]){ c = &e->vertex[0]->v.v; }else{ c = &e->vertex[1]->v.v; } dist = ccdVec3PointTriDist2(ccd_vec3_origin, a, b, c, &f->witness); f->dist = dist; } } ccd_pt_el_t *ccdPtNearest(ccd_pt_t *pt) { if (!pt->nearest){ _ccdPtNearestRenew(pt); } return pt->nearest; } void ccdPtDumpSVT(ccd_pt_t *pt, const char *fn) { FILE *fout; fout = fopen(fn, "a"); if (fout == NULL) return; ccdPtDumpSVT2(pt, fout); fclose(fout); } void ccdPtDumpSVT2(ccd_pt_t *pt, FILE *fout) { ccd_pt_vertex_t *v, *a, *b, *c; ccd_pt_edge_t *e; ccd_pt_face_t *f; size_t i; fprintf(fout, "-----\n"); fprintf(fout, "Points:\n"); i = 0; ccdListForEachEntry(&pt->vertices, v, ccd_pt_vertex_t, list){ v->id = i++; fprintf(fout, "%lf %lf %lf\n", ccdVec3X(&v->v.v), ccdVec3Y(&v->v.v), ccdVec3Z(&v->v.v)); } fprintf(fout, "Edges:\n"); ccdListForEachEntry(&pt->edges, e, ccd_pt_edge_t, list){ fprintf(fout, "%d %d\n", e->vertex[0]->id, e->vertex[1]->id); } fprintf(fout, "Faces:\n"); ccdListForEachEntry(&pt->faces, f, ccd_pt_face_t, list){ a = f->edge[0]->vertex[0]; b = f->edge[0]->vertex[1]; c = f->edge[1]->vertex[0]; if (c == a || c == b){ c = f->edge[1]->vertex[1]; } fprintf(fout, "%d %d %d\n", a->id, b->id, c->id); } } ode-0.14/libccd/src/support.c0000644000000000000000000000172612635011627014603 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #include #ifdef HAVE_CONFIG_H #include "config.h" #endif void __ccdSupport(const void *obj1, const void *obj2, const ccd_vec3_t *_dir, const ccd_t *ccd, ccd_support_t *supp) { ccd_vec3_t dir; ccdVec3Copy(&dir, _dir); ccd->support1(obj1, &dir, &supp->v1); ccdVec3Scale(&dir, -CCD_ONE); ccd->support2(obj2, &dir, &supp->v2); ccdVec3Sub2(&supp->v, &supp->v1, &supp->v2); } ode-0.14/libccd/src/testsuites/0000775000000000000000000000000012635012023015122 5ustar rootrootode-0.14/libccd/src/testsuites/Makefile.am0000644000000000000000000000112312635011627017162 0ustar rootrootSUBDIRS = cu AM_CPPFLAGS = -I $(srcdir)/.. -I $(builddir)/.. -I $(srcdir)/cu LDADD = $(builddir)/cu/libcu.la $(builddir)/../libccd.la check_PROGRAMS = test bench bench2 test_SOURCES = main.c \ common.c common.h \ support.c support.h \ vec3.c vec3.h \ polytope.c polytope.h \ boxbox.c boxbox.h \ spheresphere.c spheresphere.h \ cylcyl.c cylcyl.h \ boxcyl.c boxcyl.h \ mpr_boxbox.c mpr_boxbox.h \ mpr_cylcyl.c mpr_cylcyl.h \ mpr_boxcyl.c mpr_boxcyl.h bench_SOURCES = bench.c \ support.c support.h bench2_SOURCES = bench2.c \ support.c support.h ode-0.14/libccd/src/testsuites/bench.c0000644000000000000000000001455012635011627016361 0ustar rootroot#define CU_ENABLE_TIMER #include #include #include #include #include "support.h" TEST_SUITES { TEST_SUITES_CLOSURE }; static int bench_num = 1; static size_t cycles = 10000; static void runBench(const void *o1, const void *o2, const ccd_t *ccd) { ccd_real_t depth; ccd_vec3_t dir, pos; int res; size_t i; const struct timespec *timer; cuTimerStart(); for (i = 0; i < cycles; i++){ res = ccdGJKPenetration(o1, o2, ccd, &depth, &dir, &pos); } timer = cuTimerStop(); fprintf(stdout, "%02d: %ld %ld\n", bench_num, (long)timer->tv_sec, (long)timer->tv_nsec); fflush(stdout); bench_num++; } static void boxbox(void) { fprintf(stdout, "%s:\n", __func__); ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); ccd_vec3_t axis; ccd_quat_t rot; box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 1.; box2.z = 1.5; bench_num = 1; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, 0., 0., 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0., 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 1., 1.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = 0.2; box2.y = 0.5; box2.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 0., 0.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -1.3, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); fprintf(stdout, "\n----\n\n"); } void cylcyl(void) { fprintf(stdout, "%s:\n", __func__); ccd_t ccd; CCD_CYL(cyl1); CCD_CYL(cyl2); ccd_vec3_t axis; cyl1.radius = 0.35; cyl1.height = 0.5; cyl2.radius = 0.5; cyl2.height = 1.; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0., 0., 0.); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, 0.567, 1.2, 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, -4.567, 1.2, 0.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); fprintf(stdout, "\n----\n\n"); } void boxcyl(void) { fprintf(stdout, "%s:\n", __func__); ccd_t ccd; CCD_BOX(box); CCD_CYL(cyl); ccd_vec3_t axis; box.x = 0.5; box.y = 1.; box.z = 1.5; cyl.radius = 0.4; cyl.height = 0.7; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&cyl.pos, .6, 0., 0.); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&cyl.pos, .6, 0.6, 0.); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, 0.67, 1.1, 0.12); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .6, 0., 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .9, 0.8, 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); fprintf(stdout, "\n----\n\n"); } int main(int argc, char *argv[]) { if (argc > 1){ cycles = atol(argv[1]); } fprintf(stdout, "Cycles: %u\n", cycles); fprintf(stdout, "\n"); boxbox(); cylcyl(); boxcyl(); return 0; } ode-0.14/libccd/src/testsuites/bench2.c0000644000000000000000000001505012635011627016437 0ustar rootroot#define CU_ENABLE_TIMER #include #include #include #include #include "support.h" TEST_SUITES { TEST_SUITES_CLOSURE }; static int bench_num = 1; static size_t cycles = 10000; static void runBench(const void *o1, const void *o2, const ccd_t *ccd) { ccd_real_t depth; ccd_vec3_t dir, pos; int res; size_t i; const struct timespec *timer; cuTimerStart(); for (i = 0; i < cycles; i++){ res = ccdMPRPenetration(o1, o2, ccd, &depth, &dir, &pos); } timer = cuTimerStop(); fprintf(stdout, "%02d: %ld %ld\n", bench_num, (long)timer->tv_sec, (long)timer->tv_nsec); fflush(stdout); bench_num++; } static void boxbox(void) { fprintf(stdout, "%s:\n", __func__); ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); ccd_vec3_t axis; ccd_quat_t rot; box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 1.; box2.z = 1.5; bench_num = 1; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, 0., 0., 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0., 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 1., 1.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); box1.x = box1.y = box1.z = 1.; box2.x = 0.2; box2.y = 0.5; box2.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 0., 0.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -1.3, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); runBench(&box1, &box2, &ccd); runBench(&box2, &box1, &ccd); fprintf(stdout, "\n----\n\n"); } void cylcyl(void) { fprintf(stdout, "%s:\n", __func__); ccd_t ccd; CCD_CYL(cyl1); CCD_CYL(cyl2); ccd_vec3_t axis; cyl1.radius = 0.35; cyl1.height = 0.5; cyl2.radius = 0.5; cyl2.height = 1.; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0., 0., 0.); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, 0.567, 1.2, 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); ccdVec3Set(&axis, -4.567, 1.2, 0.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); runBench(&cyl1, &cyl2, &ccd); runBench(&cyl2, &cyl1, &ccd); fprintf(stdout, "\n----\n\n"); } void boxcyl(void) { fprintf(stdout, "%s:\n", __func__); ccd_t ccd; CCD_BOX(box); CCD_CYL(cyl); ccd_vec3_t axis; box.x = 0.5; box.y = 1.; box.z = 1.5; cyl.radius = 0.4; cyl.height = 0.7; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&cyl.pos, .6, 0., 0.); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&cyl.pos, .6, 0.6, 0.); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, 0.67, 1.1, 0.12); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .6, 0., 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .9, 0.8, 0.5); runBench(&box, &cyl, &ccd); runBench(&cyl, &box, &ccd); fprintf(stdout, "\n----\n\n"); } int main(int argc, char *argv[]) { if (argc > 1){ cycles = atol(argv[1]); } fprintf(stdout, "Cycles: %u\n", cycles); fprintf(stdout, "\n"); boxbox(); cylcyl(); boxcyl(); return 0; } ode-0.14/libccd/src/testsuites/boxbox.c0000644000000000000000000002574312635011627016611 0ustar rootroot#include #include #include #include "support.h" #include #include #include "common.h" TEST(boxboxSetUp) { } TEST(boxboxTearDown) { } TEST(boxboxAlignedX) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; //ccd.max_iterations = 20; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, -5., 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[0] += 0.1; } box1.x = 0.1; box1.y = 0.2; box1.z = 0.1; box2.x = 0.2; box2.y = 0.1; box2.z = 0.2; ccdVec3Set(&box1.pos, -0.5, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[0] += 0.01; } box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, -5., -0.1, 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[0] += 0.1; } } TEST(boxboxAlignedY) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, 0., -5., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[1] += 0.1; } } TEST(boxboxAlignedZ) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, 0., 0., -5.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[2] += 0.1; } } TEST(boxboxRot) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; ccd_vec3_t axis; ccd_real_t angle; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, -5., 0.5, 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&box1, &box2, &ccd); if (i < 33 || i > 67){ assertFalse(res); }else if (i != 33 && i != 67){ assertTrue(res); } box1.pos.v[0] += 0.1; } box1.x = 1; box1.y = 1; box1.z = 1; box2.x = 1; box2.y = 1; box2.z = 1; ccdVec3Set(&box1.pos, -1.01, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); ccdVec3Set(&axis, 0., 1., 0.); angle = 0.; for (i = 0; i < 30; i++){ res = ccdGJKIntersect(&box1, &box2, &ccd); if (i != 0 && i != 10 && i != 20){ assertTrue(res); }else{ assertFalse(res); } angle += M_PI / 20.; ccdQuatSetAngleAxis(&box1.quat, angle, &axis); } } static void pConf(ccd_box_t *box1, ccd_box_t *box2, const ccd_vec3_t *v) { fprintf(stdout, "# box1.pos: [%lf %lf %lf]\n", ccdVec3X(&box1->pos), ccdVec3Y(&box1->pos), ccdVec3Z(&box1->pos)); fprintf(stdout, "# box1->quat: [%lf %lf %lf %lf]\n", box1->quat.q[0], box1->quat.q[1], box1->quat.q[2], box1->quat.q[3]); fprintf(stdout, "# box2->pos: [%lf %lf %lf]\n", ccdVec3X(&box2->pos), ccdVec3Y(&box2->pos), ccdVec3Z(&box2->pos)); fprintf(stdout, "# box2->quat: [%lf %lf %lf %lf]\n", box2->quat.q[0], box2->quat.q[1], box2->quat.q[2], box2->quat.q[3]); fprintf(stdout, "# sep: [%lf %lf %lf]\n", ccdVec3X(v), ccdVec3Y(v), ccdVec3Z(v)); fprintf(stdout, "#\n"); } TEST(boxboxSeparate) { ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; ccd_vec3_t sep, expsep, expsep2, axis; fprintf(stderr, "\n\n\n---- boxboxSeparate ----\n\n\n"); box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 1.; box2.z = 1.5; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccdVec3Set(&box1.pos, -0.5, 0.5, 0.2); res = ccdGJKIntersect(&box1, &box2, &ccd); assertTrue(res); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0.25, 0., 0.); assertTrue(ccdVec3Eq(&sep, &expsep)); ccdVec3Scale(&sep, -1.); ccdVec3Add(&box1.pos, &sep); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0., 0., 0.); assertTrue(ccdVec3Eq(&sep, &expsep)); ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0., 0., -0.25); assertTrue(ccdVec3Eq(&sep, &expsep)); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, 0., 0., 0.); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0., 0., 1.); ccdVec3Set(&expsep2, 0., 0., -1.); assertTrue(ccdVec3Eq(&sep, &expsep) || ccdVec3Eq(&sep, &expsep2)); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0., 0.); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); pConf(&box1, &box2, &sep); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); pConf(&box1, &box2, &sep); } #define TOSVT() \ svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos); \ ccdVec3Scale(&dir, depth); \ ccdVec3Add(&box2.pos, &dir); \ svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos) TEST(boxboxPenetration) { ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; ccd_vec3_t axis; ccd_quat_t rot; ccd_real_t depth; ccd_vec3_t dir, pos; fprintf(stderr, "\n\n\n---- boxboxPenetration ----\n\n\n"); box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 1.; box2.z = 1.5; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccdVec3Set(&box2.pos, 0.1, 0., 0.); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 1"); //TOSVT(); ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 2"); //TOSVT(); <<< box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, 0.1, 0., 0.1); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 3"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0., 0.); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 4"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 5"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&box2.pos, 0.1, 0., 0.); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 6"); //TOSVT(); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 1., 1.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 7"); //TOSVT(); <<< box1.x = box1.y = box1.z = 1.; box2.x = 0.2; box2.y = 0.5; box2.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 0., 0.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -1.3, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); res = ccdGJKPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 8"); //TOSVT(); } ode-0.14/libccd/src/testsuites/boxbox.h0000644000000000000000000000101212635011627016575 0ustar rootroot#ifndef BOX_BOX #define BOX_BOX #include TEST(boxboxSetUp); TEST(boxboxTearDown); TEST(boxboxAlignedX); TEST(boxboxAlignedY); TEST(boxboxAlignedZ); TEST(boxboxRot); TEST(boxboxSeparate); TEST(boxboxPenetration); TEST_SUITE(TSBoxBox) { TEST_ADD(boxboxSetUp), TEST_ADD(boxboxAlignedX), TEST_ADD(boxboxAlignedY), TEST_ADD(boxboxAlignedZ), TEST_ADD(boxboxRot), TEST_ADD(boxboxSeparate), TEST_ADD(boxboxPenetration), TEST_ADD(boxboxTearDown), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/boxcyl.c0000644000000000000000000001077012635011627016602 0ustar rootroot#include #include "common.h" #include #include "support.h" #define TOSVT() \ svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos); \ ccdVec3Scale(&dir, depth); \ ccdVec3Add(&cyl.pos, &dir); \ svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos) TEST(boxcylIntersect) { ccd_t ccd; CCD_BOX(box); CCD_CYL(cyl); int res; ccd_vec3_t axis; box.x = 0.5; box.y = 1.; box.z = 1.5; cyl.radius = 0.4; cyl.height = 0.7; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccdVec3Set(&cyl.pos, 0.1, 0., 0.); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&cyl.pos, .6, 0., 0.); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&cyl.pos, .6, 0.6, 0.); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, 0.67, 1.1, 0.12); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .6, 0., 0.5); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .9, 0.8, 0.5); res = ccdGJKIntersect(&box, &cyl, &ccd); assertTrue(res); } TEST(boxcylPenEPA) { ccd_t ccd; CCD_BOX(box); CCD_CYL(cyl); int res; ccd_vec3_t axis; ccd_real_t depth; ccd_vec3_t dir, pos; box.x = 0.5; box.y = 1.; box.z = 1.5; cyl.radius = 0.4; cyl.height = 0.7; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccdVec3Set(&cyl.pos, 0.1, 0., 0.); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 1"); //TOSVT(); ccdVec3Set(&cyl.pos, .6, 0., 0.); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 2"); //TOSVT(); <<< ccdVec3Set(&cyl.pos, .6, 0.6, 0.); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 3"); //TOSVT(); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 4"); //TOSVT(); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 5"); //TOSVT(); ccdVec3Set(&axis, 0.67, 1.1, 0.12); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 6"); //TOSVT(); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .6, 0., 0.5); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 7"); //TOSVT(); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .9, 0.8, 0.5); res = ccdGJKPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 8"); //TOSVT(); } ode-0.14/libccd/src/testsuites/boxcyl.h0000644000000000000000000000034112635011627016600 0ustar rootroot#ifndef TEST_BOXCYL_H #define TEST_BOXCYL_H #include TEST(boxcylIntersect); TEST(boxcylPenEPA); TEST_SUITE(TSBoxCyl){ TEST_ADD(boxcylIntersect), TEST_ADD(boxcylPenEPA), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/common.c0000644000000000000000000001234412635011627016571 0ustar rootroot#include "common.h" #include #include #include "support.h" static void svtCyl(ccd_cyl_t *c, FILE *out, const char *color, const char *name) { ccd_vec3_t v[32]; ccd_quat_t rot; ccd_vec3_t axis, vpos, vpos2; ccd_real_t angle, x, y; size_t i; ccdVec3Set(&axis, 0., 0., 1.); ccdVec3Set(&vpos, 0., c->radius, 0.); angle = 0.; for (i = 0; i < 16; i++){ angle = (ccd_real_t)i * (2. * M_PI / 16.); ccdQuatSetAngleAxis(&rot, angle, &axis); ccdVec3Copy(&vpos2, &vpos); ccdQuatRotVec(&vpos2, &rot); x = ccdVec3X(&vpos2); y = ccdVec3Y(&vpos2); ccdVec3Set(&v[i], x, y, c->height / 2.); ccdVec3Set(&v[i + 16], x, y, -c->height / 2.); } for (i = 0; i < 32; i++){ ccdQuatRotVec(&v[i], &c->quat); ccdVec3Add(&v[i], &c->pos); } fprintf(out, "-----\n"); if (name) fprintf(out, "Name: %s\n", name); fprintf(out, "Face color: %s\n", color); fprintf(out, "Edge color: %s\n", color); fprintf(out, "Point color: %s\n", color); fprintf(out, "Points:\n"); for (i = 0; i < 32; i++){ fprintf(out, "%lf %lf %lf\n", ccdVec3X(&v[i]), ccdVec3Y(&v[i]), ccdVec3Z(&v[i])); } fprintf(out, "Edges:\n"); fprintf(out, "0 16\n"); fprintf(out, "0 31\n"); for (i = 1; i < 16; i++){ fprintf(out, "0 %d\n", i); fprintf(out, "16 %d\n", i + 16); if (i != 0){ fprintf(out, "%d %d\n", i - 1, i); fprintf(out, "%d %d\n", i + 16 - 1, i + 16); } fprintf(out, "%d %d\n", i, i + 16); fprintf(out, "%d %d\n", i, i + 16 - 1); } fprintf(out, "Faces:\n"); for (i = 2; i < 16; i++){ fprintf(out, "0 %d %d\n", i, i -1); fprintf(out, "16 %d %d\n", i + 16, i + 16 -1); } fprintf(out, "0 16 31\n"); fprintf(out, "0 31 15\n"); for (i = 1; i < 16; i++){ fprintf(out, "%d %d %d\n", i, i + 16, i + 16 - 1); fprintf(out, "%d %d %d\n", i, i + 16 - 1, i - 1); } fprintf(out, "-----\n"); } static void svtBox(ccd_box_t *b, FILE *out, const char *color, const char *name) { ccd_vec3_t v[8]; size_t i; ccdVec3Set(&v[0], b->x * 0.5, b->y * 0.5, b->z * 0.5); ccdVec3Set(&v[1], b->x * 0.5, b->y * -0.5, b->z * 0.5); ccdVec3Set(&v[2], b->x * 0.5, b->y * 0.5, b->z * -0.5); ccdVec3Set(&v[3], b->x * 0.5, b->y * -0.5, b->z * -0.5); ccdVec3Set(&v[4], b->x * -0.5, b->y * 0.5, b->z * 0.5); ccdVec3Set(&v[5], b->x * -0.5, b->y * -0.5, b->z * 0.5); ccdVec3Set(&v[6], b->x * -0.5, b->y * 0.5, b->z * -0.5); ccdVec3Set(&v[7], b->x * -0.5, b->y * -0.5, b->z * -0.5); for (i = 0; i < 8; i++){ ccdQuatRotVec(&v[i], &b->quat); ccdVec3Add(&v[i], &b->pos); } fprintf(out, "-----\n"); if (name) fprintf(out, "Name: %s\n", name); fprintf(out, "Face color: %s\n", color); fprintf(out, "Edge color: %s\n", color); fprintf(out, "Point color: %s\n", color); fprintf(out, "Points:\n"); for (i = 0; i < 8; i++){ fprintf(out, "%lf %lf %lf\n", ccdVec3X(&v[i]), ccdVec3Y(&v[i]), ccdVec3Z(&v[i])); } fprintf(out, "Edges:\n"); fprintf(out, "0 1\n 0 2\n2 3\n3 1\n1 2\n6 2\n1 7\n1 5\n"); fprintf(out, "5 0\n0 4\n4 2\n6 4\n6 5\n5 7\n6 7\n7 2\n7 3\n4 5\n"); fprintf(out, "Faces:\n"); fprintf(out, "0 2 1\n1 2 3\n6 2 4\n4 2 0\n4 0 5\n5 0 1\n"); fprintf(out, "5 1 7\n7 1 3\n6 4 5\n6 5 7\n2 6 7\n2 7 3\n"); fprintf(out, "-----\n"); } void svtObj(void *_o, FILE *out, const char *color, const char *name) { ccd_obj_t *o = (ccd_obj_t *)_o; if (o->type == CCD_OBJ_CYL){ svtCyl((ccd_cyl_t *)o, out, color, name); }else if (o->type == CCD_OBJ_BOX){ svtBox((ccd_box_t *)o, out, color, name); } } void svtObjPen(void *o1, void *o2, FILE *out, const char *name, ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos) { ccd_vec3_t sep; char oname[500]; ccdVec3Copy(&sep, dir); ccdVec3Scale(&sep, depth); ccdVec3Add(&sep, pos); fprintf(out, "------\n"); if (name) fprintf(out, "Name: %s\n", name); fprintf(out, "Point color: 0.1 0.1 0.9\n"); fprintf(out, "Points:\n%lf %lf %lf\n", ccdVec3X(pos), ccdVec3Y(pos), ccdVec3Z(pos)); fprintf(out, "------\n"); fprintf(out, "Point color: 0.1 0.9 0.9\n"); fprintf(out, "Edge color: 0.1 0.9 0.9\n"); fprintf(out, "Points:\n%lf %lf %lf\n", ccdVec3X(pos), ccdVec3Y(pos), ccdVec3Z(pos)); fprintf(out, "%lf %lf %lf\n", ccdVec3X(&sep), ccdVec3Y(&sep), ccdVec3Z(&sep)); fprintf(out, "Edges: 0 1\n"); oname[0] = 0x0; if (name) sprintf(oname, "%s o1", name); svtObj(o1, out, "0.9 0.1 0.1", oname); oname[0] = 0x0; if (name) sprintf(oname, "%s o1", name); svtObj(o2, out, "0.1 0.9 0.1", oname); } void recPen(ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos, FILE *out, const char *note) { if (!note) note = ""; fprintf(out, "# %s: depth: %lf\n", note, depth); fprintf(out, "# %s: dir: [%lf %lf %lf]\n", note, ccdVec3X(dir), ccdVec3Y(dir), ccdVec3Z(dir)); fprintf(out, "# %s: pos: [%lf %lf %lf]\n", note, ccdVec3X(pos), ccdVec3Y(pos), ccdVec3Z(pos)); fprintf(out, "#\n"); } ode-0.14/libccd/src/testsuites/common.h0000644000000000000000000000066612635011627016602 0ustar rootroot#ifndef TEST_COMMON #define TEST_COMMON #include #include void svtObj(void *o, FILE *out, const char *color, const char *name); void svtObjPen(void *o1, void *o2, FILE *out, const char *name, ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos); void recPen(ccd_real_t depth, const ccd_vec3_t *dir, const ccd_vec3_t *pos, FILE *out, const char *note); #endif ode-0.14/libccd/src/testsuites/cu/0000775000000000000000000000000012635012023015531 5ustar rootrootode-0.14/libccd/src/testsuites/cu/COPYING0000644000000000000000000010451312635011627016577 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ode-0.14/libccd/src/testsuites/cu/COPYING.LESSER0000644000000000000000000001672712635011627017604 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ode-0.14/libccd/src/testsuites/cu/Makefile.am0000644000000000000000000000013512635011627017573 0ustar rootrootAM_CPPFLAGS = -DCU_ENABLE_TIMER check_LTLIBRARIES = libcu.la libcu_la_SOURCES = cu.c cu.h ode-0.14/libccd/src/testsuites/cu/check-regressions0000644000000000000000000003162512635011627021110 0ustar rootroot#!/usr/bin/python ## # CU - C unit testing framework # --------------------------------- # Copyright (c)2007,2008 Daniel Fiser # # # This file is part of CU. # # CU is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 3 of # the License, or (at your option) any later version. # # CU is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # from subprocess import Popen, PIPE import os import re import sys import math from getopt import gnu_getopt, GetoptError EPS = 0.6 BASE_DIR = "." MAX_DIFF_LINES = 20 EXACT = False PROGRESS_ON = True MSG_BASE = "" class Hunk: """ This class represents one hunk from diff. """ def __init__(self): self.added = [] self.deleted = [] self.lines = [] # to identify lines with floating point numbers self.re_is_num = re.compile("^.*[0-9].*$") # pattern to match floating point number self.num_pattern = r"-?(?:(?:[0-9]+(?:\.[0-9]*)?)|(?:\.[0-9]+))(?:[eE]-?[0-9]+)?" self.re_num = re.compile(self.num_pattern) def numLines(self): return len(self.lines) def numLinesAdded(self): return len(self.added) def numLinesDeleted(self): return len(self.deleted) def addLineAdded(self, line): self.added.append(line) def addLineDeleted(self, line): self.deleted.append(line) def addLine(self, line): self.lines.append(line) def getLines(self): return self.lines def getLinesAdded(self): return self.added def getLinesDeleted(self): return self.deleted def __eq(self, num1, num2): """ Returns True if num1 equals to num2 with respect to EPS (defined above) """ return math.fabs(num1 - num2) < EPS def checkFloats(self): """ This method try to check if only difference between added and deleted lines of this hunk is different precission of floating point numbers """ # If number of added and deleted lines differs, then there is more # differences that precission of floating point numbers if self.numLinesAdded() != self.numLinesDeleted(): return False for i in xrange(0, self.numLinesAdded()): # if any line does not contain number - return False because # there must be more differences than in numbers if not self.re_is_num.match(self.added[i]) \ or not self.re_is_num.match(self.deleted[i]): return False line1 = self.added[i] line2 = self.deleted[i] # Extract all floating point numbers from each line nums1 = self.re_num.findall(line1) nums2 = self.re_num.findall(line2) # and remove all empty strings nums1 = filter(lambda x: len(x) > 0, nums1) nums2 = filter(lambda x: len(x) > 0, nums2) # if length of list nums1 does not equal to length of nums2 # return False if len(nums1) != len(nums2): return False # iterate trough all numbers for j in xrange(0, len(nums1)): # if numbers do not equal to each other return False if not self.__eq(float(nums1[j]), float(nums2[j])): return False # compare the rest of lines line1 = self.re_num.sub("", line1) line2 = self.re_num.sub("", line2) if line1 != line2: return False # If it does not fail anywhere, added and deleted lines must be # same return True class Diff: """ Represents whole diff. """ def __init__(self): self.hunks = [] self.lines = 0 self.omitted_lines = 0 def addHunk(self, hunk): self.hunks.append(hunk) self.lines += hunk.numLines() def numLines(self): return self.lines def numOmittedLines(self): return self.omitted_lines def getHunks(self): return self.hunks def numHunks(self): return len(self.hunks) def checkFloats(self): """ Will call method checkFloats on each hunk """ hks = self.hunks[:] self.hunks = [] self.lines = 0 for h in hks: if not h.checkFloats(): self.hunks.append(h) self.lines += h.numLines() else: self.omitted_lines += h.numLines() class Parser: def __init__(self, fin): self.fin = fin self.line = "" self.diff = Diff() self.cur_hunk = None # to recognize beginning of hunk: self.re_hunk = re.compile(r"^[0-9]*(,[0-9]*){0,1}[a-zA-Z]?[0-9]*(,[0-9]*){0,1}$") self.re_added = re.compile(r"^> (.*)$") self.re_deleted = re.compile(r"^< (.*)$") def __readNextLine(self): self.line = self.fin.readline() if len(self.line) == 0: return False return True def parse(self): global PROGRESS_ON global MSG_BASE num_lines = 0 while self.__readNextLine(): # beggining of hunk if self.re_hunk.match(self.line): if self.cur_hunk is not None: self.diff.addHunk(self.cur_hunk) self.cur_hunk = Hunk() self.cur_hunk.addLine(self.line) # line added match = self.re_added.match(self.line) if match is not None: self.cur_hunk.addLine(self.line) self.cur_hunk.addLineAdded(match.group(1)) # line deleted match = self.re_deleted.match(self.line) if match is not None: self.cur_hunk.addLine(self.line) self.cur_hunk.addLineDeleted(match.group(1)) num_lines += 1 if PROGRESS_ON and num_lines % 50 == 0: print MSG_BASE, "[ %08d ]" % num_lines, "\r", sys.stdout.flush() # last push to list of hunks if self.cur_hunk is not None: self.diff.addHunk(self.cur_hunk) if PROGRESS_ON: print MSG_BASE, " ", "\r", sys.stdout.flush() def getDiff(self): return self.diff def regressionFilesInDir(): """ Returns sorted list of pairs of filenames where first name in pair is tmp. file and second corresponding file with saved regressions. """ re_tmp_out_file = re.compile(r"tmp\.(.*\.out)") re_tmp_err_file = re.compile(r"tmp\.(.*\.err)") files = [] all_files = os.listdir(".") all_files.sort() for file in all_files: res = re_tmp_out_file.match(file) if res is not None: fname = res.group(1) tmp = [file, ""] for file2 in all_files: if file2 == fname: tmp = [file, file2,] break files.append(tmp) res = re_tmp_err_file.match(file) if res is not None: fname = res.group(1) tmp = [file, ""] for file2 in all_files: if file2 == fname: tmp = [file, file2,] break files.append(tmp) return files def MSG(str = "", wait = False): if wait: print str, else: print str def MSGOK(prestr = "", str = "", poststr = ""): print prestr, "\033[0;32m" + str + "\033[0;0m", poststr def MSGFAIL(prestr = "", str = "", poststr = ""): print prestr, "\033[0;31m" + str + "\033[0;0m", poststr def MSGINFO(prestr = "", str = "", poststr = ""): print prestr, "\033[0;33m" + str + "\033[0;0m", poststr def dumpLines(lines, prefix = "", wait = False, max_lines = -1): line_num = 0 if wait: for line in lines: print prefix, line, line_num += 1 if max_lines >= 0 and line_num > max_lines: break else: for line in lines: print prefix, line line_num += 1 if max_lines >= 0 and line_num > max_lines: break def main(files): global MSG_BASE # As first compute length of columns len1 = 0 len2 = 0 for filenames in files: if len(filenames[0]) > len1: len1 = len(filenames[0]) if len(filenames[1]) > len2: len2 = len(filenames[1]) for filenames in files: if len(filenames[1]) == 0: MSGFAIL("", "===", "Can't compare %s %s, bacause %s does not exist!" % \ (filenames[0], filenames[0][4:], filenames[0][4:])) continue cmd = ["diff", filenames[0], filenames[1]] MSG_BASE = "Comparing %s and %s" % \ (filenames[0].ljust(len1) ,filenames[1].ljust(len2)) if not PROGRESS_ON: print MSG_BASE, sys.stdout.flush() pipe = Popen(cmd, stdout=PIPE) parser = Parser(pipe.stdout) parser.parse() diff = parser.getDiff() if not EXACT: diff.checkFloats() if PROGRESS_ON: print MSG_BASE, if diff.numHunks() == 0: MSGOK(" [", "OK", "]") if diff.numOmittedLines() > 0: MSGINFO(" -->", str(diff.numOmittedLines()) + " lines from diff omitted") else: MSGFAIL(" [", "FAILED", "]") if diff.numOmittedLines() > 0: MSGINFO(" -->", str(diff.numOmittedLines()) + " lines from diff omitted") MSGINFO(" -->", "Diff has " + str(diff.numLines()) + " lines") if diff.numLines() <= MAX_DIFF_LINES: MSGINFO(" -->", "Diff:") for h in diff.getHunks(): dumpLines(h.getLines(), " |", True) else: MSGINFO(" -->", "Printing only first " + str(MAX_DIFF_LINES) + " lines:") lines = [] for h in diff.getHunks(): lines += h.getLines() if len(lines) > MAX_DIFF_LINES: break; dumpLines(lines, " |", True, MAX_DIFF_LINES) def usage(): print "Usage: " + sys.argv[0] + " [ OPTIONS ] [ directory, [ directory, [ ... ] ] ]" print "" print " OPTIONS:" print " --help / -h none Print this help" print " --exact / -e none Switch do exact comparasion of files" print " --not-exact / -n none Switch do non exact comparasion of files (default behaviour)" print " --max-diff-lines int Maximum of lines of diff which can be printed (default " + str(MAX_DIFF_LINES) + ")" print " --eps float Precision of floating point numbers (epsilon) (default " + str(EPS) + ")" print " --no-progress none Turn off progress bar" print " --progress none Turn on progress bar (default)" print "" print " This program is able to compare files with regressions generated by CU testsuites." print " You can specify directories which are to be searched for regression files." print " In non exact copmarasion mode (which is default), this program tries to compare" print " floating point numbers in files with respect to specified precision (see --eps) and" print " those lines which differ only in precission of floating point numbers are omitted." print "" sys.exit(-1) # Init: # Set up base dir BASE_DIR = os.getcwd() # Parse command line options: optlist, args = gnu_getopt(sys.argv[1:], "hen", ["help", "max-diff-lines=", "eps=", \ "exact", "not-exact", \ "no-progress", "progress"]) for opt in optlist: if opt[0] == "--help" or opt[0] == "-h": usage() if opt[0] == "--exact" or opt[0] == "-e": EXACT = True if opt[0] == "--not-exact" or opt[0] == "-n": EXACT = False if opt[0] == "--max-diff-lines": MAX_DIFF_LINES = int(opt[1]) if opt[0] == "--eps": EPS = float(opt[1]) if opt[0] == "--no-progress": PROGRESS_ON = False if opt[0] == "--progress": PROGRESS_ON = True if len(args) == 0: files = regressionFilesInDir() main(files) else: for dir in args: os.chdir(BASE_DIR) MSGINFO() MSGINFO("", "Processing directory '" + dir + "':") MSGINFO() try: os.chdir(dir) except: MSGFAIL(" -->", "Directory '" + dir + "' does not exist.") files = regressionFilesInDir() main(files) sys.exit(0) ode-0.14/libccd/src/testsuites/cu/cu.c0000644000000000000000000002470312635011627016321 0ustar rootroot/*** * CU - C unit testing framework * --------------------------------- * Copyright (c)2007,2008,2009 Daniel Fiser * * * This file is part of CU. * * CU is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * CU is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include #include #include #include #include "cu.h" /** Declared here, because I didn't find header file where it is declared */ char *strsignal(int sig); const char *cu_current_test; const char *cu_current_test_suite; int cu_success_test_suites = 0; int cu_fail_test_suites = 0; int cu_success_tests = 0; int cu_fail_tests = 0; int cu_success_checks = 0; int cu_fail_checks = 0; char cu_out_prefix[CU_OUT_PREFIX_LENGTH+1] = ""; /* globally used file descriptor for reading/writing messages */ int fd; /* indicate if test was failed */ int test_failed; /* codes of messages */ #define CHECK_FAILED '0' #define CHECK_SUCCEED '1' #define TEST_FAILED '2' #define TEST_SUCCEED '3' #define TEST_SUITE_FAILED '4' #define TEST_SUITE_SUCCEED '5' #define END '6' #define TEST_NAME '7' /* predefined messages */ #define MSG_CHECK_SUCCEED write(fd, "1\n", 2) #define MSG_TEST_FAILED write(fd, "2\n", 2) #define MSG_TEST_SUCCEED write(fd, "3\n", 2) #define MSG_TEST_SUITE_FAILED write(fd, "4\n", 2) #define MSG_TEST_SUITE_SUCCEED write(fd, "5\n", 2) #define MSG_END write(fd, "6\n", 2) /* length of buffers */ #define BUF_LEN 1000 #define MSGBUF_LEN 300 static void redirect_out_err(const char *testName); static void close_out_err(void); static void run_test_suite(const char *ts_name, cu_test_suite_t *ts); static void receive_messages(void); static void cu_run_fork(const char *ts_name, cu_test_suite_t *test_suite); static void cu_print_results(void); void cu_run(int argc, char *argv[]) { cu_test_suites_t *tss; int i; char found = 0; if (argc > 1){ for (i=1; i < argc; i++){ tss = cu_test_suites; while (tss->name != NULL && tss->test_suite != NULL){ if (strcmp(argv[i], tss->name) == 0){ found = 1; cu_run_fork(tss->name, tss->test_suite); break; } tss++; } if (tss->name == NULL || tss->test_suite == NULL){ fprintf(stderr, "ERROR: Could not find test suite '%s'\n", argv[i]); } } if (found == 1) cu_print_results(); }else{ tss = cu_test_suites; while (tss->name != NULL && tss->test_suite != NULL){ cu_run_fork(tss->name, tss->test_suite); tss++; } cu_print_results(); } } static void cu_run_fork(const char *ts_name, cu_test_suite_t *ts) { int pipefd[2]; int pid; int status; if (pipe(pipefd) == -1){ perror("Pipe error"); exit(-1); } fprintf(stdout, " -> %s [IN PROGESS]\n", ts_name); fflush(stdout); pid = fork(); if (pid < 0){ perror("Fork error"); exit(-1); } if (pid == 0){ /* close read end of pipe */ close(pipefd[0]); fd = pipefd[1]; /* run testsuite, messages go to fd */ run_test_suite(ts_name, ts); MSG_END; close(fd); /* stop process where running testsuite */ exit(0); }else{ /* close write end of pipe */ close(pipefd[1]); fd = pipefd[0]; /* receive and interpret all messages */ receive_messages(); /* wait for children */ wait(&status); if (!WIFEXITED(status)){ /* if child process ends up abnormaly */ if (WIFSIGNALED(status)){ fprintf(stdout, "Test suite was terminated by signal %d (%s).\n", WTERMSIG(status), strsignal(WTERMSIG(status))); }else{ fprintf(stdout, "Test suite terminated abnormaly!\n"); } /* mark this test suite as failed, because was terminated * prematurely */ cu_fail_test_suites++; } close(fd); fprintf(stdout, " -> %s [DONE]\n\n", ts_name); fflush(stdout); } } static void run_test_suite(const char *ts_name, cu_test_suite_t *ts) { int test_suite_failed = 0; char buffer[MSGBUF_LEN]; int len; /* set up current test suite name for later messaging... */ cu_current_test_suite = ts_name; /* redirect stdout and stderr */ redirect_out_err(cu_current_test_suite); while (ts->name != NULL && ts->func != NULL){ test_failed = 0; /* set up name of test for later messaging */ cu_current_test = ts->name; /* send message what test is currently running */ len = snprintf(buffer, MSGBUF_LEN, "%c --> Running %s...\n", TEST_NAME, cu_current_test); write(fd, buffer, len); /* run test */ (*(ts->func))(); if (test_failed){ MSG_TEST_FAILED; test_suite_failed = 1; }else{ MSG_TEST_SUCCEED; } ts++; /* next test in test suite */ } if (test_suite_failed){ MSG_TEST_SUITE_FAILED; }else{ MSG_TEST_SUITE_SUCCEED; } /* close redirected stdout and stderr */ close_out_err(); } static void receive_messages(void) { char buf[BUF_LEN]; /* buffer */ int buf_len; /* how many chars stored in buf */ char bufout[MSGBUF_LEN]; /* buffer which can be printed out */ int bufout_len; int state = 0; /* 0 - waiting for code, 1 - copy msg to stdout */ int i; int end = 0; /* end of messages? */ bufout_len = 0; while((buf_len = read(fd, buf, BUF_LEN)) > 0 && !end){ for (i=0; i < buf_len; i++){ /* Prepare message for printing out */ if (state == 1 || state == 2){ if (bufout_len < MSGBUF_LEN) bufout[bufout_len++] = buf[i]; } /* reset state on '\n' in msg */ if (buf[i] == '\n'){ /* copy messages out */ if (state == 1) write(1, bufout, bufout_len); if (state == 2) write(2, bufout, bufout_len); state = 0; bufout_len = 0; continue; } if (state == 0){ if (buf[i] == CHECK_FAILED){ cu_fail_checks++; state = 2; }else if (buf[i] == TEST_NAME){ state = 1; }else if (buf[i] == CHECK_SUCCEED){ cu_success_checks++; }else if (buf[i] == TEST_FAILED){ cu_fail_tests++; }else if (buf[i] == TEST_SUCCEED){ cu_success_tests++; }else if (buf[i] == TEST_SUITE_FAILED){ cu_fail_test_suites++; }else if (buf[i] == TEST_SUITE_SUCCEED){ cu_success_test_suites++; }else if (buf[i] == END){ end = 1; break; } } } } } void cu_success_assertation(void) { MSG_CHECK_SUCCEED; } void cu_fail_assertation(const char *file, int line, const char *msg) { char buf[MSGBUF_LEN]; int len; len = snprintf(buf, MSGBUF_LEN, "%c%s:%d (%s::%s) :: %s\n", CHECK_FAILED, file, line, cu_current_test_suite, cu_current_test, msg); write(fd, buf, len); /* enable test_failed flag */ test_failed = 1; } static void cu_print_results(void) { fprintf(stdout, "\n"); fprintf(stdout, "==================================================\n"); fprintf(stdout, "| | failed | succeed | total |\n"); fprintf(stdout, "|------------------------------------------------|\n"); fprintf(stdout, "| assertations: | %6d | %7d | %5d |\n", cu_fail_checks, cu_success_checks, cu_success_checks+cu_fail_checks); fprintf(stdout, "| tests: | %6d | %7d | %5d |\n", cu_fail_tests, cu_success_tests, cu_success_tests+cu_fail_tests); fprintf(stdout, "| tests suites: | %6d | %7d | %5d |\n", cu_fail_test_suites, cu_success_test_suites, cu_success_test_suites+cu_fail_test_suites); fprintf(stdout, "==================================================\n"); } void cu_set_out_prefix(const char *str) { strncpy(cu_out_prefix, str, CU_OUT_PREFIX_LENGTH); } static void redirect_out_err(const char *test_name) { char buf[100]; snprintf(buf, 99, "%stmp.%s.out", cu_out_prefix, test_name); if (freopen(buf, "w", stdout) == NULL){ perror("Redirecting of stdout failed"); exit(-1); } snprintf(buf, 99, "%stmp.%s.err", cu_out_prefix, test_name); if (freopen(buf, "w", stderr) == NULL){ perror("Redirecting of stderr failed"); exit(-1); } } static void close_out_err(void) { fclose(stdout); fclose(stderr); } #ifdef CU_ENABLE_TIMER /* global variables for timer functions */ struct timespec __cu_timer; static struct timespec __cu_timer_start, __cu_timer_stop; const struct timespec *cuTimer(void) { return &__cu_timer; } void cuTimerStart(void) { clock_gettime(CLOCK_MONOTONIC, &__cu_timer_start); } const struct timespec *cuTimerStop(void) { clock_gettime(CLOCK_MONOTONIC, &__cu_timer_stop); /* store into t difference between time_start and time_end */ if (__cu_timer_stop.tv_nsec > __cu_timer_start.tv_nsec){ __cu_timer.tv_nsec = __cu_timer_stop.tv_nsec - __cu_timer_start.tv_nsec; __cu_timer.tv_sec = __cu_timer_stop.tv_sec - __cu_timer_start.tv_sec; }else{ __cu_timer.tv_nsec = __cu_timer_stop.tv_nsec + 1000000000L - __cu_timer_start.tv_nsec; __cu_timer.tv_sec = __cu_timer_stop.tv_sec - 1 - __cu_timer_start.tv_sec; } return &__cu_timer; } #endif /* CU_ENABLE_TIMER */ ode-0.14/libccd/src/testsuites/cu/cu.h0000644000000000000000000000747612635011627016336 0ustar rootroot/*** * CU - C unit testing framework * --------------------------------- * Copyright (c)2007,2008,2009 Daniel Fiser * * * This file is part of CU. * * CU is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * CU is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef _CU_H_ #define _CU_H_ #ifdef CU_ENABLE_TIMER # include #endif /* CU_ENABLE_TIMER */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /***** PUBLIC API *****/ /** * Define test */ #define TEST(name) \ void name(void) /** * Define testsuite */ #define TEST_SUITE(name) \ cu_test_suite_t test_suite_##name[] = /** * Must be on the end of list of tests. */ #define TEST_SUITE_CLOSURE \ { NULL, NULL } #define TEST_SUITES \ cu_test_suites_t cu_test_suites[] = #define TEST_SUITES_CLOSURE \ { NULL, NULL } #define TEST_SUITE_ADD(name) \ { #name, test_suite_##name } /** * Add test to testsuite */ #define TEST_ADD(name) \ { #name, name } #define CU_RUN(argc, argv) \ cu_run(argc, argv) /** * Set prefix for files printed out. Must contain trailing /. */ #define CU_SET_OUT_PREFIX(str) \ cu_set_out_prefix(str) /** * Assertations * Assertations with suffix 'M' (e.g. assertTrueM) is variation of macro * where is possible to specify error message. */ #define assertTrueM(a, message) \ if (a){ \ cu_success_assertation(); \ }else{ \ cu_fail_assertation(__FILE__, __LINE__, message); \ } #define assertTrue(a) \ assertTrueM((a), #a " is not true") #define assertFalseM(a, message) \ assertTrueM(!(a), message) #define assertFalse(a) \ assertFalseM((a), #a " is not false") #define assertEqualsM(a,b,message) \ assertTrueM((a) == (b), message) #define assertEquals(a,b) \ assertEqualsM((a), (b), #a " not equals " #b) #define assertNotEqualsM(a,b,message) \ assertTrueM((a) != (b), message) #define assertNotEquals(a,b) \ assertNotEqualsM((a), (b), #a " equals " #b) /***** PUBLIC API END *****/ #include #define CU_MAX_NAME_LENGTH 30 typedef void (*cu_test_func_t)(void); typedef struct _cu_test_suite_t { const char *name; cu_test_func_t func; } cu_test_suite_t; typedef struct _cu_test_suites_t { const char *name; cu_test_suite_t *test_suite; } cu_test_suites_t; extern cu_test_suites_t cu_test_suites[]; extern const char *cu_current_test; extern const char *cu_current_test_suite; extern int cu_success_test_suites; extern int cu_fail_test_suites; extern int cu_success_tests; extern int cu_fail_tests; extern int cu_success_checks; extern int cu_fail_checks; #define CU_OUT_PREFIX_LENGTH 30 extern char cu_out_prefix[CU_OUT_PREFIX_LENGTH+1]; void cu_run(int argc, char *argv[]); void cu_success_assertation(void); void cu_fail_assertation(const char *file, int line, const char *msg); void cu_set_out_prefix(const char *str); /** Timer **/ #ifdef CU_ENABLE_TIMER extern struct timespec __cu_timer; /** * Returns value of timer. (as timespec struct) */ const struct timespec *cuTimer(void); /** * Starts timer. */ void cuTimerStart(void); /** * Stops timer and record elapsed time from last call of cuTimerStart(). * Returns current value of timer. */ const struct timespec *cuTimerStop(void); #endif /* CU_ENABLE_TIMER */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif ode-0.14/libccd/src/testsuites/cu/latest.sh0000755000000000000000000000042212635011627017371 0ustar rootroot#!/bin/bash repo=http://git.danfis.cz/cu.git files="COPYING \ COPYING.LESSER \ cu.h \ cu.c \ Makefile \ check-regressions \ .gitignore \ " rm -rf cu git clone $repo for file in $files; do mv cu/"$file" . done; rm -rf cu ode-0.14/libccd/src/testsuites/cylcyl.c0000644000000000000000000000757712635011627016614 0ustar rootroot#include #include #include #include "support.h" #include "common.h" TEST(cylcylSetUp) { } TEST(cylcylTearDown) { } TEST(cylcylAlignedX) { ccd_t ccd; CCD_CYL(c1); CCD_CYL(c2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; c1.radius = 0.35; c1.height = 0.5; c2.radius = 0.5; c2.height = 1.; ccdVec3Set(&c1.pos, -5., 0., 0.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&c1, &c2, &ccd); if (i < 42 || i > 58){ assertFalse(res); }else{ assertTrue(res); } c1.pos.v[0] += 0.1; } } TEST(cylcylAlignedY) { ccd_t ccd; CCD_CYL(c1); CCD_CYL(c2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; c1.radius = 0.35; c1.height = 0.5; c2.radius = 0.5; c2.height = 1.; ccdVec3Set(&c1.pos, 0., -5., 0.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&c1, &c2, &ccd); if (i < 42 || i > 58){ assertFalse(res); }else{ assertTrue(res); } c1.pos.v[1] += 0.1; } } TEST(cylcylAlignedZ) { ccd_t ccd; CCD_CYL(c1); CCD_CYL(c2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; c1.radius = 0.35; c1.height = 0.5; c2.radius = 0.5; c2.height = 1.; ccdVec3Set(&c1.pos, 0., 0., -5.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&c1, &c2, &ccd); if (i < 43 || i > 57){ assertFalse(res); }else{ assertTrue(res); } c1.pos.v[2] += 0.1; } } #define TOSVT() \ svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos); \ ccdVec3Scale(&dir, depth); \ ccdVec3Add(&cyl2.pos, &dir); \ svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos) TEST(cylcylPenetrationEPA) { ccd_t ccd; CCD_CYL(cyl1); CCD_CYL(cyl2); int res; ccd_vec3_t axis; ccd_real_t depth; ccd_vec3_t dir, pos; fprintf(stderr, "\n\n\n---- cylcylPenetration ----\n\n\n"); cyl1.radius = 0.35; cyl1.height = 0.5; cyl2.radius = 0.5; cyl2.height = 1.; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccdVec3Set(&cyl2.pos, 0., 0., 0.3); res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 1"); //TOSVT(); ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 2"); //TOSVT(); <<< ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0., 0., 0.); res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 3"); //TOSVT(); ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 4"); //TOSVT(); ccdVec3Set(&axis, 0.567, 1.2, 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 5"); //TOSVT(); ccdVec3Set(&axis, -4.567, 1.2, 0.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); res = ccdGJKPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 6"); //TOSVT(); } ode-0.14/libccd/src/testsuites/cylcyl.h0000644000000000000000000000066312635011627016606 0ustar rootroot#ifndef CYL_CYL #define CYL_CYL #include TEST(cylcylSetUp); TEST(cylcylTearDown); TEST(cylcylAlignedX); TEST(cylcylAlignedY); TEST(cylcylAlignedZ); TEST(cylcylPenetrationEPA); TEST_SUITE(TSCylCyl) { TEST_ADD(cylcylSetUp), TEST_ADD(cylcylAlignedX), TEST_ADD(cylcylAlignedY), TEST_ADD(cylcylAlignedZ), TEST_ADD(cylcylPenetrationEPA), TEST_ADD(cylcylTearDown), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/main.c0000644000000000000000000000117512635011627016225 0ustar rootroot#include "vec3.h" #include "polytope.h" #include "boxbox.h" #include "spheresphere.h" #include "cylcyl.h" #include "boxcyl.h" #include "mpr_boxbox.h" #include "mpr_cylcyl.h" #include "mpr_boxcyl.h" TEST_SUITES { TEST_SUITE_ADD(TSVec3), TEST_SUITE_ADD(TSPt), TEST_SUITE_ADD(TSBoxBox), TEST_SUITE_ADD(TSSphereSphere), TEST_SUITE_ADD(TSCylCyl), TEST_SUITE_ADD(TSBoxCyl), TEST_SUITE_ADD(TSMPRBoxBox), TEST_SUITE_ADD(TSMPRCylCyl), TEST_SUITE_ADD(TSMPRBoxCyl), TEST_SUITES_CLOSURE }; int main(int argc, char *argv[]) { CU_SET_OUT_PREFIX("regressions/"); CU_RUN(argc, argv); return 0; } ode-0.14/libccd/src/testsuites/mpr_boxbox.c0000644000000000000000000003035412635011627017461 0ustar rootroot#include #include #include #include "support.h" #include #include #include "common.h" TEST(mprBoxboxAlignedX) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, -5., 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[0] += 0.1; } box1.x = 0.1; box1.y = 0.2; box1.z = 0.1; box2.x = 0.2; box2.y = 0.1; box2.z = 0.2; ccdVec3Set(&box1.pos, -0.5, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[0] += 0.01; } box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, -5., -0.1, 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[0] += 0.1; } } TEST(mprBoxboxAlignedY) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, 0., -5., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[1] += 0.1; } } TEST(mprBoxboxAlignedZ) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, 0., 0., -5.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&box1, &box2, &ccd); if (i < 35 || i > 65){ assertFalse(res); }else if (i != 35 && i != 65){ assertTrue(res); } box1.pos.v[2] += 0.1; } } TEST(mprBoxboxRot) { size_t i; ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; ccd_vec3_t axis; ccd_real_t angle; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; box1.x = 1; box1.y = 2; box1.z = 1; box2.x = 2; box2.y = 1; box2.z = 2; ccdVec3Set(&box1.pos, -5., 0.5, 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&box1, &box2, &ccd); if (i < 33 || i > 67){ assertFalse(res); }else if (i != 33 && i != 67){ assertTrue(res); } box1.pos.v[0] += 0.1; } box1.x = 1; box1.y = 1; box1.z = 1; box2.x = 1; box2.y = 1; box2.z = 1; ccdVec3Set(&box1.pos, -1.01, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); ccdVec3Set(&axis, 0., 1., 0.); angle = 0.; for (i = 0; i < 30; i++){ res = ccdMPRIntersect(&box1, &box2, &ccd); if (i != 0 && i != 10 && i != 20){ assertTrue(res); }else{ assertFalse(res); } angle += M_PI / 20.; ccdQuatSetAngleAxis(&box1.quat, angle, &axis); } } static void pConf(ccd_box_t *box1, ccd_box_t *box2, const ccd_vec3_t *v) { fprintf(stdout, "# box1.pos: [%lf %lf %lf]\n", ccdVec3X(&box1->pos), ccdVec3Y(&box1->pos), ccdVec3Z(&box1->pos)); fprintf(stdout, "# box1->quat: [%lf %lf %lf %lf]\n", box1->quat.q[0], box1->quat.q[1], box1->quat.q[2], box1->quat.q[3]); fprintf(stdout, "# box2->pos: [%lf %lf %lf]\n", ccdVec3X(&box2->pos), ccdVec3Y(&box2->pos), ccdVec3Z(&box2->pos)); fprintf(stdout, "# box2->quat: [%lf %lf %lf %lf]\n", box2->quat.q[0], box2->quat.q[1], box2->quat.q[2], box2->quat.q[3]); fprintf(stdout, "# sep: [%lf %lf %lf]\n", ccdVec3X(v), ccdVec3Y(v), ccdVec3Z(v)); fprintf(stdout, "#\n"); } TEST(mprBoxboxSeparate) { ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; ccd_vec3_t sep, expsep, expsep2, axis; fprintf(stderr, "\n\n\n---- boxboxSeparate ----\n\n\n"); box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 1.; box2.z = 1.5; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccdVec3Set(&box1.pos, -0.5, 0.5, 0.2); res = ccdMPRIntersect(&box1, &box2, &ccd); assertTrue(res); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0.25, 0., 0.); assertTrue(ccdVec3Eq(&sep, &expsep)); ccdVec3Scale(&sep, -1.); ccdVec3Add(&box1.pos, &sep); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0., 0., 0.); assertTrue(ccdVec3Eq(&sep, &expsep)); ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0., 0., -0.25); assertTrue(ccdVec3Eq(&sep, &expsep)); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, 0., 0., 0.); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); ccdVec3Set(&expsep, 0., 0., 1.); ccdVec3Set(&expsep2, 0., 0., -1.); assertTrue(ccdVec3Eq(&sep, &expsep) || ccdVec3Eq(&sep, &expsep2)); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0., 0.); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); pConf(&box1, &box2, &sep); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); res = ccdGJKSeparate(&box1, &box2, &ccd, &sep); assertTrue(res == 0); pConf(&box1, &box2, &sep); } #define TOSVT() \ svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos); \ ccdVec3Scale(&dir, depth); \ ccdVec3Add(&box2.pos, &dir); \ svtObjPen(&box1, &box2, stdout, "Pen 1", depth, &dir, &pos) TEST(mprBoxboxPenetration) { ccd_t ccd; CCD_BOX(box1); CCD_BOX(box2); int res; ccd_vec3_t axis; ccd_quat_t rot; ccd_real_t depth; ccd_vec3_t dir, pos; fprintf(stderr, "\n\n\n---- boxboxPenetration ----\n\n\n"); box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 1.; box2.z = 1.5; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; /* ccdVec3Set(&box2.pos, 0., 0., 0.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 1"); TOSVT(); */ ccdVec3Set(&box2.pos, 0.1, 0., 0.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 1"); //TOSVT(); ccdVec3Set(&box1.pos, -0.3, 0.5, 1.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 2"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, 0.1, 0., 0.1); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 3"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0., 0.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 4"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.5, 0.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 5"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&box2.pos, 0.1, 0., 0.); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 6"); //TOSVT(); box1.x = box1.y = box1.z = 1.; ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 1., 1.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -0.5, 0.1, 0.4); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 7"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = 0.2; box2.y = 0.5; box2.z = 1.; box2.x = box2.y = box2.z = 1.; ccdVec3Set(&axis, 0., 0., 1.); ccdQuatSetAngleAxis(&box1.quat, M_PI / 4., &axis); ccdVec3Set(&axis, 1., 0., 0.); ccdQuatSetAngleAxis(&rot, M_PI / 4., &axis); ccdQuatMul(&box1.quat, &rot); ccdVec3Set(&box1.pos, -1.3, 0., 0.); ccdVec3Set(&box2.pos, 0., 0., 0.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 8"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 0.5; box2.z = .5; ccdVec3Set(&box1.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdVec3Set(&box2.pos, 0., 0.73, 0.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 9"); //TOSVT(); box1.x = box1.y = box1.z = 1.; box2.x = 0.5; box2.y = 0.5; box2.z = .5; ccdVec3Set(&box1.pos, 0., 0., 0.); ccdQuatSet(&box1.quat, 0., 0., 0., 1.); ccdVec3Set(&box2.pos, 0.3, 0.738, 0.); ccdQuatSet(&box2.quat, 0., 0., 0., 1.); res = ccdMPRPenetration(&box1, &box2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 10"); //TOSVT(); } ode-0.14/libccd/src/testsuites/mpr_boxbox.h0000644000000000000000000000072712635011627017467 0ustar rootroot#ifndef MPR_BOX_BOX #define MPR_BOX_BOX #include TEST(mprBoxboxAlignedX); TEST(mprBoxboxAlignedY); TEST(mprBoxboxAlignedZ); TEST(mprBoxboxRot); TEST(mprBoxboxSeparate); TEST(mprBoxboxPenetration); TEST_SUITE(TSMPRBoxBox) { TEST_ADD(mprBoxboxAlignedX), TEST_ADD(mprBoxboxAlignedY), TEST_ADD(mprBoxboxAlignedZ), TEST_ADD(mprBoxboxRot), //TEST_ADD(mprBoxboxSeparate), TEST_ADD(mprBoxboxPenetration), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/mpr_boxcyl.c0000644000000000000000000001117212635011627017455 0ustar rootroot#include #include "common.h" #include #include "support.h" #define TOSVT() \ svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos); \ ccdVec3Scale(&dir, depth); \ ccdVec3Add(&cyl.pos, &dir); \ svtObjPen(&box, &cyl, stdout, "Pen 1", depth, &dir, &pos) TEST(mprBoxcylIntersect) { ccd_t ccd; CCD_BOX(box); CCD_CYL(cyl); int res; ccd_vec3_t axis; box.x = 0.5; box.y = 1.; box.z = 1.5; cyl.radius = 0.4; cyl.height = 0.7; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; ccdVec3Set(&cyl.pos, 0.1, 0., 0.); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&cyl.pos, .6, 0., 0.); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&cyl.pos, .6, 0.6, 0.); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, 0.67, 1.1, 0.12); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .6, 0., 0.5); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .9, 0.8, 0.5); res = ccdMPRIntersect(&box, &cyl, &ccd); assertTrue(res); } TEST(mprBoxcylPen) { ccd_t ccd; CCD_BOX(box); CCD_CYL(cyl); int res; ccd_vec3_t axis; ccd_real_t depth; ccd_vec3_t dir, pos; box.x = 0.5; box.y = 1.; box.z = 1.5; cyl.radius = 0.4; cyl.height = 0.7; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; ccdVec3Set(&cyl.pos, 0.1, 0., 0.); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 1"); //TOSVT(); ccdVec3Set(&cyl.pos, .6, 0., 0.); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 2"); //TOSVT(); ccdVec3Set(&cyl.pos, .6, 0.6, 0.); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 3"); //TOSVT(); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 4"); //TOSVT(); ccdVec3Set(&axis, 0., 1., 0.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 3., &axis); ccdVec3Set(&cyl.pos, .6, 0.6, 0.5); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 5"); //TOSVT(); ccdVec3Set(&axis, 0.67, 1.1, 0.12); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 4., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 6"); //TOSVT(); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .6, 0., 0.5); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 7"); //TOSVT(); ccdVec3Set(&axis, -0.1, 2.2, -1.); ccdQuatSetAngleAxis(&cyl.quat, M_PI / 5., &axis); ccdVec3Set(&cyl.pos, .6, 0., 0.5); ccdVec3Set(&axis, 1., 1., 0.); ccdQuatSetAngleAxis(&box.quat, -M_PI / 4., &axis); ccdVec3Set(&box.pos, .9, 0.8, 0.5); res = ccdMPRPenetration(&box, &cyl, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 8"); //TOSVT(); } ode-0.14/libccd/src/testsuites/mpr_boxcyl.h0000644000000000000000000000036212635011627017461 0ustar rootroot#ifndef MPR_TEST_BOXCYL_H #define MPR_TEST_BOXCYL_H #include TEST(mprBoxcylIntersect); TEST(mprBoxcylPen); TEST_SUITE(TSMPRBoxCyl){ TEST_ADD(mprBoxcylIntersect), TEST_ADD(mprBoxcylPen), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/mpr_cylcyl.c0000644000000000000000000001013512635011627017452 0ustar rootroot#include #include #include #include "support.h" #include "common.h" TEST(mprCylcylAlignedX) { ccd_t ccd; CCD_CYL(c1); CCD_CYL(c2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; c1.radius = 0.35; c1.height = 0.5; c2.radius = 0.5; c2.height = 1.; ccdVec3Set(&c1.pos, -5., 0., 0.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&c1, &c2, &ccd); if (i < 42 || i > 58){ assertFalse(res); }else{ assertTrue(res); } c1.pos.v[0] += 0.1; } } TEST(mprCylcylAlignedY) { ccd_t ccd; CCD_CYL(c1); CCD_CYL(c2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; c1.radius = 0.35; c1.height = 0.5; c2.radius = 0.5; c2.height = 1.; ccdVec3Set(&c1.pos, 0., -5., 0.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&c1, &c2, &ccd); if (i < 42 || i > 58){ assertFalse(res); }else{ assertTrue(res); } c1.pos.v[1] += 0.1; } } TEST(mprCylcylAlignedZ) { ccd_t ccd; CCD_CYL(c1); CCD_CYL(c2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; c1.radius = 0.35; c1.height = 0.5; c2.radius = 0.5; c2.height = 1.; ccdVec3Set(&c1.pos, 0., 0., -5.); for (i = 0; i < 100; i++){ res = ccdMPRIntersect(&c1, &c2, &ccd); if (i < 43 || i > 57){ assertFalse(res); }else{ assertTrue(res); } c1.pos.v[2] += 0.1; } } #define TOSVT() \ svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos); \ ccdVec3Scale(&dir, depth); \ ccdVec3Add(&cyl2.pos, &dir); \ svtObjPen(&cyl1, &cyl2, stdout, "Pen 1", depth, &dir, &pos) TEST(mprCylcylPenetration) { ccd_t ccd; CCD_CYL(cyl1); CCD_CYL(cyl2); int res; ccd_vec3_t axis; ccd_real_t depth; ccd_vec3_t dir, pos; fprintf(stderr, "\n\n\n---- mprCylcylPenetration ----\n\n\n"); cyl1.radius = 0.35; cyl1.height = 0.5; cyl2.radius = 0.5; cyl2.height = 1.; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; ccd.center1 = ccdObjCenter; ccd.center2 = ccdObjCenter; ccdVec3Set(&cyl2.pos, 0., 0., 0.3); res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 1"); //TOSVT(); ccdVec3Set(&cyl1.pos, 0.3, 0.1, 0.1); res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 2"); //TOSVT(); ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0., 0., 0.); res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 3"); //TOSVT(); ccdVec3Set(&axis, 0., 1., 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, -0.2, 0.7, 0.2); res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 4"); //TOSVT(); ccdVec3Set(&axis, 0.567, 1.2, 1.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 4., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 5"); //TOSVT(); ccdVec3Set(&axis, -4.567, 1.2, 0.); ccdQuatSetAngleAxis(&cyl2.quat, M_PI / 3., &axis); ccdVec3Set(&cyl2.pos, 0.6, -0.7, 0.2); res = ccdMPRPenetration(&cyl1, &cyl2, &ccd, &depth, &dir, &pos); assertTrue(res == 0); recPen(depth, &dir, &pos, stdout, "Pen 6"); //TOSVT(); } ode-0.14/libccd/src/testsuites/mpr_cylcyl.h0000644000000000000000000000055412635011627017463 0ustar rootroot#ifndef MPR_CYL_CYL #define MPR_CYL_CYL #include TEST(mprCylcylAlignedX); TEST(mprCylcylAlignedY); TEST(mprCylcylAlignedZ); TEST(mprCylcylPenetration); TEST_SUITE(TSMPRCylCyl) { TEST_ADD(mprCylcylAlignedX), TEST_ADD(mprCylcylAlignedY), TEST_ADD(mprCylcylAlignedZ), TEST_ADD(mprCylcylPenetration), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/polytope.c0000644000000000000000000003044612635011627017157 0ustar rootroot//#undef NDEBUG #include #include #include TEST(ptSetUp) { } TEST(ptTearDown) { } TEST(ptCreate1) { ccd_pt_t pt; ccd_pt_vertex_t *v[3]; ccd_pt_edge_t *e[3]; ccd_pt_face_t *f; ccd_vec3_t u; int res; size_t i; DBG2("------"); ccdPtInit(&pt); ccdPtDestroy(&pt); ccdPtInit(&pt); ccdVec3Set(&u, -1., -1., 0.); v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); assertTrue(ccdVec3Eq(&u, &v[0]->v.v)); ccdVec3Set(&u, 1., 0., 0.); v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); assertTrue(ccdVec3Eq(&u, &v[1]->v.v)); ccdVec3Set(&u, 0., 0., 1.); v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); assertTrue(ccdVec3Eq(&u, &v[2]->v.v)); for (i = 0; i < 3; i++){ assertTrue(ccdEq(v[i]->dist, ccdVec3Len2(&v[i]->v.v))); } e[0] = ccdPtAddEdge(&pt, v[0], v[1]); e[1] = ccdPtAddEdge(&pt, v[1], v[2]); e[2] = ccdPtAddEdge(&pt, v[2], v[0]); for (i = 0; i < 3; i++){ DBG("e[%d]->dist: %lf", i, e[i]->dist); DBG_VEC3(&e[i]->witness, " ->witness: "); } f = ccdPtAddFace(&pt, e[0], e[1], e[2]); DBG("f->dist: %lf", f->dist); DBG_VEC3(&f->witness, " ->witness: "); for (i = 0; i < 3; i++){ res = ccdPtDelVertex(&pt, v[i]); assertFalse(res == 0); res = ccdPtDelEdge(&pt, e[i]); assertFalse(res == 0); } ccdPtDelFace(&pt, f); for (i = 0; i < 3; i++){ res = ccdPtDelVertex(&pt, v[i]); assertFalse(res == 0); } for (i = 0; i < 3; i++){ res = ccdPtDelEdge(&pt, e[i]); assertTrue(res == 0); } for (i = 0; i < 3; i++){ res = ccdPtDelVertex(&pt, v[i]); assertTrue(res == 0); } v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); e[0] = ccdPtAddEdge(&pt, v[0], v[1]); e[1] = ccdPtAddEdge(&pt, v[1], v[2]); e[2] = ccdPtAddEdge(&pt, v[2], v[0]); f = ccdPtAddFace(&pt, e[0], e[1], e[2]); ccdPtDestroy(&pt); } TEST(ptCreate2) { ccd_pt_t pt; ccd_pt_vertex_t *v[4]; ccd_pt_edge_t *e[6]; ccd_pt_face_t *f[4]; ccd_vec3_t u; int res; size_t i; DBG2("------"); ccdPtInit(&pt); ccdVec3Set(&u, -1., -1., 0.); v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); assertTrue(ccdVec3Eq(&u, &v[0]->v.v)); ccdVec3Set(&u, 1., 0., 0.); v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); assertTrue(ccdVec3Eq(&u, &v[1]->v.v)); ccdVec3Set(&u, 0., 0., 1.); v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); assertTrue(ccdVec3Eq(&u, &v[2]->v.v)); ccdVec3Set(&u, 0., 1., 0.); v[3] = ccdPtAddVertexCoords(&pt, 0., 1., 0.); assertTrue(ccdVec3Eq(&u, &v[3]->v.v)); for (i = 0; i < 4; i++){ assertTrue(ccdEq(v[i]->dist, ccdVec3Len2(&v[i]->v.v))); } for (i = 0; i < 4; i++){ DBG("v[%d]->dist: %lf", i, v[i]->dist); DBG_VEC3(&v[i]->witness, " ->witness: "); } e[0] = ccdPtAddEdge(&pt, v[0], v[1]); e[1] = ccdPtAddEdge(&pt, v[1], v[2]); e[2] = ccdPtAddEdge(&pt, v[2], v[0]); e[3] = ccdPtAddEdge(&pt, v[3], v[0]); e[4] = ccdPtAddEdge(&pt, v[3], v[1]); e[5] = ccdPtAddEdge(&pt, v[3], v[2]); for (i = 0; i < 6; i++){ DBG("e[%d]->dist: %lf", i, e[i]->dist); DBG_VEC3(&e[i]->witness, " ->witness: "); } f[0] = ccdPtAddFace(&pt, e[0], e[1], e[2]); f[1] = ccdPtAddFace(&pt, e[3], e[4], e[0]); f[2] = ccdPtAddFace(&pt, e[4], e[5], e[1]); f[3] = ccdPtAddFace(&pt, e[5], e[3], e[2]); for (i = 0; i < 4; i++){ DBG("f[%d]->dist: %lf", i, f[i]->dist); DBG_VEC3(&f[i]->witness, " ->witness: "); } for (i = 0; i < 4; i++){ res = ccdPtDelVertex(&pt, v[i]); assertFalse(res == 0); } for (i = 0; i < 6; i++){ res = ccdPtDelEdge(&pt, e[i]); assertFalse(res == 0); } res = ccdPtDelFace(&pt, f[0]); for (i = 0; i < 6; i++){ res = ccdPtDelEdge(&pt, e[i]); assertFalse(res == 0); } res = ccdPtDelFace(&pt, f[1]); assertTrue(ccdPtDelEdge(&pt, e[0]) == 0); assertFalse(ccdPtDelEdge(&pt, e[1]) == 0); assertFalse(ccdPtDelEdge(&pt, e[2]) == 0); assertFalse(ccdPtDelEdge(&pt, e[3]) == 0); assertFalse(ccdPtDelEdge(&pt, e[4]) == 0); assertFalse(ccdPtDelEdge(&pt, e[5]) == 0); for (i = 0; i < 4; i++){ res = ccdPtDelVertex(&pt, v[i]); assertFalse(res == 0); } res = ccdPtDelFace(&pt, f[2]); assertTrue(ccdPtDelEdge(&pt, e[1]) == 0); assertTrue(ccdPtDelEdge(&pt, e[4]) == 0); assertFalse(ccdPtDelEdge(&pt, e[2]) == 0); assertFalse(ccdPtDelEdge(&pt, e[3]) == 0); assertFalse(ccdPtDelEdge(&pt, e[5]) == 0); assertTrue(ccdPtDelVertex(&pt, v[1]) == 0); assertFalse(ccdPtDelVertex(&pt, v[0]) == 0); assertFalse(ccdPtDelVertex(&pt, v[2]) == 0); assertFalse(ccdPtDelVertex(&pt, v[3]) == 0); res = ccdPtDelFace(&pt, f[3]); assertTrue(ccdPtDelEdge(&pt, e[2]) == 0); assertTrue(ccdPtDelEdge(&pt, e[3]) == 0); assertTrue(ccdPtDelEdge(&pt, e[5]) == 0); assertTrue(ccdPtDelVertex(&pt, v[0]) == 0); assertTrue(ccdPtDelVertex(&pt, v[2]) == 0); assertTrue(ccdPtDelVertex(&pt, v[3]) == 0); v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); v[3] = ccdPtAddVertexCoords(&pt, 0., 1., 0.); e[0] = ccdPtAddEdge(&pt, v[0], v[1]); e[1] = ccdPtAddEdge(&pt, v[1], v[2]); e[2] = ccdPtAddEdge(&pt, v[2], v[0]); e[3] = ccdPtAddEdge(&pt, v[3], v[0]); e[4] = ccdPtAddEdge(&pt, v[3], v[1]); e[5] = ccdPtAddEdge(&pt, v[3], v[2]); f[0] = ccdPtAddFace(&pt, e[0], e[1], e[2]); f[1] = ccdPtAddFace(&pt, e[3], e[4], e[0]); f[2] = ccdPtAddFace(&pt, e[4], e[5], e[1]); f[3] = ccdPtAddFace(&pt, e[5], e[3], e[2]); ccdPtDestroy(&pt); } TEST(ptNearest) { ccd_pt_t pt; ccd_pt_vertex_t *v[4]; ccd_pt_edge_t *e[6]; ccd_pt_face_t *f[4]; ccd_pt_el_t *nearest; DBG2("------"); ccdPtInit(&pt); v[0] = ccdPtAddVertexCoords(&pt, -1., -1., 0.); v[1] = ccdPtAddVertexCoords(&pt, 1., 0., 0.); v[2] = ccdPtAddVertexCoords(&pt, 0., 0., 1.); v[3] = ccdPtAddVertexCoords(&pt, 0., 1., 0.); e[0] = ccdPtAddEdge(&pt, v[0], v[1]); e[1] = ccdPtAddEdge(&pt, v[1], v[2]); e[2] = ccdPtAddEdge(&pt, v[2], v[0]); e[3] = ccdPtAddEdge(&pt, v[3], v[0]); e[4] = ccdPtAddEdge(&pt, v[3], v[1]); e[5] = ccdPtAddEdge(&pt, v[3], v[2]); f[0] = ccdPtAddFace(&pt, e[0], e[1], e[2]); f[1] = ccdPtAddFace(&pt, e[3], e[4], e[0]); f[2] = ccdPtAddFace(&pt, e[4], e[5], e[1]); f[3] = ccdPtAddFace(&pt, e[5], e[3], e[2]); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_FACE); assertEquals(nearest, (ccd_pt_el_t *)f[1]); assertTrue(ccdPtDelFace(&pt, f[1]) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_FACE); assertTrue(nearest == (ccd_pt_el_t *)f[0] || nearest == (ccd_pt_el_t *)f[3]); assertTrue(ccdPtDelFace(&pt, (ccd_pt_face_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_FACE); assertTrue(nearest == (ccd_pt_el_t *)f[0] || nearest == (ccd_pt_el_t *)f[3]); assertTrue(ccdPtDelFace(&pt, (ccd_pt_face_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_EDGE); assertTrue(nearest == (ccd_pt_el_t *)e[0] || nearest == (ccd_pt_el_t *)e[3]); assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_EDGE); assertTrue(nearest == (ccd_pt_el_t *)e[0] || nearest == (ccd_pt_el_t *)e[3]); assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_FACE); assertEquals(nearest, (ccd_pt_el_t *)f[2]); assertTrue(ccdPtDelFace(&pt, f[2]) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_EDGE); assertTrue(nearest == (ccd_pt_el_t *)e[1] || nearest == (ccd_pt_el_t *)e[4] || nearest == (ccd_pt_el_t *)e[5]); assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_EDGE); assertTrue(nearest == (ccd_pt_el_t *)e[1] || nearest == (ccd_pt_el_t *)e[4] || nearest == (ccd_pt_el_t *)e[5]); assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_EDGE); assertTrue(nearest == (ccd_pt_el_t *)e[1] || nearest == (ccd_pt_el_t *)e[4] || nearest == (ccd_pt_el_t *)e[5]); assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_EDGE); assertTrue(nearest == (ccd_pt_el_t *)e[2]); assertTrue(ccdPtDelEdge(&pt, (ccd_pt_edge_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_VERTEX); assertTrue(nearest == (ccd_pt_el_t *)v[1] || nearest == (ccd_pt_el_t *)v[2] || nearest == (ccd_pt_el_t *)v[3]); assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_VERTEX); assertTrue(nearest == (ccd_pt_el_t *)v[1] || nearest == (ccd_pt_el_t *)v[2] || nearest == (ccd_pt_el_t *)v[3]); assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_VERTEX); assertTrue(nearest == (ccd_pt_el_t *)v[1] || nearest == (ccd_pt_el_t *)v[2] || nearest == (ccd_pt_el_t *)v[3]); assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); nearest = ccdPtNearest(&pt); //DBG("nearest->type: %d", nearest->type); //DBG(" ->dist: %lf", nearest->dist); //DBG_VEC3(&nearest->witness, " ->witness: "); assertEquals(nearest->type, CCD_PT_VERTEX); assertTrue(nearest == (ccd_pt_el_t *)v[0]); assertTrue(ccdPtDelVertex(&pt, (ccd_pt_vertex_t *)nearest) == 0); nearest = ccdPtNearest(&pt); assertTrue(nearest == NULL); ccdPtDestroy(&pt); } ode-0.14/libccd/src/testsuites/polytope.h0000644000000000000000000000051612635011627017157 0ustar rootroot#ifndef TEST_POLYTOPE_H #define TEST_POLYTOPE_H #include TEST(ptSetUp); TEST(ptTearDown); TEST(ptCreate1); TEST(ptCreate2); TEST(ptNearest); TEST_SUITE(TSPt) { TEST_ADD(ptSetUp), TEST_ADD(ptCreate1), TEST_ADD(ptCreate2), TEST_ADD(ptNearest), TEST_ADD(ptTearDown), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/regressions/0000775000000000000000000000000012635012023017465 5ustar rootrootode-0.14/libccd/src/testsuites/regressions/TSBoxBox.err0000644000000000000000000000007712635011627021662 0ustar rootroot ---- boxboxSeparate ---- ---- boxboxPenetration ---- ode-0.14/libccd/src/testsuites/regressions/TSBoxBox.out0000644000000000000000000000257212635011627021703 0ustar rootroot# box1.pos: [-0.500000 0.000000 0.000000] # box1->quat: [0.000000 0.000000 0.382683 0.923880] # box2->pos: [0.000000 0.000000 0.000000] # box2->quat: [0.000000 0.000000 0.000000 1.000000] # sep: [0.707107 0.000000 0.000000] # # box1.pos: [-0.500000 0.100000 0.400000] # box1->quat: [0.000000 0.270598 0.270598 0.923880] # box2->pos: [0.000000 0.000000 0.000000] # box2->quat: [0.000000 0.000000 0.000000 1.000000] # sep: [0.633939 0.000000 -0.371353] # # Pen 1: depth: 0.650000 # Pen 1: dir: [1.000000 0.000000 0.000000] # Pen 1: pos: [0.096875 0.000000 0.000000] # # Pen 2: depth: 0.250000 # Pen 2: dir: [-0.000000 0.000000 -1.000000] # Pen 2: pos: [-0.058333 0.250000 0.583333] # # Pen 3: depth: 0.900000 # Pen 3: dir: [0.000000 0.000000 -1.000000] # Pen 3: pos: [0.111506 0.000000 0.050000] # # Pen 4: depth: 0.607107 # Pen 4: dir: [1.000000 0.000000 0.000000] # Pen 4: pos: [-0.153585 0.000000 0.000000] # # Pen 5: depth: 0.429289 # Pen 5: dir: [0.707107 -0.707107 0.000000] # Pen 5: pos: [-0.167157 0.379289 0.000000] # # Pen 6: depth: 0.648412 # Pen 6: dir: [0.862856 0.000000 -0.505449] # Pen 6: pos: [-0.148223 0.055362 0.319638] # # Pen 7: depth: 0.622622 # Pen 7: dir: [1.000000 0.000000 -0.000000] # Pen 7: pos: [-0.095997 0.063593 0.067678] # # Pen 8: depth: 0.053553 # Pen 8: dir: [1.000000 0.000000 0.000000] # Pen 8: pos: [-0.523223 -0.073223 0.020711] # ode-0.14/libccd/src/testsuites/regressions/TSBoxCyl.out0000644000000000000000000000165712635011627021705 0ustar rootroot# Pen 1: depth: 0.549996 # Pen 1: dir: [0.999992 -0.003902 0.000000] # Pen 1: pos: [0.020284 0.000000 0.000000] # # Pen 2: depth: 0.050000 # Pen 2: dir: [0.999992 -0.003902 0.000000] # Pen 2: pos: [0.253480 0.000000 0.025000] # # Pen 3: depth: 0.030994 # Pen 3: dir: [0.950248 0.311493 0.000000] # Pen 3: pos: [0.246546 0.420744 0.000000] # # Pen 4: depth: 0.033436 # Pen 4: dir: [0.976101 0.217308 0.001900] # Pen 4: pos: [0.243648 0.480401 0.450000] # # Pen 5: depth: 0.142160 # Pen 5: dir: [0.968442 0.249235 0.001146] # Pen 5: pos: [0.190887 0.421462 0.605496] # # Pen 6: depth: 0.179282 # Pen 6: dir: [0.999995 0.001057 0.002913] # Pen 6: pos: [0.176026 0.036944 0.488189] # # Pen 7: depth: 0.750000 # Pen 7: dir: [-0.853795 -0.143509 -0.500438] # Pen 7: pos: [0.572744 0.014828 0.562324] # # Pen 8: depth: 0.142666 # Pen 8: dir: [-0.475515 -0.841074 0.257839] # Pen 8: pos: [0.824886 0.230213 0.463136] # ode-0.14/libccd/src/testsuites/regressions/TSCylCyl.err0000644000000000000000000000004112635011627021647 0ustar rootroot ---- cylcylPenetration ---- ode-0.14/libccd/src/testsuites/regressions/TSCylCyl.out0000644000000000000000000000131412635011627021672 0ustar rootroot# Pen 1: depth: 0.750000 # Pen 1: dir: [0.000000 0.000000 1.000000] # Pen 1: pos: [0.004079 -0.012238 0.009615] # # Pen 2: depth: 0.531931 # Pen 2: dir: [-0.926428 -0.376463 -0.002666] # Pen 2: pos: [0.218566 0.072232 0.025000] # # Pen 3: depth: 0.645740 # Pen 3: dir: [-0.500000 -0.146447 -0.853553] # Pen 3: pos: [0.177594 0.070484 0.186987] # # Pen 4: depth: 0.104445 # Pen 4: dir: [-0.482095 0.866317 0.130685] # Pen 4: pos: [0.123724 0.348390 0.269312] # # Pen 5: depth: 0.093082 # Pen 5: dir: [0.034600 -0.999228 -0.018627] # Pen 5: pos: [0.311257 -0.203923 -0.064270] # # Pen 6: depth: 0.198749 # Pen 6: dir: [0.411370 -0.911372 0.013223] # Pen 6: pos: [0.405836 -0.130066 0.121441] # ode-0.14/libccd/src/testsuites/regressions/TSMPRBoxBox.err0000644000000000000000000000004112635011627022230 0ustar rootroot ---- boxboxPenetration ---- ode-0.14/libccd/src/testsuites/regressions/TSMPRBoxBox.out0000644000000000000000000000224412635011627022256 0ustar rootroot# Pen 1: depth: 0.650000 # Pen 1: dir: [1.000000 0.000000 0.000000] # Pen 1: pos: [0.175000 0.000000 0.000000] # # Pen 2: depth: 0.250000 # Pen 2: dir: [-0.000000 0.000000 -1.000000] # Pen 2: pos: [-0.033333 0.250000 0.600000] # # Pen 3: depth: 0.900000 # Pen 3: dir: [0.000000 0.000000 -1.000000] # Pen 3: pos: [0.100000 0.000000 0.050000] # # Pen 4: depth: 0.607107 # Pen 4: dir: [1.000000 0.000000 0.000000] # Pen 4: pos: [-0.096447 0.000000 0.000000] # # Pen 5: depth: 0.429289 # Pen 5: dir: [0.707107 -0.707107 0.000000] # Pen 5: pos: [-0.222183 0.322183 0.000000] # # Pen 6: depth: 0.648412 # Pen 6: dir: [0.862856 -0.000000 -0.505449] # Pen 6: pos: [-0.163060 0.012676 0.263060] # # Pen 7: depth: 0.622928 # Pen 7: dir: [0.999509 0.028016 -0.014008] # Pen 7: pos: [-0.145374 0.170833 0.176732] # # Pen 8: depth: 0.053553 # Pen 8: dir: [1.000000 0.000000 0.000000] # Pen 8: pos: [-0.480217 -0.140652 0.000000] # # Pen 9: depth: 0.020000 # Pen 9: dir: [0.000000 1.000000 0.000000] # Pen 9: pos: [0.000000 0.490000 0.000000] # # Pen 10: depth: 0.012000 # Pen 10: dir: [-0.000000 1.000000 0.000000] # Pen 10: pos: [0.200000 0.492000 0.000000] # ode-0.14/libccd/src/testsuites/regressions/TSMPRBoxCyl.out0000644000000000000000000000166212635011627022260 0ustar rootroot# Pen 1: depth: 0.550000 # Pen 1: dir: [1.000000 0.000000 0.000000] # Pen 1: pos: [-0.025000 0.000000 0.000000] # # Pen 2: depth: 0.050000 # Pen 2: dir: [1.000000 0.000000 0.000000] # Pen 2: pos: [0.225000 0.000000 0.000000] # # Pen 3: depth: 0.038532 # Pen 3: dir: [0.788956 0.614450 -0.000000] # Pen 3: pos: [0.238587 0.477175 0.000000] # # Pen 4: depth: 0.038654 # Pen 4: dir: [0.779134 0.626832 -0.005696] # Pen 4: pos: [0.238603 0.477206 0.340909] # # Pen 5: depth: 0.166653 # Pen 5: dir: [0.734126 0.679013 -0.000000] # Pen 5: pos: [0.208320 0.416640 0.595113] # # Pen 6: depth: 0.180673 # Pen 6: dir: [1.000000 0.000003 -0.000000] # Pen 6: pos: [0.192142 0.009404 0.479162] # # Pen 7: depth: 0.771410 # Pen 7: dir: [-0.922598 -0.242256 -0.300208] # Pen 7: pos: [0.600000 0.000000 0.500000] # # Pen 8: depth: 0.142813 # Pen 8: dir: [-0.476782 -0.840534 0.257259] # Pen 8: pos: [0.776128 0.285646 0.436629] # ode-0.14/libccd/src/testsuites/regressions/TSMPRCylCyl.err0000644000000000000000000000004412635011627022231 0ustar rootroot ---- mprCylcylPenetration ---- ode-0.14/libccd/src/testsuites/regressions/TSMPRCylCyl.out0000644000000000000000000000131212635011627022247 0ustar rootroot# Pen 1: depth: 0.450000 # Pen 1: dir: [0.000000 0.000000 1.000000] # Pen 1: pos: [0.000000 0.000000 0.025000] # # Pen 2: depth: 0.533732 # Pen 2: dir: [-0.952492 -0.304562 0.000000] # Pen 2: pos: [0.176471 0.058824 0.166667] # # Pen 3: depth: 0.720933 # Pen 3: dir: [-0.947406 -0.320033 0.000085] # Pen 3: pos: [0.198747 0.066309 0.050800] # # Pen 4: depth: 0.106076 # Pen 4: dir: [-0.524820 0.835278 0.163936] # Pen 4: pos: [0.138692 0.362418 0.320024] # # Pen 5: depth: 0.103863 # Pen 5: dir: [0.291494 -0.956567 -0.003314] # Pen 5: pos: [0.337721 -0.209314 -0.094587] # # Pen 6: depth: 0.202625 # Pen 6: dir: [0.347225 -0.937782 -0.000000] # Pen 6: pos: [0.399554 -0.164780 0.199941] # ode-0.14/libccd/src/testsuites/regressions/TSPt.err0000644000000000000000000000327512635011627021047 0ustar rootrootptCreate1 :: ------ ptCreate1 :: e[0]->dist: 0.200000 ptCreate1 :: ->witness: [0.200000 -0.400000 0.000000] ptCreate1 :: e[1]->dist: 0.500000 ptCreate1 :: ->witness: [0.500000 0.000000 0.500000] ptCreate1 :: e[2]->dist: 0.666667 ptCreate1 :: ->witness: [-0.333333 -0.333333 0.666667] ptCreate1 :: f->dist: 0.166667 ptCreate1 :: ->witness: [0.166667 -0.333333 0.166667] ptCreate2 :: ------ ptCreate2 :: v[0]->dist: 2.000000 ptCreate2 :: ->witness: [-1.000000 -1.000000 0.000000] ptCreate2 :: v[1]->dist: 1.000000 ptCreate2 :: ->witness: [1.000000 0.000000 0.000000] ptCreate2 :: v[2]->dist: 1.000000 ptCreate2 :: ->witness: [0.000000 0.000000 1.000000] ptCreate2 :: v[3]->dist: 1.000000 ptCreate2 :: ->witness: [0.000000 1.000000 0.000000] ptCreate2 :: e[0]->dist: 0.200000 ptCreate2 :: ->witness: [0.200000 -0.400000 0.000000] ptCreate2 :: e[1]->dist: 0.500000 ptCreate2 :: ->witness: [0.500000 0.000000 0.500000] ptCreate2 :: e[2]->dist: 0.666667 ptCreate2 :: ->witness: [-0.333333 -0.333333 0.666667] ptCreate2 :: e[3]->dist: 0.200000 ptCreate2 :: ->witness: [-0.400000 0.200000 0.000000] ptCreate2 :: e[4]->dist: 0.500000 ptCreate2 :: ->witness: [0.500000 0.500000 0.000000] ptCreate2 :: e[5]->dist: 0.500000 ptCreate2 :: ->witness: [0.000000 0.500000 0.500000] ptCreate2 :: f[0]->dist: 0.166667 ptCreate2 :: ->witness: [0.166667 -0.333333 0.166667] ptCreate2 :: f[1]->dist: 0.000000 ptCreate2 :: ->witness: [0.000000 0.000000 0.000000] ptCreate2 :: f[2]->dist: 0.333333 ptCreate2 :: ->witness: [0.333333 0.333333 0.333333] ptCreate2 :: f[3]->dist: 0.166667 ptCreate2 :: ->witness: [-0.333333 0.166667 0.166667] ptNearest :: ------ ode-0.14/libccd/src/testsuites/spheresphere.c0000644000000000000000000000320112635011627017766 0ustar rootroot#include #include #include "support.h" #include TEST(spheresphereSetUp) { } TEST(spheresphereTearDown) { } TEST(spheresphereAlignedX) { ccd_t ccd; CCD_SPHERE(s1); CCD_SPHERE(s2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; s1.radius = 0.35; s2.radius = .5; ccdVec3Set(&s1.pos, -5., 0., 0.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&s1, &s2, &ccd); if (i < 42 || i > 58){ assertFalse(res); }else{ assertTrue(res); } s1.pos.v[0] += 0.1; } } TEST(spheresphereAlignedY) { ccd_t ccd; CCD_SPHERE(s1); CCD_SPHERE(s2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; s1.radius = 0.35; s2.radius = .5; ccdVec3Set(&s1.pos, 0., -5., 0.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&s1, &s2, &ccd); if (i < 42 || i > 58){ assertFalse(res); }else{ assertTrue(res); } s1.pos.v[1] += 0.1; } } TEST(spheresphereAlignedZ) { ccd_t ccd; CCD_SPHERE(s1); CCD_SPHERE(s2); size_t i; int res; CCD_INIT(&ccd); ccd.support1 = ccdSupport; ccd.support2 = ccdSupport; s1.radius = 0.35; s2.radius = .5; ccdVec3Set(&s1.pos, 0., 0., -5.); for (i = 0; i < 100; i++){ res = ccdGJKIntersect(&s1, &s2, &ccd); if (i < 42 || i > 58){ assertFalse(res); }else{ assertTrue(res); } s1.pos.v[2] += 0.1; } } ode-0.14/libccd/src/testsuites/spheresphere.h0000644000000000000000000000067612635011627020010 0ustar rootroot#ifndef SPHERE_SPHERE #define SPHERE_SPHERE #include TEST(spheresphereSetUp); TEST(spheresphereTearDown); TEST(spheresphereAlignedX); TEST(spheresphereAlignedY); TEST(spheresphereAlignedZ); TEST_SUITE(TSSphereSphere) { TEST_ADD(spheresphereSetUp), TEST_ADD(spheresphereAlignedX), TEST_ADD(spheresphereAlignedY), TEST_ADD(spheresphereAlignedZ), TEST_ADD(spheresphereTearDown), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/testsuites/support.c0000644000000000000000000000514212635011627017013 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #include #include #include #include "support.h" void ccdSupport(const void *_obj, const ccd_vec3_t *_dir, ccd_vec3_t *v) { // Support function is made according to Gino van den Bergen's paper // A Fast and Robust CCD Implementation for Collision Detection of // Convex Objects ccd_obj_t *obj = (ccd_obj_t *)_obj; ccd_vec3_t dir; ccd_quat_t qinv; ccdVec3Copy(&dir, _dir); ccdQuatInvert2(&qinv, &obj->quat); ccdQuatRotVec(&dir, &qinv); if (obj->type == CCD_OBJ_BOX){ ccd_box_t *box = (ccd_box_t *)obj; ccdVec3Set(v, ccdSign(ccdVec3X(&dir)) * box->x * CCD_REAL(0.5), ccdSign(ccdVec3Y(&dir)) * box->y * CCD_REAL(0.5), ccdSign(ccdVec3Z(&dir)) * box->z * CCD_REAL(0.5)); }else if (obj->type == CCD_OBJ_SPHERE){ ccd_sphere_t *sphere = (ccd_sphere_t *)obj; ccd_real_t len; len = ccdVec3Len2(&dir); if (len - CCD_EPS > CCD_ZERO){ ccdVec3Copy(v, &dir); ccdVec3Scale(v, sphere->radius / CCD_SQRT(len)); }else{ ccdVec3Set(v, CCD_ZERO, CCD_ZERO, CCD_ZERO); } }else if (obj->type == CCD_OBJ_CYL){ ccd_cyl_t *cyl = (ccd_cyl_t *)obj; ccd_real_t zdist, rad; zdist = dir.v[0] * dir.v[0] + dir.v[1] * dir.v[1]; zdist = CCD_SQRT(zdist); if (ccdIsZero(zdist)){ ccdVec3Set(v, CCD_ZERO, CCD_ZERO, ccdSign(ccdVec3Z(&dir)) * cyl->height * CCD_REAL(0.5)); }else{ rad = cyl->radius / zdist; ccdVec3Set(v, rad * ccdVec3X(&dir), rad * ccdVec3Y(&dir), ccdSign(ccdVec3Z(&dir)) * cyl->height * CCD_REAL(0.5)); } } // transform support vertex ccdQuatRotVec(v, &obj->quat); ccdVec3Add(v, &obj->pos); } void ccdObjCenter(const void *_obj, ccd_vec3_t *center) { ccd_obj_t *obj = (ccd_obj_t *)_obj; ccdVec3Set(center, CCD_ZERO, CCD_ZERO, CCD_ZERO); // rotation is not needed ccdVec3Add(center, &obj->pos); } ode-0.14/libccd/src/testsuites/support.h0000644000000000000000000000472212635011627017023 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ /*** * Some support() functions for some convex shapes. */ #ifndef __CCD_SUPPORT_H__ #define __CCD_SUPPORT_H__ #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define CCD_OBJ_BOX 1 #define CCD_OBJ_SPHERE 2 #define CCD_OBJ_CYL 3 #define __CCD_OBJ__ \ int type; \ ccd_vec3_t pos; \ ccd_quat_t quat; struct _ccd_obj_t { __CCD_OBJ__ }; typedef struct _ccd_obj_t ccd_obj_t; struct _ccd_box_t { __CCD_OBJ__ ccd_real_t x, y, z; //!< Lengths of box's edges }; typedef struct _ccd_box_t ccd_box_t; struct _ccd_sphere_t { __CCD_OBJ__ ccd_real_t radius; }; typedef struct _ccd_sphere_t ccd_sphere_t; struct _ccd_cyl_t { __CCD_OBJ__ ccd_real_t radius; ccd_real_t height; }; typedef struct _ccd_cyl_t ccd_cyl_t; #define CCD_BOX(name) \ ccd_box_t name = { .type = CCD_OBJ_BOX, \ .pos = { .v = { 0., 0., 0. } }, \ .quat = { .q = { 0., 0., 0., 1. } }, \ .x = 0., \ .y = 0., \ .z = 0. } #define CCD_SPHERE(name) \ ccd_sphere_t name = { .type = CCD_OBJ_SPHERE, \ .pos = { .v = { 0., 0., 0. } }, \ .quat = { .q = { 0., 0., 0., 1. } }, \ .radius = 0. } #define CCD_CYL(name) \ ccd_cyl_t name = { .type = CCD_OBJ_CYL, \ .pos = { .v = { 0., 0., 0. } }, \ .quat = { .q = { 0., 0., 0., 1. } }, \ .radius = 0., \ .height = 0. } /** * Returns supporting vertex via v. * Supporting vertex is fathest vertex from object in direction dir. */ void ccdSupport(const void *obj, const ccd_vec3_t *dir, ccd_vec3_t *v); /** * Returns center of object. */ void ccdObjCenter(const void *obj, ccd_vec3_t *center); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __CCD_SUPPORT_H__ */ ode-0.14/libccd/src/testsuites/vec3.c0000644000000000000000000001773012635011627016145 0ustar rootroot#include #include #include TEST(vec3SetUp) { } TEST(vec3TearDown) { } TEST(vec3PointSegmentDist) { ccd_vec3_t P, a, b, w, ew; ccd_real_t dist; ccdVec3Set(&a, 0., 0., 0.); ccdVec3Set(&b, 1., 0., 0.); // extereme w == a ccdVec3Set(&P, -1., 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 1.)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, -0.5, 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.5 * 0.5)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, -0.1, 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, .1 * .1)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, 0., 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, -1., 1., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 2.)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, -0.5, 0.5, 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.5)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, -0.1, -1., 2.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 5.01)); assertTrue(ccdVec3Eq(&w, &a)); // extereme w == b ccdVec3Set(&P, 2., 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 1.)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, 1.5, 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.5 * 0.5)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, 1.1, 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, .1 * .1)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, 1., 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, 2., 1., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 2.)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, 1.5, 0.5, 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.5)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, 1.1, -1., 2.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 5.01)); assertTrue(ccdVec3Eq(&w, &b)); // inside segment ccdVec3Set(&P, .5, 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &P)); ccdVec3Set(&P, .9, 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &P)); ccdVec3Set(&P, .5, 1., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 1.)); ccdVec3Set(&ew, 0.5, 0., 0.); assertTrue(ccdVec3Eq(&w, &ew)); ccdVec3Set(&P, .5, 1., 1.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 2.)); ccdVec3Set(&ew, 0.5, 0., 0.); assertTrue(ccdVec3Eq(&w, &ew)); ccdVec3Set(&a, -.5, 2., 1.); ccdVec3Set(&b, 1., 1.5, 0.5); // extereme w == a ccdVec3Set(&P, -10., 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 9.5 * 9.5 + 2. * 2. + 1.)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, -10., 9.2, 3.4); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 9.5 * 9.5 + 7.2 * 7.2 + 2.4 * 2.4)); assertTrue(ccdVec3Eq(&w, &a)); // extereme w == b ccdVec3Set(&P, 10., 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 9. * 9. + 1.5 * 1.5 + 0.5 * 0.5)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, 10., 9.2, 3.4); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 9. * 9. + 7.7 * 7.7 + 2.9 * 2.9)); assertTrue(ccdVec3Eq(&w, &b)); // inside ab ccdVec3Set(&a, -.1, 1., 1.); ccdVec3Set(&b, 1., 1., 1.); ccdVec3Set(&P, 0., 0., 0.); dist = ccdVec3PointSegmentDist2(&P, &a, &b, &w); assertTrue(ccdEq(dist, 2.)); ccdVec3Set(&ew, 0., 1., 1.); assertTrue(ccdVec3Eq(&w, &ew)); } TEST(vec3PointTriDist) { ccd_vec3_t P, a, b, c, w, P0; ccd_real_t dist; ccdVec3Set(&a, -1., 0., 0.); ccdVec3Set(&b, 0., 1., 1.); ccdVec3Set(&c, -1., 0., 1.); ccdVec3Set(&P, -1., 0., 0.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, 0., 1., 1.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, -1., 0., 1.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &c)); ccdVec3Set(&P, 0., 0., 0.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, NULL); assertTrue(ccdEq(dist, 2./3.)); // region 4 ccdVec3Set(&P, -2., 0., 0.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &a))); assertTrue(ccdVec3Eq(&w, &a)); ccdVec3Set(&P, -2., 0.2, -1.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &a))); assertTrue(ccdVec3Eq(&w, &a)); // region 2 ccdVec3Set(&P, -1.3, 0., 1.2); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &c))); assertTrue(ccdVec3Eq(&w, &c)); ccdVec3Set(&P, -1.2, 0.2, 1.1); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &c))); assertTrue(ccdVec3Eq(&w, &c)); // region 6 ccdVec3Set(&P, 0.3, 1., 1.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &b))); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, .1, 1., 1.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, ccdVec3Dist2(&P, &b))); assertTrue(ccdVec3Eq(&w, &b)); // region 1 ccdVec3Set(&P, 0., 1., 2.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 1.)); assertTrue(ccdVec3Eq(&w, &b)); ccdVec3Set(&P, -1., 0., 2.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 1.)); assertTrue(ccdVec3Eq(&w, &c)); ccdVec3Set(&P, -0.5, 0.5, 2.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 1.)); ccdVec3Set(&P0, -0.5, 0.5, 1.); assertTrue(ccdVec3Eq(&w, &P0)); // region 3 ccdVec3Set(&P, -2., -1., 0.7); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 2.)); ccdVec3Set(&P0, -1., 0., 0.7); assertTrue(ccdVec3Eq(&w, &P0)); // region 5 ccdVec3Set(&P, 0., 0., 0.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 2./3.)); ccdVec3Set(&P0, -2./3., 1./3., 1./3.); assertTrue(ccdVec3Eq(&w, &P0)); // region 0 ccdVec3Set(&P, -0.5, 0.5, 0.5); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &P)); ccdVec3Set(&P, -0.5, 0.5, 0.7); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &P)); ccdVec3Set(&P, -0.5, 0.5, 0.9); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.)); assertTrue(ccdVec3Eq(&w, &P)); ccdVec3Set(&P, 0., 0., 0.5); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.5)); ccdVec3Set(&P0, -.5, .5, .5); assertTrue(ccdVec3Eq(&w, &P0)); ccdVec3Set(&a, -1., 0., 0.); ccdVec3Set(&b, 0., 1., -1.); ccdVec3Set(&c, 0., 1., 1.); ccdVec3Set(&P, 0., 0., 0.); dist = ccdVec3PointTriDist2(&P, &a, &b, &c, &w); assertTrue(ccdEq(dist, 0.5)); ccdVec3Set(&P0, -.5, .5, 0.); assertTrue(ccdVec3Eq(&w, &P0)); //fprintf(stderr, "dist: %lf\n", dist); } ode-0.14/libccd/src/testsuites/vec3.h0000644000000000000000000000051012635011627016136 0ustar rootroot#ifndef TEST_VEC3_H #define TEST_VEC3_H #include TEST(vec3SetUp); TEST(vec3TearDown); TEST(vec3PointSegmentDist); TEST(vec3PointTriDist); TEST_SUITE(TSVec3) { TEST_ADD(vec3SetUp), TEST_ADD(vec3PointSegmentDist), TEST_ADD(vec3PointTriDist), TEST_ADD(vec3TearDown), TEST_SUITE_CLOSURE }; #endif ode-0.14/libccd/src/vec3.c0000644000000000000000000002124112635011627013721 0ustar rootroot/*** * libccd * --------------------------------- * Copyright (c)2010 Daniel Fiser * * * This file is part of libccd. * * Distributed under the OSI-approved BSD License (the "License"); * see accompanying file BDS-LICENSE for details or see * . * * This software is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the License for more information. */ #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif static CCD_VEC3(__ccd_vec3_origin, CCD_ZERO, CCD_ZERO, CCD_ZERO); ccd_vec3_t *ccd_vec3_origin = &__ccd_vec3_origin; static ccd_vec3_t points_on_sphere[] = { CCD_VEC3_STATIC(CCD_REAL( 0.000000), CCD_REAL(-0.000000), CCD_REAL(-1.000000)), CCD_VEC3_STATIC(CCD_REAL( 0.723608), CCD_REAL(-0.525725), CCD_REAL(-0.447219)), CCD_VEC3_STATIC(CCD_REAL(-0.276388), CCD_REAL(-0.850649), CCD_REAL(-0.447219)), CCD_VEC3_STATIC(CCD_REAL(-0.894426), CCD_REAL(-0.000000), CCD_REAL(-0.447216)), CCD_VEC3_STATIC(CCD_REAL(-0.276388), CCD_REAL( 0.850649), CCD_REAL(-0.447220)), CCD_VEC3_STATIC(CCD_REAL( 0.723608), CCD_REAL( 0.525725), CCD_REAL(-0.447219)), CCD_VEC3_STATIC(CCD_REAL( 0.276388), CCD_REAL(-0.850649), CCD_REAL( 0.447220)), CCD_VEC3_STATIC(CCD_REAL(-0.723608), CCD_REAL(-0.525725), CCD_REAL( 0.447219)), CCD_VEC3_STATIC(CCD_REAL(-0.723608), CCD_REAL( 0.525725), CCD_REAL( 0.447219)), CCD_VEC3_STATIC(CCD_REAL( 0.276388), CCD_REAL( 0.850649), CCD_REAL( 0.447219)), CCD_VEC3_STATIC(CCD_REAL( 0.894426), CCD_REAL( 0.000000), CCD_REAL( 0.447216)), CCD_VEC3_STATIC(CCD_REAL(-0.000000), CCD_REAL( 0.000000), CCD_REAL( 1.000000)), CCD_VEC3_STATIC(CCD_REAL( 0.425323), CCD_REAL(-0.309011), CCD_REAL(-0.850654)), CCD_VEC3_STATIC(CCD_REAL(-0.162456), CCD_REAL(-0.499995), CCD_REAL(-0.850654)), CCD_VEC3_STATIC(CCD_REAL( 0.262869), CCD_REAL(-0.809012), CCD_REAL(-0.525738)), CCD_VEC3_STATIC(CCD_REAL( 0.425323), CCD_REAL( 0.309011), CCD_REAL(-0.850654)), CCD_VEC3_STATIC(CCD_REAL( 0.850648), CCD_REAL(-0.000000), CCD_REAL(-0.525736)), CCD_VEC3_STATIC(CCD_REAL(-0.525730), CCD_REAL(-0.000000), CCD_REAL(-0.850652)), CCD_VEC3_STATIC(CCD_REAL(-0.688190), CCD_REAL(-0.499997), CCD_REAL(-0.525736)), CCD_VEC3_STATIC(CCD_REAL(-0.162456), CCD_REAL( 0.499995), CCD_REAL(-0.850654)), CCD_VEC3_STATIC(CCD_REAL(-0.688190), CCD_REAL( 0.499997), CCD_REAL(-0.525736)), CCD_VEC3_STATIC(CCD_REAL( 0.262869), CCD_REAL( 0.809012), CCD_REAL(-0.525738)), CCD_VEC3_STATIC(CCD_REAL( 0.951058), CCD_REAL( 0.309013), CCD_REAL( 0.000000)), CCD_VEC3_STATIC(CCD_REAL( 0.951058), CCD_REAL(-0.309013), CCD_REAL( 0.000000)), CCD_VEC3_STATIC(CCD_REAL( 0.587786), CCD_REAL(-0.809017), CCD_REAL( 0.000000)), CCD_VEC3_STATIC(CCD_REAL( 0.000000), CCD_REAL(-1.000000), CCD_REAL( 0.000000)), CCD_VEC3_STATIC(CCD_REAL(-0.587786), CCD_REAL(-0.809017), CCD_REAL( 0.000000)), CCD_VEC3_STATIC(CCD_REAL(-0.951058), CCD_REAL(-0.309013), CCD_REAL(-0.000000)), CCD_VEC3_STATIC(CCD_REAL(-0.951058), CCD_REAL( 0.309013), CCD_REAL(-0.000000)), CCD_VEC3_STATIC(CCD_REAL(-0.587786), CCD_REAL( 0.809017), CCD_REAL(-0.000000)), CCD_VEC3_STATIC(CCD_REAL(-0.000000), CCD_REAL( 1.000000), CCD_REAL(-0.000000)), CCD_VEC3_STATIC(CCD_REAL( 0.587786), CCD_REAL( 0.809017), CCD_REAL(-0.000000)), CCD_VEC3_STATIC(CCD_REAL( 0.688190), CCD_REAL(-0.499997), CCD_REAL( 0.525736)), CCD_VEC3_STATIC(CCD_REAL(-0.262869), CCD_REAL(-0.809012), CCD_REAL( 0.525738)), CCD_VEC3_STATIC(CCD_REAL(-0.850648), CCD_REAL( 0.000000), CCD_REAL( 0.525736)), CCD_VEC3_STATIC(CCD_REAL(-0.262869), CCD_REAL( 0.809012), CCD_REAL( 0.525738)), CCD_VEC3_STATIC(CCD_REAL( 0.688190), CCD_REAL( 0.499997), CCD_REAL( 0.525736)), CCD_VEC3_STATIC(CCD_REAL( 0.525730), CCD_REAL( 0.000000), CCD_REAL( 0.850652)), CCD_VEC3_STATIC(CCD_REAL( 0.162456), CCD_REAL(-0.499995), CCD_REAL( 0.850654)), CCD_VEC3_STATIC(CCD_REAL(-0.425323), CCD_REAL(-0.309011), CCD_REAL( 0.850654)), CCD_VEC3_STATIC(CCD_REAL(-0.425323), CCD_REAL( 0.309011), CCD_REAL( 0.850654)), CCD_VEC3_STATIC(CCD_REAL( 0.162456), CCD_REAL( 0.499995), CCD_REAL( 0.850654)) }; ccd_vec3_t *ccd_points_on_sphere = points_on_sphere; size_t ccd_points_on_sphere_len = sizeof(points_on_sphere) / sizeof(ccd_vec3_t); _ccd_inline ccd_real_t __ccdVec3PointSegmentDist2(const ccd_vec3_t *P, const ccd_vec3_t *x0, const ccd_vec3_t *b, ccd_vec3_t *witness) { // The computation comes from solving equation of segment: // S(t) = x0 + t.d // where - x0 is initial point of segment // - d is direction of segment from x0 (|d| > 0) // - t belongs to <0, 1> interval // // Than, distance from a segment to some point P can be expressed: // D(t) = |x0 + t.d - P|^2 // which is distance from any point on segment. Minimization // of this function brings distance from P to segment. // Minimization of D(t) leads to simple quadratic equation that's // solving is straightforward. // // Bonus of this method is witness point for free. ccd_real_t dist, t; ccd_vec3_t d, a; // direction of segment ccdVec3Sub2(&d, b, x0); // precompute vector from P to x0 ccdVec3Sub2(&a, x0, P); t = -CCD_REAL(1.) * ccdVec3Dot(&a, &d); t /= ccdVec3Len2(&d); if (t < CCD_ZERO || ccdIsZero(t)){ dist = ccdVec3Dist2(x0, P); if (witness) ccdVec3Copy(witness, x0); }else if (t > CCD_ONE || ccdEq(t, CCD_ONE)){ dist = ccdVec3Dist2(b, P); if (witness) ccdVec3Copy(witness, b); }else{ if (witness){ ccdVec3Copy(witness, &d); ccdVec3Scale(witness, t); ccdVec3Add(witness, x0); dist = ccdVec3Dist2(witness, P); }else{ // recycling variables ccdVec3Scale(&d, t); ccdVec3Add(&d, &a); dist = ccdVec3Len2(&d); } } return dist; } ccd_real_t ccdVec3PointSegmentDist2(const ccd_vec3_t *P, const ccd_vec3_t *x0, const ccd_vec3_t *b, ccd_vec3_t *witness) { return __ccdVec3PointSegmentDist2(P, x0, b, witness); } ccd_real_t ccdVec3PointTriDist2(const ccd_vec3_t *P, const ccd_vec3_t *x0, const ccd_vec3_t *B, const ccd_vec3_t *C, ccd_vec3_t *witness) { // Computation comes from analytic expression for triangle (x0, B, C) // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and // Then equation for distance is: // D(s, t) = | T(s, t) - P |^2 // This leads to minimization of quadratic function of two variables. // The solution from is taken only if s is between 0 and 1, t is // between 0 and 1 and t + s < 1, otherwise distance from segment is // computed. ccd_vec3_t d1, d2, a; ccd_real_t u, v, w, p, q, r; ccd_real_t s, t, dist, dist2; ccd_vec3_t witness2; ccdVec3Sub2(&d1, B, x0); ccdVec3Sub2(&d2, C, x0); ccdVec3Sub2(&a, x0, P); u = ccdVec3Dot(&a, &a); v = ccdVec3Dot(&d1, &d1); w = ccdVec3Dot(&d2, &d2); p = ccdVec3Dot(&a, &d1); q = ccdVec3Dot(&a, &d2); r = ccdVec3Dot(&d1, &d2); s = (q * r - w * p) / (w * v - r * r); t = (-s * r - q) / w; if ((ccdIsZero(s) || s > CCD_ZERO) && (ccdEq(s, CCD_ONE) || s < CCD_ONE) && (ccdIsZero(t) || t > CCD_ZERO) && (ccdEq(t, CCD_ONE) || t < CCD_ONE) && (ccdEq(t + s, CCD_ONE) || t + s < CCD_ONE)){ if (witness){ ccdVec3Scale(&d1, s); ccdVec3Scale(&d2, t); ccdVec3Copy(witness, x0); ccdVec3Add(witness, &d1); ccdVec3Add(witness, &d2); dist = ccdVec3Dist2(witness, P); }else{ dist = s * s * v; dist += t * t * w; dist += CCD_REAL(2.) * s * t * r; dist += CCD_REAL(2.) * s * p; dist += CCD_REAL(2.) * t * q; dist += u; } }else{ dist = __ccdVec3PointSegmentDist2(P, x0, B, witness); dist2 = __ccdVec3PointSegmentDist2(P, x0, C, &witness2); if (dist2 < dist){ dist = dist2; if (witness) ccdVec3Copy(witness, &witness2); } dist2 = __ccdVec3PointSegmentDist2(P, B, C, &witness2); if (dist2 < dist){ dist = dist2; if (witness) ccdVec3Copy(witness, &witness2); } } return dist; } ode-0.14/m4/0000775000000000000000000000000012635012023011217 5ustar rootrootode-0.14/m4/pkg.m40000644000000000000000000001247312635011627012260 0ustar rootroot# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT]) ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .]) ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES ode-0.14/ode-config.in0000644000000000000000000000160512635011627013252 0ustar rootroot#!/bin/sh prefix=@prefix@ exec_prefix=@exec_prefix@ exec_prefix_set=no usage="\ Usage: ode-config [--prefix[=DIR]] [--exec-prefix[=DIR]] [--version] [--cflags] [--libs]" if test $# -eq 0; then echo "${usage}" 1>&2 exit 1 fi while test $# -gt 0; do case "$1" in -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac case $1 in --prefix=*) prefix=$optarg if test $exec_prefix_set = no ; then exec_prefix=$optarg fi ;; --prefix) echo $prefix ;; --exec-prefix=*) exec_prefix=$optarg exec_prefix_set=yes ;; --exec-prefix) echo $exec_prefix ;; --version) echo @ODE_VERSION@ ;; --cflags) echo -I@includedir@ ;; --libs) echo -L@libdir@ -lode ;; *) echo "${usage}" 1>&2 exit 1 ;; esac shift done ode-0.14/ode.pc.in0000644000000000000000000000037312635011627012411 0ustar rootrootprefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ precision=@ODE_PRECISION@ Name: ode Description: Open Dynamics Engine Version: @ODE_VERSION@ Libs: -L${libdir} -lode Libs.private: -lstdc++ -lm Cflags: -I${includedir} ode-0.14/ode/0000775000000000000000000000000012635012023011446 5ustar rootrootode-0.14/ode/Makefile.am0000644000000000000000000000011512635011627013506 0ustar rootrootSUBDIRS = src doc if ENABLE_DEMOS SUBDIRS += demo endif #EXTRA_DIST = doc ode-0.14/ode/README0000644000000000000000000001350312635011627012337 0ustar rootrootDynamics Library. ================= CONVENTIONS ----------- matrix storage -------------- matrix operations like factorization are expensive, so we must store the data in a way that is most useful to the matrix code. we want the ability to update the dynamics library without recompiling applications, e.g. so users can take advantage of new floating point hardware. so we must settle on a single format. because of the prevalence of 4-way SIMD, the format is this: store the matrix by rows or columns, and each column is rounded up to a multiple of 4 elements. the extra "padding" elements at the end of each row/column are set to 0. this is called the "standard format". to indicate if the data is stored by rows or columns, we will say "standard row format" or "standard column format". hopefully this decision will remain good in the future, as more and more processors have 4-way SIMD, and 3D graphics always needs fast 4x4 matrices. exception: matrices that have only one column or row (vectors), are always stored as consecutive elements in standard row format, i.e. there is no interior padding, only padding at the end. thus: all 3x1 floating point vectors are stored as 4x1 vectors: (x,x,x,0). also: all 6x1 spatial velocities and accelerations are split into 3x1 position and angular components, which are stored as contiguous 4x1 vectors. ALL matrices are stored by in standard row format. arguments --------- 3x1 vector arguments to set() functions are supplied as x,y,z. 3x1 vector result arguments to get() function are pointers to arrays. larger vectors are always supplied and returned as pointers. all coordinates are in the global frame except where otherwise specified. output-only arguments are usually supplied at the end. memory allocation ----------------- with many C/C++ libraries memory allocation is a difficult problem to solve. who allocates the memory? who frees it? must objects go on the heap or can they go on the stack or in static storage? to provide the maximum flexibility, the dynamics and collision libraries do not do their own memory allocation. you must pass in pointers to externally allocated chunks of the right sizes. the body, joint and colllision object structures are all exported, so you can make instances of those structure and pass pointers to them. there are helper functions which allocate objects out of areans, in case you need loots of dynamic creation and deletion. BUT!!! this ties us down to the body/joint/collision representation. a better approach is to supply custom memory allocation functions (e.g. dlAlloc() etc). C versus C++ ... ? ------------------ everything should be C linkable, and there should be C header files for everything. but we want to develop in C++. so do this: * all comments are "//". automatically convert to /**/ for distribution. * structures derived from other structures --> automatically convert? WORLDS ------ might want better terminology here. the dynamics world (DWorld) is a list of systems. each system corresponds to one or more bodies, or perhaps some other kinds of physical object. each system corresponds to one or more objects in the collision world (there does not have to be a one-to-one correspondence between bodies and collision objects). systems are simulated separately, perhaps using completely different techniques. we must do something special when systems collide. systems collide when collision objects belonging to system A touch collision objects belonging to system B. for each collision point, the system must provide matrix equation data that is used to compute collision forces. once those forces are computed, the system must incorporate the forces into its timestep. PROBLEM: what if we intertwine the LCP problems of the two systems - then this simple approach wont work. the dynamics world contains two kinds of objects: bodies and joints. joints connect two bodies together. the world contains one of more partitions. each partition is a collection of bodies and joints such that each body is attached (through one or more joints) to every other body. Joints ------ a joint can be connected to one or two bodies. if the joint is only connected to one body, joint.node[1].body == 0. joint.node[0].body is always valid. Linkage ------- this library will always be statically linked with the app, for these reasons: * collision space is selected at compile time, it adds data to the geom objects. Optimization ------------ doubles must be aligned on 8 byte boundaries! MinGW on Windows issues ----------------------- * the .rc file for drawstuff needs a different include, try winresrc.h. * it seems we can't have both main() and WinMain() without the entry point defaulting to main() and having resource loading problems. this screws up what i was trying to do in the drawstuff library. perhaps main2() ? * remember to compile resources to COFF format RES files. Collision --------- to plug in your own collision handling, replace (some of?) these functions with your own. collision should be a separate library that you can link in or not. your own library can call components in this collision library, e.g. if you want polymorphic spaces instead of a single statically called space. creating an object will automatically register the appropriate class (if necessary). how can we ensure that the minimum amount of code is linked in? e.g. only one space handler, and sphere-sphere and sphere-box and box-box collision code (if spheres and boxes instanced). the user creates a collision space, and for each dynamics object that is created a collision object is inserted into the space. the collision object's pos and R pointers are set to the corresponding dynamics variables. there should be utility functions which create the dynamics and collision objects at the same time, e.g. dMakeSphere(). collision objects and dynamics objects keep pointers to each other. ode-0.14/ode/TODO0000644000000000000000000006027712635011627012161 0ustar rootroot @@@'s TODO for COLLISION ------------------ box-box collision: adjust generated face-face contact points by depth/2 to be more fair. what happens when a GeomTransform's encapsulated object is manipulated, e.g. position changed. should this be disallowed? should a GeomTransform behave like a space and propagate dirtyness upwards? make sure that when we are using a large space for static environmental geoms, that there is not excessive AABB computation when geoms are added/removed from the space. the space AABB is pretty much guaranteed to cover everything, so there's no need to compute/test the AABB in this case. hash space: implement collide2() efficiently instead of the current simple-space-like brute-force approach. hash space: incremental scheme, so we dont have to rebuild the data structures for geoms that don't move. disabled geoms (remove from all collision considerations) ... isn't this the same as just taking it out of its enclosing group/space? integrate: dRay triangle collider - get latest tri collider code from erwin erwin's quadtree space tests: all aspects of collision API dGeomSetBody(0) maintains body-geom linked list properly. simple space: instantiate lots of non-moving geoms (i.e. environmental geoms and make sure that we're still able to collide efficiently. make sure AABB computation is efficient, or can be made efficient through proper use of the API. test C interface support for making new classes. make sure the dxGeom::aabbTest() function behaves as advertised. testing for contact point consistency: test for things that would cause the dynamics to fail or become unstable test for: small adjustment in geom position causes a big jump in the contact point set (bad for dynamics). test for: if contact constraints observed then it's impossible (or hard) to move the objects so that the penetration is increased. relax this when only a subset of the contact points are returned. test for consistency, e.g. the boundary of geoms X and Y can be defined by intersecting with a point, so test the intersection of X and Y by comparing with the point tests. check that contact points are in the collision volume all existing space tests, and more. demos: test_buggy: make a terrain out of non-moving geoms. use heirarchical groups to get efficient collision, even with the simple space. go though the new collision docs and make sure the behavior that is described there is actually implemented. multi-resolution hash table: the current implementation rebuilds a new hash table each time collide() is called. we don't keep any state between calls. this is wasteful if there are unmoving objects in the space. make sure we prevent multiple collision callbacks for the same pair better virtual address function. the collision search can perhaps be optimized - as we search chains we can come across other candidate intersections at other levels, perhaps we should do the intersection check straight away? --> save on list searching time only, which is not too significant. collision docs: optimization guide: whenever a single geom changes in a simple space, the space AABB has to be recomputed by examining EVERY geom. document this, or find a better behavior. TODO BEFORE NEXT RELEASE ------------------------ g++ needed for compiling tests using gcc 3.2 ? what is the problem? add joint feedback info from lambda, so that we can get motor forces etc. need a way to map constraint indexes to what they mean. track down and fix the occasional popping/jumping problem in test_boxstack, especially when boxes are piled on top of each other. find out if this is caused by a configuration singularity or whether there is a bug in LCP. i need to add some kind of diagnostic tool to help resolve these kinds of problems. fixup ground plane jitter and shadow jumping in drawstuff. the inertias/COMs don't appear to be totally correct for the boxstack demo. fix up, and add a mode that shows the effective mass box (for a given density). Improve box-box collision, especially for face-face contact (3 contact points). Improve cylinder-box collision (2 contact points). windows DLL building and unix shared libs. libtool? also MSVC project files. dBodyGetPointVel() contrib directory - all stuff in ~/3/ode functions to allow systems to be copied/cloned dBodyTransplant (b, world) dTransplantIsland (b, world) dBodyCopy (bdest, bsrc) dJointCopy (jdest, jsrc) -- what about body connections? dCloneBody() dCloneJoint() dCloseBodyAndJointList() dCloneIsland() this collision rule: // no contacts if both geoms on the same body, and the body is not 0 if (g1->body == g2->body && g1->body) return 0; needs to be replaced. sometimes we want no collision when both bodies are 0, but this wont work for geomgroup-to-environment. avoid stupid stuff like dGeomSetBody (geom_group, (dBodyID) 1); this also causes "failed-to-report" errors in the space test. Expose type-specific collision functions? Automatic code optimization process. joint limit spongyness: interacts with powered joints badly, because when the limit is reached full power is applied. fix or doc. various hinge2 functions may not function correctly if axis1 and axis2 are not perpendicular. in particular the getAngle() and getAngleRate() functions probably will give bogus answers. slow step function will not respect the joint getinfo2 functions calling addTorque() because it reads the force/torque accumulators before the getinfo2 functions are called. spaces need multiple lists of objects that can never overlap. objects in these lists are never tested against each other. deleting a body a joint is attached to should adjust the joint to only have one body attached. currently the connected joints have *both* their body attachments removed. BUT, dont do this if the dJOINT_TWOBODIES flag is set on the joint. document error, mem and math functions. Web pages credits section projects using ODE update C++ interface? use SWIG? collision exclusion groups - exclude if obj1.n == obj2.n ? make sure the amotor joint can be used with just one body. at the moment it only allows two-body attachments. implement dJointGetAMotorAngleRate() erwin says: Should the GeomGroup have a cleanupmode as the GeomTransform has? erwin says: http://q12.org/pipermail/ode/2002-January/000766.html and http://q12.org/pipermail/ode/2001-December/000753.html rename duplicate filenames (object.h?) - some environments can't handle this. naming inconsistency: dCreateSphere() should be dSphereCreate() (etc...) to match the rest of the API. TODO ---- joint allocation in joint groups. allocation size should be rounded up using dEFFICIENT_SIZE, to properly align all the data members. all dAlloc() allocations should be aligned using dEFFICIENT_SIZE() ??? automatic body & joint disabling / enabling. sometimes getting LCP infinite loops. function to get the entire island of bodies/joints joints: hinge2 joint - implement trail, i.e. non-convergent steering and wheel axes. erp individually settable for each joint? more joints: angular3 (constrian full angle not position) fixed path 1 (point must follow fixed path, etc etc) - other fixed path joints. linear a (point in 1 body fixed to plane of other) linear b (point in 1 body fixed to line on other) linear c (line in 1 body fixed to plane on other) linear d (line in 1 body fixed to line on other) - like prismatic but orientation along line can change Relative-Path-Relative-Oriention Joint (set all dofs of 2 bodies relative to each other) spring (with natural length) universal (2 kinds) various angular relationships when attaching joints to static env, provision to move attachment point (e.g. give it a linear/angular velocity). this can be used instead of a FPFO joint on a body in many cases. also do this with contacts to static env, to allow for contacts to *moving* objects in the static env. interpretation of erp: is it (1) the error reduction per timestep, (2) or a time constant independent of timestep?? if it's (2) then perhaps this should be universal - this is already the meaning for the suspension. hinge2 suspension: suspension limits suspension limit restitution and spongyness?? use autoconf? set paths in makefile? no-arg init functions, for andy explore: do joint parameters need to be set for the joint to be setup correctly, or should set some proper body-dependent params when it is attached? this is only really an issue for joints that have no parameters to set, such as the fixed joint. dAlloc() should take an arena parameters which is stored in dWorld. debugging mode should use dASSERT2 that prints a descriptive error message on error, not just the file:line or function. use dASSERT for internal consistency checking. when vectors and matrices are initialized, we must ensure that the padding elements are set to 0. this is going to be a problem everywhere! don't use 3-vectors anywhere. use SIMD friendly 4-vectors. make sure all data in body/joint etc objects is aligned well for single precision SIMD (i.e. all vectors start on a 16 byte boundary). think about more complicated uses of collision, e.g. a single geom representing an articulated structure. bodyGroup? (like joint group but for bodies). systemGroup? check the overhead of resizing Array<>s as elements are pushed on to them. replace alloca() with dPushFrame(), dPopFrame(), and dAlloca() ? allow for the possibility of allocating in non-stack memory ? make sure that we can set mass parameters with non-zero center of mass. if this is done after the body position is set, the position is adjusted. if this is done before the body position is set, what do we do when the pos is set? does the pos always refer to the center of mass from the user's point of view? consider splitting solver into functions, which can be optimized separately. might make things go faster. faster code for islands with a single body? faster code for dynamically symmetric bodies? rotation.cpp functions that set matrices should also set padding elements. lcp solver must return (L,d) and some other information, so we can re-solve for other right hand sides later on, but using the same complimentarity solution so there are no integrator discontinuities. dSetZero() - make fast inline functions for fixed n e.g. (1-4). need proper `sticky' friction, i.e. compensation for numerical slip. on windows, make sure gcc-compiles libs can be linked with VC++ apps. need to make sure some C++ runtime bits are present? kill all references to dArray<> (in geom.cpp). need testing code to test all joints with body-to-static-env copy stack.cpp, memory.cpp stuff to reuse dFactorLDLT() is not so efficient for matrix sizes < block size, e.g. redundant calls, zero loads, adds etc contacts: cheaper friction: viscous friction? one step delay friction force. in geom.cpp, for objects that are never meant to collide, dCollide() will always try to find the collider functions, which wastes a bit of time. geom.cpp:dCollideG() - handle special case of colliding 2 groups more efficiently. timer reporting function: void timerReport (void (*printFunction)(char *, ...)); disabled bodies stored in a separate list, so they are never traversed at all, for speed when there are many disabled bodies. MAYBE ----- new implementation for joint groups that is not so system dependent. maybe individual contacts are reusable? in this case contact information should be settable in the contact joints. max_size arg is really annoying. consider making anchor,axis, (everything) into a joint parameter and setting them with a consistent interface. also consider overload the joint functions so they are not distinguished by joint type?? collision memory optimizations? collision: support for persistent contact information? multiply reference tri list data so that it can be cloned if the tri-list geoms could support rot/pos transformations then we could have several tri-lists pointing to the same vertex information. height fields pre-converted collision data -- Creating a hash space and associated opcode tree structures may take significant amounts of time for a large world with many 10s of thousands of triangles. Any chance of pre-building that off-line and passing a memory block pointer to the collision system? putting objects in multiple spaces -- If it was possible to add objects to more than one space, you could do collision queries other than 1vsN and NvsN. That flexibility might be useful when you want to only collide against a subset of the space. For example, a camera system may want to collide some rays with occlusion walls but the occlusion walls may also need to be in the game-level space to bounce against. ALWAYS ------ make sure functions check their arguments in debug mode (e.g. using dASSERT). make sure joint/geom functions check for the specific object type. vectors alloca()ed on the stack must have the correct alignment, use ALLOCA16. library should have no global constructors, as it might be used with C linkage. use `const' in function arguments. blah. DON'T BOTHER ------------ warning if user tries to set mass params with nonzero center of mass. DONE ---- check: when contact attached with (body1,0) and (0,body1), check that polarity on depth and error info is okay for the two cases. set a better convention for which is the 1st and 2nd body in a joint, because sometimes we get things swapped (because of the way the joint nodes are used). hinge and prismatic, attachment to static environment. turn macros into C++ inline functions? what about C users? remove `space' argument to geom creation functions? make user add it? or just remove it from dCreateGeom() ? <-- did this one. test_chain should be in C, not C++. but first must remove global constructors. add more functionality to C++ interface - dMass, dSpace, dGeom there should be functions to delete groups of bodies/joints in one go - this will be more efficient than deleting them one at a time, because less partitioning tests will be needed. should we expose body and joint object structures so that the user can explicitly allocate them locally, or e.g. on the stack? makes allocating temporary contact constraints easier. NO --> helps data hiding and therefore library binary compatability. joints: hinge & slider - DONE measure angle, rate - DONE power - DONE joint limits - DONE mixed powered+limited joints, powering away from limit - DONE hinge2 - DONE steering angle and rate measurement - DONE steering limits - DONE steering motor - DONE wheel motor - DONE wheel angle rate measurement - DONE optional hinge2 suspension: - DONE alignment of B&S part to given axis - DONE global framework for giving epsilon and gamma - DONE toss away r-motor, make power & stuff specific to joint - DONE it's just easier that way joint code reuse: - DONE use standard functions to set velocity (c), limits (lo,hi), spongyness (epsilon) etc, this prevents these functions from proliferating implicit spring framework - actually allow joints to return a value `k' such that J*vnew = c + k*f, where f = force needed to achieve vnew - DONE contact slip - DONE contact erp & cfm parameters (not just "softness") - DONE hinge2: when we lock back wheels along the steering axis, there is no error correction if they get out of alignment - DONE, just use high and low limits. joint limit spongyness: erp and cfm for joint set from world (global) values when joint created. - DONE joint limit restitution - DONE check inertia transformations, e.g. by applying steering torque to a thin wheel --> actually, i made test_I more comprehensive random number comparisons between slow and fast methods. - random PD inertia (not just diagonal). - random velocity - random joint error (make joints then move bodies a bit) check that J*vnew=c (slow step already does this, but it doesn't equal zero for some reason! - actually, when LCP constraint limits are reached, it wont!) tons of things in lcp.cpp (@@@), especially speed optimizations. also, we wanted to do index block switching and index block updates to take advantage of the outer product trick ... but this is not worth the effort i think. lcp.cpp: if lo=hi=0, check operation. can we switch from NL <-> NH without going through C? --> done. andy says: still having trouble with those resource files.. drawstuff.res doesn't seem to build or be found under cygwin gcc. DOC how bodies and geoms associated then resolved in contact callback ... not really necessary. fix the "memory leak" in geom.cpp library should have no global constructors, as it might be used with C linkage. --> as long as test_chain1 works, there are none. DOC cfm, the derivation and what it means. --> partially done, could be better joint "get type" function andy says: in ode/src/error.cpp _snprintf() and _vsnprintf() are missing in testode: finite and isnan are missing. copysign is missing russ: okay here's the problem: i have Makefile.platform files for VC++, MinGW, but not Cygwin. Cygwin uses the unix-like functions for everything, but the VC++/MinGW configs assumes the MS C-runtime functions. this is easy to fix, except i need to install Cygwin which is a pain to do over MinGW. argh. build on linux - assumptions made about location of X11 lib, opengl etc. implement: dBodyAddForceAtPos,dBodyAddRelForceAtPos,dBodyAddRelForceAtRelPos, dBodyGetPointPos,dBodyGetPointVel,dBodyGetPointRelVel dJointAttach(), allow both bodies to be 0 to put the joint into limbo. space near-callback should be given potentially intersecting objects 100 at a time instead of 1 at a time, to save on calling costs ... which are trivial, so we don't bother to do this. doccer: @func{} also refs second etc function in function *list*. make sure joints can return 0 from GetInfo1, i.e. no constraints or "inactive" joint, and the step functions will handle it. when attaching contact with (0,body), instead of setting the reverse flag on the joint and checking it in getInfo2(), we should just reverse the normal straight away ... ? --> trouble is, dJointAttach() knows nothing about what kind of joint it is attaching. hinge2 needs to be attached to two bodies for it to work, make sure this is always the case. --> assertion added in dJointAttach(). if two joints connect to the same two bodies, check that the fast solver works! -> it should. functions to get all the joints/bodies a body/joint is connected to. If I don't have the GCC libraries installed, HUGE_VALF is undefined. fix capped cylinder - capped cylinder collision so that two contacts can be generated. transformation geometry object. joint groups should also be destroyed by destroying the world --> naaahhh. DONT DO THIS: body/joint creators with world = 0 --> not inserted into any world. allow bodies/joints to be detached from a world (this is what happens to grouped joints when a world is destroyed). can bodies and joints be linked together when not attached to world?? what happens when we have an island of b/j, some of which are not in world? soln: dont keep lists of b/j in the world, just infer it from the islands? body & joint disabling / enabling start a change log. collision flags - 0xffff mask. dBodyGetFiniteRotationMode() / ...Axis() dBodyAddForceAtRelPos() ball & socket joint limits and motors. auto-build env on windows: 3 compilers, debug/release, short/double = 12 combinations --> auto logs. handle infinities better: HUGE_VALF is not commanly defined, it seems. get rid of the __USE_ISOC9X macro in common.h perhaps just use a "big" number instead of the actual IEEE infinity, it's more portable anyway. --> new config system dCloseODE() - tidy up *all* allocated memory, esp in geom.cpp. used to keep leak detectors happy. extra API to get lambda and J'*lambda from last timestep. better stack implementation that is not so system dependent. but how will we do dynamic page allocation? do we even need to? all collision files will now be collision_*, not geom_* check exported global symbols - no C++ mangling. rename dSphere etc to dxSphere etc. C interface support for making new classes. make sure DLL-ized stuff preserved ... but class numbers should no longer be exported. point geom ( = sphere of radius 0 ) geoms stored in doubly linked lists in space (fast removal). bodies need to keep geoms pointers and call dGeomMoved() in dBodySetPosition() etc and world step. PROBLEM: links dynamics and collision together too much, makes it hard to extract ODE collision ... unless we say: dGeomMoved() and dGeomID must be supplied by the new collision library! dCollide() should take spaces as arguments - it should call dSpaceCollide2() with its own callback that puts all found contacts in the array, stopping when there is no more space left in the array. dxSpace::getGeom() - the geom numbers will change as geoms are dirtied - find some other numbering scheme, or document this behavior. the 'placeable' property - objects that should not ever be attached to bodies should flag an error when setBody etc are called. dGeomSetBody(0) - DOC: the position and orientation of the body will be preserved. in this case the geom should NOT be dirtied (dGeomMoved() should not be called). DOC: dGeomGetBodyNext() as part of dynamics/collision interface groups/spaces are subclasses of geom. groups/spaces can contain other groups/spaces. geom can be owned by a group/space. collision handling: geom-geom : standard collision function geom-group : special space code group-group : n^2 tests (or n space tests) - hard to optimize because of disjoint space representations. group internal : normal space internal-collision code groups/spaces can be told that some objects never move, i.e. that the objects are locked. should we lock the whole space? locking: the AABB for the object is not recalculated groups/spaces can be told that the internal contents self-intersect or not. actually an old ODE group is the equivalent of an old ODE simple space. - just call dCollide() or not. the group doesn't get passed to the space callback any more ... only the intersecting geoms get passed? maybe the callback can initiate the extra intersection tests itself? (because we want programmable flexibility to determine what gets intersected and what doesn't) - NO infrastructure to indicate when an object has moved (and thus its AABB needs to be recalculated) space enumeration functions. make sure that there are no additions or deletions while enumeration is taking place. - documented the behavior, didn't disallow it cache the AABB in the dxGeom? (for non-moving objects) - perhaps keep a pointer to separately allocated space? ... no DOC: dGeomGetClass() is a first-class geom function, not in the "User defined classes" section. it returns a constant that can be checked against dSphereClass etc. remove dxGeom dependence on dBodyID? ... not yet dBase -> dxBase allow a geom to be inserted into multiple spaces? need this to optimize some kinds of tests ... no update docs. make CHECK_NOT_LOCKED an assert. DOC: "Calling these functions on a non-placeable geom results in a runtime error." ...in the debug build only? non-placeable geoms should not allocate dxPosR. perhaps pass a dGeom constructor arg that says 'placeable' or not - this also sets the GEOM_PLACEABLE flag. GeomTransform: final_pos and final_R valid if no GEOM_AABB_BAD flag!!! fix up this code, esp use of ComputeTX(). Space incompatibilities: no dSpaceDestroy(), dGeomDestroy() does not take a dSpaceID ... dSpaceDestroy() added. GeomGroup incompatibilities: dCollide() used to take a GeomGroup and would return all the contact points for all the intersecting objects. now you have to call dSpaceCollide2() and get a callback for each one. need to provide old behavior. simple space optimization: we should keep the precomputed AABB for the non-moving geoms around, so that when the other geoms move we can just compute the AABBs for those geoms and then combine it with the non-moving AABB. --> too hard! collision build options: old and new tidyups for collision: * rationalize what stuff goes in what source files, and file names * minimize set of header files that all collision* sources use - after all changes. * update ode-cpp stuff (C++ interface header files). porting guide: ODE list email dGeomGetSpaceAABB() deleted dGeomGetClass (geom_group); used to return a unique type for GeomGroups, but now it returns dSimpleSpaceID. tidyups: update DLL declarations. ode-0.14/ode/demo/0000775000000000000000000000000012635012023012372 5ustar rootrootode-0.14/ode/demo/Makefile.am0000644000000000000000000000405012635011627014434 0ustar rootrootAM_CPPFLAGS = -I$(top_srcdir)/include \ -I$(top_builddir)/include \ -DDRAWSTUFF_TEXTURE_PATH="\"$(abs_top_srcdir)/drawstuff/textures\"" if X11 AM_LDFLAGS = $(X_PRE_LIBS) $(X_LIBS) $(X_EXTRA_LIBS) endif # On Windows, GL_LIBS must go after libdrawstuff.la. LDADD = $(top_builddir)/drawstuff/src/libdrawstuff.la \ $(top_builddir)/ode/src/libode.la @GL_LIBS@ noinst_HEADERS = basket_geom.h texturepath.h world_geom3.h bunny_geom.h convex_bunny_geom.h \ icosahedron_geom.h AM_DEFAULT_SOURCE_EXT = .cpp noinst_PROGRAMS = \ demo_boxstack \ demo_buggy \ demo_cards \ demo_chain1 \ demo_chain2 \ demo_collision \ demo_crash \ demo_cylvssphere \ demo_dball \ demo_dhinge \ demo_transmission \ demo_feedback \ demo_friction \ demo_gyroscopic \ demo_gyro2 \ demo_heightfield \ demo_hinge \ demo_I \ demo_jointPR \ demo_joints \ demo_jointPU \ demo_kinematic \ demo_motion \ demo_motor \ demo_ode \ demo_piston \ demo_plane2d \ demo_rfriction \ demo_slider \ demo_space \ demo_space_stress \ demo_step \ demo_tracks demo_chain1_SOURCES = demo_chain1.c demo_chain1_LDADD = $(LDADD) -lstdc++ if TRIMESH noinst_PROGRAMS += \ demo_basket \ demo_cyl \ demo_moving_trimesh \ demo_moving_convex \ demo_trimesh AM_CPPFLAGS += -DdTRIMESH_ENABLED endif if WIN32 resources.o: $(top_srcdir)/drawstuff/src/resources.rc $(top_srcdir)/drawstuff/src/resource.h @WINDRES@ $(top_srcdir)/drawstuff/src/resources.rc -o resources.o LDADD += resources.o endif ode-0.14/ode/demo/basket_geom.h0000644000000000000000000005104112635011627015033 0ustar rootroot static float world_normals[] = { 0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,-0.948064f,0.318080f,0,-0.989482f,0.144655f,0,-0.983494f,0.180939f,0,-0.983494f,0.180939f,0,-0.908999f,0.416798f,0,-0.948064f,0.318080f,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,-0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-0.132460f,0.991188f,0,0.264920f,0.964270f,0,0.132460f,0.991188f,0,0.132460f,0.991188f,0,-0.264920f,0.964270f,0,-0.132460f,0.991188f,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-0.687592f,-0.726097f,-0,-0.881727f,-0.471761f,0,-0.687592f,-0.726097f,-0,-0.881727f,-0.471761f,0,-0.881727f,-0.471761f,0,-0.687592f,-0.726097f,-0,0.687592f,-0.726097f,0,0.928375f,-0.371644f,0,0.824321f,-0.566123f,0,0.687592f,-0.726097f,0,0.824321f,-0.566123f,0,0.687592f,-0.726097f,0,-0.881727f,-0.471761f,0,-0.985594f,-0.169128f,0,-0.985594f,-0.169128f,0,-0.985594f,-0.169128f,0,-0.881727f,-0.471761f,0,-0.881727f,-0.471761f,0,0.928375f,-0.371644f,0,0.985594f,-0.169128f,0,0.985594f,-0.169128f,0,0.928375f,-0.371644f,0,0.985594f,-0.169128f,0,0.824321f,-0.566123f,0,-0.870167f,0.492758f,0,-0.870167f,0.492758f,0,-0.870167f,0.492758f,0,-0.870167f,0.492758f,0,-0.870167f,0.492758f,0,-0.870167f,0.492758f,0,0.870167f,0.492758f,0,0.870167f,0.492758f,0,0.870167f,0.492758f,0,0.870167f,0.492758f,0,0.870167f,0.492758f,0,0.870167f,0.492758f,-0,-0.390313f,0.920682f,0,-0.132460f,0.991188f,0,-0.264920f,0.964270f,0,-0.264920f,0.964270f,0,-0.390313f,0.920682f,0,-0.390313f,0.920682f,0,0.390313f,0.920682f,0,0.132460f,0.991188f,0,0.264920f,0.964270f,0,0.390313f,0.920682f,0,0.264920f,0.964270f,0,0.390313f,0.920682f,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0.985594f,0.169128f,0,0.824321f,0.566123f,0,0.928375f,0.371644f,0,0.928375f,0.371644f,0,0.985594f,0.169128f,0,0.985594f,0.169128f,0,0.824321f,0.566123f,0,0.687592f,0.726097f,0,0.687592f,0.726097f,0,0.687592f,0.726097f,0,0.928375f,0.371644f,0,0.824321f,0.566123f,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0.687592f,0.726097f,0,-0.687592f,0.726097f,0,-0.881727f,0.471761f,0,-0.881727f,0.471761f,0,-0.881727f,0.471761f,0,-0.687592f,0.726097f,0,-0.881727f,0.471761f,0,-0.985594f,0.169128f,0,-0.985594f,0.169128f,0,-0.985594f,0.169128f,0,-0.881727f,0.471761f,0,-0.881727f,0.471761f,0,-0.870166f,-0.492758f,0,-0.870166f,-0.492758f,0,-0.870166f,-0.492758f,0,-0.870166f,-0.492758f,0,-0.870166f,-0.492758f,0,-0.870166f,-0.492758f,0,-0.390314f,-0.920682f,0,-0.132460f,-0.991188f,0,-0.264921f,-0.964270f,0,-0.264921f,-0.964270f,0,-0.390314f,-0.920682f,0,-0.390314f,-0.920682f,0,-0.132460f,-0.991188f,0,0.264921f,-0.964270f,0,0.132460f,-0.991188f,0,0.132460f,-0.991188f,0,-0.264921f,-0.964270f,0,-0.132460f,-0.991188f,0,0.264921f,-0.964270f,0,0.390314f,-0.920682f,0,0.390314f,-0.920682f,0,0.390314f,-0.920682f,0,0.132460f,-0.991188f,0,0.264921f,-0.964270f,0,0.870166f,-0.492758f,0,0.870166f,-0.492758f,0,0.870166f,-0.492758f,0,0.870166f,-0.492758f,0,0.870166f,-0.492758f,0,0.870166f,-0.492758f,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0.527606f,0.849489f,0,-0.793893f,0.608057f,0,-0.715135f,0.698986f,0,-0.715135f,0.698986f,0,-0.418249f,0.908332f,0,-0.527606f,0.849489f,0,-0.075284f,0.997162f,0,-0.253577f,0.967315f,0,-0.202069f,0.979371f,0,-0.202069f,0.979371f,0,-0.075284f,0.997162f,0,-0.075284f,0.997162f,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0.160137f,0.987095f,0,0.049305f,0.998784f,0,0.049305f,0.998784f,0,0.049305f,0.998784f,0,0.221401f,0.975183f,0,0.160137f,0.987095f,0,0.696124f,0.717921f,0,0.696124f,0.717921f,0,0.433340f,0.901230f,0,0.433340f,0.901230f,0,0.433340f,0.901230f,0,0.696124f,0.717921f,0,0.696124f,0.717921f,0,0.696124f,0.717921f,0,0.838308f,0.545197f,0,0.696124f,0.717921f,0,0.872167f,0.489208f,0,0.838308f,0.545197f,0,-0.994126f,0.108225f,0,-0.983494f,0.180939f,0,-0.989482f,0.144655f,0,-0.994126f,0.108225f,0,-0.989482f,0.144655f,0,-0.994126f,0.108225f,0,-0.948064f,0.318080f,0,-0.908999f,0.416798f,0,-0.793893f,0.608057f,0,-0.908999f,0.416798f,0,-0.715135f,0.698986f,0,-0.793893f,0.608057f,0,-0.527606f,0.849489f,0,-0.418249f,0.908332f,0,-0.253577f,0.967315f,0,-0.418249f,0.908332f,0,-0.202069f,0.979371f,0,-0.253577f,0.967315f,0,-0.075284f,0.997162f,0,-0.075284f,0.997162f,0,0,1,0,-0.075284f,0.997162f,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0.049305f,0.998784f,0,0,1,0,0.049305f,0.998784f,0,0.049305f,0.998784f,0,0.160137f,0.987095f,0,0.221401f,0.975183f,0,0.433340f,0.901230f,0,0.221401f,0.975183f,0,0.433340f,0.901230f,0,0.433340f,0.901230f,0,0.902172f,0.431376f,0,0.838308f,0.545197f,0,0.872167f,0.489208f,0,0.872167f,0.489208f,0,0.902172f,0.431376f,0,0.902172f,0.431376f, }; static float world_vertices[] = { -4,-4,-0.100000f,4,-4,-0.100000f,4,-4,0.100000f,-4,-4,-0.100000f,4,-4,0.100000f,-4,-4,0.100000f,4,0,0.100000f,4,-4,-0.100000f,4,4,-0.100000f,4,0,0.100000f,4,4,-0.100000f,4,4,0.100000f,4,0,0.100000f,4,-4,0.100000f,4,-4,-0.100000f,-4,-4,-0.100000f,-4,4,-0.100000f,4,4,-0.100000f,-4,-4,-0.100000f,4,4,-0.100000f,4,-4,-0.100000f,0.066000f,-2.060000f,2,0.066000f,-1.940000f,2,-0.066000f,-2.060000f,2,0.066000f,-1.940000f,2,-0.066000f,-1.940000f,2,-0.066000f,-2.060000f,2,-4,4,0.100000f,4,4,0.100000f,4,4,-0.100000f,4,4,-0.100000f,-4,4,-0.100000f,-4,4,0.100000f,-4,-4,0.100000f,-4,0,0.100000f,-4,-4,-0.100000f,-4,0,0.100000f,-4,4,0.100000f,-4,4,-0.100000f,-4,0,0.100000f,-4,4,-0.100000f,-4,-4,-0.100000f,0.360000f,3.244444f,1.466974f,0.360000f,3.422222f,2.266974f,-0.360000f,3.422222f,2.266974f,-0.360000f,3.422222f,2.266974f,-0.360000f,3.244444f,1.466974f,0.360000f,3.244444f,1.466974f,4,-4,0.100000f,0.066000f,-2.060000f,0.100000f,-0.066000f,-2.060000f,0.100000f,-0.066000f,-2.060000f,0.100000f,-4,-4,0.100000f,4,-4,0.100000f,4,0,0.100000f,0.066000f,-1.940000f,0.100000f,4,-4,0.100000f,0.066000f,-1.940000f,0.100000f,0.066000f,-2.060000f,0.100000f,4,-4,0.100000f,-0.066000f,-1.940000f,0.100000f,0.066000f,-1.940000f,0.100000f,4,0,0.100000f,4,0,0.100000f,-4,0,0.100000f,-0.066000f,-1.940000f,0.100000f,-0.066000f,-2.060000f,0.100000f,-0.066000f,-1.940000f,0.100000f,-4,0,0.100000f,-4,0,0.100000f,-4,-4,0.100000f,-0.066000f,-2.060000f,0.100000f,0.066000f,-2.060000f,2,-0.066000f,-2.060000f,2,-0.066000f,-2.060000f,0.100000f,-0.066000f,-2.060000f,0.100000f,0.066000f,-2.060000f,0.100000f,0.066000f,-2.060000f,2,0.066000f,-1.940000f,1.950000f,0.066000f,-1.940000f,2,0.066000f,-2.060000f,2,0.066000f,-2.060000f,2,0.066000f,-2.060000f,0.100000f,0.066000f,-1.940000f,1.950000f,0.066000f,-2.060000f,0.100000f,0.066000f,-1.940000f,0.100000f,0.066000f,-1.940000f,1.950000f,-0.052853f,-1.506390f,2,0.052853f,-1.506390f,2,0.052853f,-1.506390f,1.950000f,0.052853f,-1.506390f,1.950000f,-0.052853f,-1.506390f,1.950000f,-0.052853f,-1.506390f,2,-0.066000f,-2.060000f,0.100000f,-0.066000f,-2.060000f,2,-0.066000f,-1.940000f,1.950000f,-0.066000f,-2.060000f,0.100000f,-0.066000f,-1.940000f,1.950000f,-0.066000f,-1.940000f,0.100000f,-0.066000f,-2.060000f,2,-0.066000f,-1.940000f,2,-0.066000f,-1.940000f,1.950000f,-0.066000f,-1.940000f,0.100000f,-0.066000f,-1.940000f,1.950000f,0.066000f,-1.940000f,1.950000f,-0.066000f,-1.940000f,0.100000f,0.066000f,-1.940000f,1.950000f,0.066000f,-1.940000f,0.100000f,-0.066000f,-1.940000f,1.950000f,-0.066000f,-1.840000f,1.950000f,0.066000f,-1.940000f,1.950000f,-0.066000f,-1.840000f,1.950000f,0.066000f,-1.840000f,1.950000f,0.066000f,-1.940000f,1.950000f,-0.066000f,-1.940000f,2,-0.066000f,-1.840000f,2,-0.066000f,-1.840000f,1.950000f,-0.066000f,-1.840000f,1.950000f,-0.066000f,-1.940000f,1.950000f,-0.066000f,-1.940000f,2,0.066000f,-1.940000f,2,0.066000f,-1.840000f,2,-0.066000f,-1.940000f,2,0.066000f,-1.840000f,2,-0.066000f,-1.840000f,2,-0.066000f,-1.940000f,2,0.066000f,-1.940000f,1.950000f,0.066000f,-1.840000f,1.950000f,0.066000f,-1.840000f,2,0.066000f,-1.940000f,1.950000f,0.066000f,-1.840000f,2,0.066000f,-1.940000f,2,-0.066000f,-1.840000f,2,-0.171600f,-1.740000f,2,-0.066000f,-1.840000f,1.950000f,-0.171600f,-1.740000f,2,-0.171600f,-1.740000f,1.950000f,-0.066000f,-1.840000f,1.950000f,0.066000f,-1.840000f,1.950000f,0.171600f,-1.740000f,1.950000f,0.171600f,-1.740000f,2,0.066000f,-1.840000f,1.950000f,0.171600f,-1.740000f,2,0.066000f,-1.840000f,2,-0.171600f,-1.740000f,2,-0.188760f,-1.640000f,2,-0.188760f,-1.640000f,1.950000f,-0.188760f,-1.640000f,1.950000f,-0.171600f,-1.740000f,1.950000f,-0.171600f,-1.740000f,2,0.171600f,-1.740000f,1.950000f,0.188760f,-1.640000f,1.950000f,0.188760f,-1.640000f,2,0.171600f,-1.740000f,1.950000f,0.188760f,-1.640000f,2,0.171600f,-1.740000f,2,-0.188760f,-1.640000f,2,-0.132132f,-1.540000f,2,-0.132132f,-1.540000f,1.950000f,-0.132132f,-1.540000f,1.950000f,-0.188760f,-1.640000f,1.950000f,-0.188760f,-1.640000f,2,0.188760f,-1.640000f,1.950000f,0.132132f,-1.540000f,1.950000f,0.132132f,-1.540000f,2,0.188760f,-1.640000f,1.950000f,0.132132f,-1.540000f,2,0.188760f,-1.640000f,2,-0.132132f,-1.540000f,2,-0.052853f,-1.506390f,2,-0.052853f,-1.506390f,1.950000f,-0.052853f,-1.506390f,1.950000f,-0.132132f,-1.540000f,1.950000f,-0.132132f,-1.540000f,2,0.132132f,-1.540000f,1.950000f,0.052853f,-1.506390f,1.950000f,0.052853f,-1.506390f,2,0.132132f,-1.540000f,1.950000f,0.052853f,-1.506390f,2,0.132132f,-1.540000f,2,0.188760f,-1.640000f,1.950000f,0.173397f,-1.642679f,1.950000f,0.121808f,-1.551577f,1.950000f,0.121808f,-1.551577f,1.950000f,0.132132f,-1.540000f,1.950000f,0.188760f,-1.640000f,1.950000f,0.171600f,-1.740000f,1.950000f,0.157950f,-1.732697f,1.950000f,0.173397f,-1.642679f,1.950000f,0.171600f,-1.740000f,1.950000f,0.173397f,-1.642679f,1.950000f,0.188760f,-1.640000f,1.950000f,0.171600f,-1.740000f,1.950000f,0.066000f,-1.840000f,1.950000f,0.060149f,-1.825311f,1.950000f,0.171600f,-1.740000f,1.950000f,0.060149f,-1.825311f,1.950000f,0.157950f,-1.732697f,1.950000f,-0.066000f,-1.840000f,1.950000f,-0.060149f,-1.825311f,1.950000f,0.066000f,-1.840000f,1.950000f,-0.060149f,-1.825311f,1.950000f,0.060149f,-1.825311f,1.950000f,0.066000f,-1.840000f,1.950000f,-0.171600f,-1.740000f,1.950000f,-0.157950f,-1.732697f,1.950000f,-0.060149f,-1.825311f,1.950000f,-0.171600f,-1.740000f,1.950000f,-0.060149f,-1.825311f,1.950000f,-0.066000f,-1.840000f,1.950000f,-0.173397f,-1.642679f,1.950000f,-0.157950f,-1.732697f,1.950000f,-0.171600f,-1.740000f,1.950000f,-0.171600f,-1.740000f,1.950000f,-0.188760f,-1.640000f,1.950000f,-0.173397f,-1.642679f,1.950000f,-0.121808f,-1.551577f,1.950000f,-0.173397f,-1.642679f,1.950000f,-0.188760f,-1.640000f,1.950000f,-0.188760f,-1.640000f,1.950000f,-0.132132f,-1.540000f,1.950000f,-0.121808f,-1.551577f,1.950000f,-0.052853f,-1.506390f,1.950000f,-0.049868f,-1.521079f,1.950000f,-0.121808f,-1.551577f,1.950000f,-0.052853f,-1.506390f,1.950000f,-0.121808f,-1.551577f,1.950000f,-0.132132f,-1.540000f,1.950000f,0.049868f,-1.521079f,1.950000f,-0.049868f,-1.521079f,1.950000f,-0.052853f,-1.506390f,1.950000f,-0.052853f,-1.506390f,1.950000f,0.052853f,-1.506390f,1.950000f,0.049868f,-1.521079f,1.950000f,0.052853f,-1.506390f,1.950000f,0.132132f,-1.540000f,1.950000f,0.121808f,-1.551577f,1.950000f,0.052853f,-1.506390f,1.950000f,0.121808f,-1.551577f,1.950000f,0.049868f,-1.521079f,1.950000f,-0.188760f,-1.640000f,2,-0.173397f,-1.642679f,2,-0.121808f,-1.551577f,2,-0.121808f,-1.551577f,2,-0.132132f,-1.540000f,2,-0.188760f,-1.640000f,2,-0.171600f,-1.740000f,2,-0.157950f,-1.732697f,2,-0.173397f,-1.642679f,2,-0.173397f,-1.642679f,2,-0.188760f,-1.640000f,2,-0.171600f,-1.740000f,2,-0.066000f,-1.840000f,2,-0.060149f,-1.825311f,2,-0.171600f,-1.740000f,2,-0.060149f,-1.825311f,2,-0.157950f,-1.732697f,2,-0.171600f,-1.740000f,2,0.066000f,-1.840000f,2,0.060149f,-1.825311f,2,-0.066000f,-1.840000f,2,0.060149f,-1.825311f,2,-0.060149f,-1.825311f,2,-0.066000f,-1.840000f,2,0.171600f,-1.740000f,2,0.157950f,-1.732697f,2,0.060149f,-1.825311f,2,0.171600f,-1.740000f,2,0.060149f,-1.825311f,2,0.066000f,-1.840000f,2,0.173397f,-1.642679f,2,0.157950f,-1.732697f,2,0.171600f,-1.740000f,2,0.171600f,-1.740000f,2,0.188760f,-1.640000f,2,0.173397f,-1.642679f,2,0.121808f,-1.551577f,2,0.173397f,-1.642679f,2,0.188760f,-1.640000f,2,0.188760f,-1.640000f,2,0.132132f,-1.540000f,2,0.121808f,-1.551577f,2,0.052853f,-1.506390f,2,0.049868f,-1.521079f,2,0.121808f,-1.551577f,2,0.052853f,-1.506390f,2,0.121808f,-1.551577f,2,0.132132f,-1.540000f,2,-0.049868f,-1.521079f,2,0.049868f,-1.521079f,2,0.052853f,-1.506390f,2,0.052853f,-1.506390f,2,-0.052853f,-1.506390f,2,-0.049868f,-1.521079f,2,-0.121808f,-1.551577f,2,-0.049868f,-1.521079f,2,-0.052853f,-1.506390f,2,-0.052853f,-1.506390f,2,-0.132132f,-1.540000f,2,-0.121808f,-1.551577f,2,-0.173397f,-1.642679f,2,-0.157950f,-1.732697f,2,-0.157950f,-1.732697f,1.950000f,-0.157950f,-1.732697f,1.950000f,-0.173397f,-1.642679f,1.950000f,-0.173397f,-1.642679f,2,-0.157950f,-1.732697f,2,-0.060149f,-1.825311f,2,-0.060149f,-1.825311f,1.950000f,-0.060149f,-1.825311f,1.950000f,-0.157950f,-1.732697f,1.950000f,-0.157950f,-1.732697f,2,-0.060149f,-1.825311f,2,0.060149f,-1.825311f,2,0.060149f,-1.825311f,1.950000f,0.060149f,-1.825311f,1.950000f,-0.060149f,-1.825311f,1.950000f,-0.060149f,-1.825311f,2,0.060149f,-1.825311f,1.950000f,0.060149f,-1.825311f,2,0.157950f,-1.732697f,2,0.157950f,-1.732697f,2,0.157950f,-1.732697f,1.950000f,0.060149f,-1.825311f,1.950000f,0.157950f,-1.732697f,2,0.173397f,-1.642679f,2,0.173397f,-1.642679f,1.950000f,0.173397f,-1.642679f,1.950000f,0.157950f,-1.732697f,1.950000f,0.157950f,-1.732697f,2,0.173397f,-1.642679f,2,0.121808f,-1.551577f,2,0.121808f,-1.551577f,1.950000f,0.121808f,-1.551577f,1.950000f,0.173397f,-1.642679f,1.950000f,0.173397f,-1.642679f,2,0.121808f,-1.551577f,2,0.049868f,-1.521079f,2,0.049868f,-1.521079f,1.950000f,0.049868f,-1.521079f,1.950000f,0.121808f,-1.551577f,1.950000f,0.121808f,-1.551577f,2,0.049868f,-1.521079f,2,-0.049868f,-1.521079f,2,-0.049868f,-1.521079f,1.950000f,-0.049868f,-1.521079f,1.950000f,0.049868f,-1.521079f,1.950000f,0.049868f,-1.521079f,2,-0.049868f,-1.521079f,2,-0.121808f,-1.551577f,2,-0.121808f,-1.551577f,1.950000f,-0.121808f,-1.551577f,1.950000f,-0.049868f,-1.521079f,1.950000f,-0.049868f,-1.521079f,2,-0.121808f,-1.551577f,2,-0.173397f,-1.642679f,2,-0.173397f,-1.642679f,1.950000f,-0.173397f,-1.642679f,1.950000f,-0.121808f,-1.551577f,1.950000f,-0.121808f,-1.551577f,2,-0.360000f,3.600000f,0.100000f,0.360000f,3.600000f,0.100000f,4,4,0.100000f,4,4,0.100000f,-4,4,0.100000f,-0.360000f,3.600000f,0.100000f,-0.360000f,0.400000f,0.100000f,-0.360000f,3.600000f,0.100000f,-4,4,0.100000f,-4,4,0.100000f,-4,0,0.100000f,-0.360000f,0.400000f,0.100000f,4,0,0.100000f,0.360000f,0.400000f,0.100000f,-0.360000f,0.400000f,0.100000f,-0.360000f,0.400000f,0.100000f,-4,0,0.100000f,4,0,0.100000f,4,4,0.100000f,0.360000f,3.600000f,0.100000f,4,0,0.100000f,0.360000f,3.600000f,0.100000f,0.360000f,0.400000f,0.100000f,4,0,0.100000f,0.360000f,2.888889f,1.023752f,0.360000f,3.066667f,1.166974f,-0.360000f,3.066667f,1.166974f,-0.360000f,3.066667f,1.166974f,-0.360000f,2.888889f,1.023752f,0.360000f,2.888889f,1.023752f,0.360000f,2.533333f,0.939976f,0.360000f,2.711111f,0.966974f,-0.360000f,2.711111f,0.966974f,-0.360000f,2.711111f,0.966974f,-0.360000f,2.533333f,0.939976f,0.360000f,2.533333f,0.939976f,-0.360000f,2.177778f,0.939976f,0.360000f,2.177778f,0.939976f,0.360000f,2.355556f,0.939976f,0.360000f,2.355556f,0.939976f,-0.360000f,2.355556f,0.939976f,-0.360000f,2.177778f,0.939976f,-0.360000f,1.822222f,0.939976f,0.360000f,1.822222f,0.939976f,0.360000f,2,0.939976f,0.360000f,2,0.939976f,-0.360000f,2,0.939976f,-0.360000f,1.822222f,0.939976f,-0.360000f,1.466667f,0.939976f,0.360000f,1.466667f,0.939976f,0.360000f,1.644444f,0.939976f,0.360000f,1.644444f,0.939976f,-0.360000f,1.644444f,0.939976f,-0.360000f,1.466667f,0.939976f,0.360000f,1.111111f,0.957571f,0.360000f,1.288889f,0.939976f,-0.360000f,1.288889f,0.939976f,-0.360000f,1.288889f,0.939976f,-0.360000f,1.111111f,0.957571f,0.360000f,1.111111f,0.957571f,-0.360000f,0.755556f,1.134246f,0.360000f,0.755556f,1.134246f,0.360000f,0.933333f,1.009739f,0.360000f,0.933333f,1.009739f,-0.360000f,0.933333f,1.009739f,-0.360000f,0.755556f,1.134246f,0.360000f,0.755556f,1.134246f,-0.360000f,0.755556f,1.134246f,0.360000f,0.577778f,1.372130f,-0.360000f,0.755556f,1.134246f,-0.360000f,0.577778f,1.372130f,0.360000f,0.577778f,1.372130f,-0.360000f,3.600000f,3.900000f,-0.360000f,3.422222f,2.266974f,0.360000f,3.422222f,2.266974f,-0.360000f,3.600000f,3.900000f,0.360000f,3.422222f,2.266974f,0.360000f,3.600000f,3.900000f,0.360000f,3.244444f,1.466974f,-0.360000f,3.244444f,1.466974f,0.360000f,3.066667f,1.166974f,-0.360000f,3.244444f,1.466974f,-0.360000f,3.066667f,1.166974f,0.360000f,3.066667f,1.166974f,0.360000f,2.888889f,1.023752f,-0.360000f,2.888889f,1.023752f,0.360000f,2.711111f,0.966974f,-0.360000f,2.888889f,1.023752f,-0.360000f,2.711111f,0.966974f,0.360000f,2.711111f,0.966974f,0.360000f,2.533333f,0.939976f,-0.360000f,2.533333f,0.939976f,-0.360000f,2.355556f,0.939976f,0.360000f,2.533333f,0.939976f,-0.360000f,2.355556f,0.939976f,0.360000f,2.355556f,0.939976f,0.360000f,2.177778f,0.939976f,-0.360000f,2.177778f,0.939976f,-0.360000f,2,0.939976f,0.360000f,2.177778f,0.939976f,-0.360000f,2,0.939976f,0.360000f,2,0.939976f,0.360000f,1.822222f,0.939976f,-0.360000f,1.822222f,0.939976f,-0.360000f,1.644444f,0.939976f,0.360000f,1.822222f,0.939976f,-0.360000f,1.644444f,0.939976f,0.360000f,1.644444f,0.939976f,0.360000f,1.466667f,0.939976f,-0.360000f,1.466667f,0.939976f,-0.360000f,1.288889f,0.939976f,0.360000f,1.466667f,0.939976f,-0.360000f,1.288889f,0.939976f,0.360000f,1.288889f,0.939976f,0.360000f,1.111111f,0.957571f,-0.360000f,1.111111f,0.957571f,0.360000f,0.933333f,1.009739f,-0.360000f,1.111111f,0.957571f,-0.360000f,0.933333f,1.009739f,0.360000f,0.933333f,1.009739f,0.360000f,0.400000f,1.743932f,0.360000f,0.577778f,1.372130f,-0.360000f,0.577778f,1.372130f,-0.360000f,0.577778f,1.372130f,-0.360000f,0.400000f,1.743932f,0.360000f,0.400000f,1.743932f, }; static dTriIndex world_indices[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485, }; ode-0.14/ode/demo/bunny_geom.h0000644000000000000000000007372212635011627014727 0ustar rootroot// Bunny mesh ripped from Opcode const int VertexCount = 453; const int IndexCount = 902 * 3; float Vertices[VertexCount * 3] = { -0.334392f, 0.133007f, 0.062259f, -0.350189f, 0.150354f, -0.147769f, -0.234201f, 0.343811f, -0.174307f, -0.200259f, 0.285207f, 0.093749f, 0.003520f, 0.475208f, -0.159365f, 0.001856f, 0.419203f, 0.098582f, -0.252802f, 0.093666f, 0.237538f, -0.162901f, 0.237984f, 0.206905f, 0.000865f, 0.318141f, 0.235370f, -0.414624f, 0.164083f, -0.278254f, -0.262213f, 0.357334f, -0.293246f, 0.004628f, 0.482694f, -0.338626f, -0.402162f, 0.133528f, -0.443247f, -0.243781f, 0.324275f, -0.436763f, 0.005293f, 0.437592f, -0.458332f, -0.339884f, -0.041150f, -0.668211f, -0.248382f, 0.255825f, -0.627493f, 0.006261f, 0.376103f, -0.631506f, -0.216201f, -0.126776f, -0.886936f, -0.171075f, 0.011544f, -0.881386f, -0.181074f, 0.098223f, -0.814779f, -0.119891f, 0.218786f, -0.760153f, -0.078895f, 0.276780f, -0.739281f, 0.006801f, 0.310959f, -0.735661f, -0.168842f, 0.102387f, -0.920381f, -0.104072f, 0.177278f, -0.952530f, -0.129704f, 0.211848f, -0.836678f, -0.099875f, 0.310931f, -0.799381f, 0.007237f, 0.361687f, -0.794439f, -0.077913f, 0.258753f, -0.921640f, 0.007957f, 0.282241f, -0.931680f, -0.252222f, -0.550401f, -0.557810f, -0.267633f, -0.603419f, -0.655209f, -0.446838f, -0.118517f, -0.466159f, -0.459488f, -0.093017f, -0.311341f, -0.370645f, -0.100108f, -0.159454f, -0.371984f, -0.091991f, -0.011044f, -0.328945f, -0.098269f, 0.088659f, -0.282452f, -0.018862f, 0.311501f, -0.352403f, -0.131341f, 0.144902f, -0.364126f, -0.200299f, 0.202388f, -0.283965f, -0.231869f, 0.023668f, -0.298943f, -0.155218f, 0.369716f, -0.293787f, -0.121856f, 0.419097f, -0.290163f, -0.290797f, 0.107824f, -0.264165f, -0.272849f, 0.036347f, -0.228567f, -0.372573f, 0.290309f, -0.190431f, -0.286997f, 0.421917f, -0.191039f, -0.240973f, 0.507118f, -0.287272f, -0.276431f, -0.065444f, -0.295675f, -0.280818f, -0.174200f, -0.399537f, -0.313131f, -0.376167f, -0.392666f, -0.488581f, -0.427494f, -0.331669f, -0.570185f, -0.466054f, -0.282290f, -0.618140f, -0.589220f, -0.374238f, -0.594882f, -0.323298f, -0.381071f, -0.629723f, -0.350777f, -0.382112f, -0.624060f, -0.221577f, -0.272701f, -0.566522f, 0.259157f, -0.256702f, -0.663406f, 0.286079f, -0.280948f, -0.428359f, 0.055790f, -0.184974f, -0.508894f, 0.326265f, -0.279971f, -0.526918f, 0.395319f, -0.282599f, -0.663393f, 0.412411f, -0.188329f, -0.475093f, 0.417954f, -0.263384f, -0.663396f, 0.466604f, -0.209063f, -0.663393f, 0.509344f, -0.002044f, -0.319624f, 0.553078f, -0.001266f, -0.371260f, 0.413296f, -0.219753f, -0.339762f, -0.040921f, -0.256986f, -0.282511f, -0.006349f, -0.271706f, -0.260881f, 0.001764f, -0.091191f, -0.419184f, -0.045912f, -0.114944f, -0.429752f, -0.124739f, -0.113970f, -0.382987f, -0.188540f, -0.243012f, -0.464942f, -0.242850f, -0.314815f, -0.505402f, -0.324768f, 0.002774f, -0.437526f, -0.262766f, -0.072625f, -0.417748f, -0.221440f, -0.160112f, -0.476932f, -0.293450f, 0.003859f, -0.453425f, -0.443916f, -0.120363f, -0.581567f, -0.438689f, -0.091499f, -0.584191f, -0.294511f, -0.116469f, -0.599861f, -0.188308f, -0.208032f, -0.513640f, -0.134649f, -0.235749f, -0.610017f, -0.040939f, -0.344916f, -0.622487f, -0.085380f, -0.336401f, -0.531864f, -0.212298f, 0.001961f, -0.459550f, -0.135547f, -0.058296f, -0.430536f, -0.043440f, 0.001378f, -0.449511f, -0.037762f, -0.130135f, -0.510222f, 0.079144f, 0.000142f, -0.477549f, 0.157064f, -0.114284f, -0.453206f, 0.304397f, -0.000592f, -0.443558f, 0.285401f, -0.056215f, -0.663402f, 0.326073f, -0.026248f, -0.568010f, 0.273318f, -0.049261f, -0.531064f, 0.389854f, -0.127096f, -0.663398f, 0.479316f, -0.058384f, -0.663401f, 0.372891f, -0.303961f, 0.054199f, 0.625921f, -0.268594f, 0.193403f, 0.502766f, -0.277159f, 0.126123f, 0.443289f, -0.287605f, -0.005722f, 0.531844f, -0.231396f, -0.121289f, 0.587387f, -0.253475f, -0.081797f, 0.756541f, -0.195164f, -0.137969f, 0.728011f, -0.167673f, -0.156573f, 0.609388f, -0.145917f, -0.169029f, 0.697600f, -0.077776f, -0.214247f, 0.622586f, -0.076873f, -0.214971f, 0.696301f, -0.002341f, -0.233135f, 0.622859f, -0.002730f, -0.213526f, 0.691267f, -0.003136f, -0.192628f, 0.762731f, -0.056136f, -0.201222f, 0.763806f, -0.114589f, -0.166192f, 0.770723f, -0.155145f, -0.129632f, 0.791738f, -0.183611f, -0.058705f, 0.847012f, -0.165562f, 0.001980f, 0.833386f, -0.220084f, 0.019914f, 0.768935f, -0.255730f, 0.090306f, 0.670782f, -0.255594f, 0.113833f, 0.663389f, -0.226380f, 0.212655f, 0.617740f, -0.003367f, -0.195342f, 0.799680f, -0.029743f, -0.210508f, 0.827180f, -0.003818f, -0.194783f, 0.873636f, -0.004116f, -0.157907f, 0.931268f, -0.031280f, -0.184555f, 0.889476f, -0.059885f, -0.184448f, 0.841330f, -0.135333f, -0.164332f, 0.878200f, -0.085574f, -0.170948f, 0.925547f, -0.163833f, -0.094170f, 0.897114f, -0.138444f, -0.104250f, 0.945975f, -0.083497f, -0.084934f, 0.979607f, -0.004433f, -0.146642f, 0.985872f, -0.150715f, 0.032650f, 0.884111f, -0.135892f, -0.035520f, 0.945455f, -0.070612f, 0.036849f, 0.975733f, -0.004458f, -0.042526f, 1.015670f, -0.004249f, 0.046042f, 1.003240f, -0.086969f, 0.133224f, 0.947633f, -0.003873f, 0.161605f, 0.970499f, -0.125544f, 0.140012f, 0.917678f, -0.125651f, 0.250246f, 0.857602f, -0.003127f, 0.284070f, 0.878870f, -0.159174f, 0.125726f, 0.888878f, -0.183807f, 0.196970f, 0.844480f, -0.159890f, 0.291736f, 0.732480f, -0.199495f, 0.207230f, 0.779864f, -0.206182f, 0.164608f, 0.693257f, -0.186315f, 0.160689f, 0.817193f, -0.192827f, 0.166706f, 0.782271f, -0.175112f, 0.110008f, 0.860621f, -0.161022f, 0.057420f, 0.855111f, -0.172319f, 0.036155f, 0.816189f, -0.190318f, 0.064083f, 0.760605f, -0.195072f, 0.129179f, 0.731104f, -0.203126f, 0.410287f, 0.680536f, -0.216677f, 0.309274f, 0.642272f, -0.241515f, 0.311485f, 0.587832f, -0.002209f, 0.366663f, 0.749413f, -0.088230f, 0.396265f, 0.678635f, -0.170147f, 0.109517f, 0.840784f, -0.160521f, 0.067766f, 0.830650f, -0.181546f, 0.139805f, 0.812146f, -0.180495f, 0.148568f, 0.776087f, -0.180255f, 0.129125f, 0.744192f, -0.186298f, 0.078308f, 0.769352f, -0.167622f, 0.060539f, 0.806675f, -0.189876f, 0.102760f, 0.802582f, -0.108340f, 0.455446f, 0.657174f, -0.241585f, 0.527592f, 0.669296f, -0.265676f, 0.513366f, 0.634594f, -0.203073f, 0.478550f, 0.581526f, -0.266772f, 0.642330f, 0.602061f, -0.216961f, 0.564846f, 0.535435f, -0.202210f, 0.525495f, 0.475944f, -0.193888f, 0.467925f, 0.520606f, -0.265837f, 0.757267f, 0.500933f, -0.240306f, 0.653440f, 0.463215f, -0.309239f, 0.776868f, 0.304726f, -0.271009f, 0.683094f, 0.382018f, -0.312111f, 0.671099f, 0.286687f, -0.268791f, 0.624342f, 0.377231f, -0.302457f, 0.533996f, 0.360289f, -0.263656f, 0.529310f, 0.412564f, -0.282311f, 0.415167f, 0.447666f, -0.239201f, 0.442096f, 0.495604f, -0.220043f, 0.569026f, 0.445877f, -0.001263f, 0.395631f, 0.602029f, -0.057345f, 0.442535f, 0.572224f, -0.088927f, 0.506333f, 0.529106f, -0.125738f, 0.535076f, 0.612913f, -0.126251f, 0.577170f, 0.483159f, -0.149594f, 0.611520f, 0.557731f, -0.163188f, 0.660791f, 0.491080f, -0.172482f, 0.663387f, 0.415416f, -0.160464f, 0.591710f, 0.370659f, -0.156445f, 0.536396f, 0.378302f, -0.136496f, 0.444358f, 0.425226f, -0.095564f, 0.373768f, 0.473659f, -0.104146f, 0.315912f, 0.498104f, -0.000496f, 0.384194f, 0.473817f, -0.000183f, 0.297770f, 0.401486f, -0.129042f, 0.270145f, 0.434495f, 0.000100f, 0.272963f, 0.349138f, -0.113060f, 0.236984f, 0.385554f, 0.007260f, 0.016311f, -0.883396f, 0.007865f, 0.122104f, -0.956137f, -0.032842f, 0.115282f, -0.953252f, -0.089115f, 0.108449f, -0.950317f, -0.047440f, 0.014729f, -0.882756f, -0.104458f, 0.013137f, -0.882070f, -0.086439f, -0.584866f, -0.608343f, -0.115026f, -0.662605f, -0.436732f, -0.071683f, -0.665372f, -0.606385f, -0.257884f, -0.665381f, -0.658052f, -0.272542f, -0.665381f, -0.592063f, -0.371322f, -0.665382f, -0.353620f, -0.372362f, -0.665381f, -0.224420f, -0.335166f, -0.665380f, -0.078623f, -0.225999f, -0.665375f, -0.038981f, -0.106719f, -0.665374f, -0.186351f, -0.081749f, -0.665372f, -0.292554f, 0.006943f, -0.091505f, -0.858354f, 0.006117f, -0.280985f, -0.769967f, 0.004495f, -0.502360f, -0.559799f, -0.198638f, -0.302135f, -0.845816f, -0.237395f, -0.542544f, -0.587188f, -0.270001f, -0.279489f, -0.669861f, -0.134547f, -0.119852f, -0.959004f, -0.052088f, -0.122463f, -0.944549f, -0.124463f, -0.293508f, -0.899566f, -0.047616f, -0.289643f, -0.879292f, -0.168595f, -0.529132f, -0.654931f, -0.099793f, -0.515719f, -0.645873f, -0.186168f, -0.605282f, -0.724690f, -0.112970f, -0.583097f, -0.707469f, -0.108152f, -0.665375f, -0.700408f, -0.183019f, -0.665378f, -0.717630f, -0.349529f, -0.334459f, -0.511985f, -0.141182f, -0.437705f, -0.798194f, -0.212670f, -0.448725f, -0.737447f, -0.261111f, -0.414945f, -0.613835f, -0.077364f, -0.431480f, -0.778113f, 0.005174f, -0.425277f, -0.651592f, 0.089236f, -0.431732f, -0.777093f, 0.271006f, -0.415749f, -0.610577f, 0.223981f, -0.449384f, -0.734774f, 0.153275f, -0.438150f, -0.796391f, 0.358414f, -0.335529f, -0.507649f, 0.193434f, -0.665946f, -0.715325f, 0.118363f, -0.665717f, -0.699021f, 0.123515f, -0.583454f, -0.706020f, 0.196851f, -0.605860f, -0.722345f, 0.109788f, -0.516035f, -0.644590f, 0.178656f, -0.529656f, -0.652804f, 0.061157f, -0.289807f, -0.878626f, 0.138234f, -0.293905f, -0.897958f, 0.066933f, -0.122643f, -0.943820f, 0.149571f, -0.120281f, -0.957264f, 0.280989f, -0.280321f, -0.666487f, 0.246581f, -0.543275f, -0.584224f, 0.211720f, -0.302754f, -0.843303f, 0.086966f, -0.665627f, -0.291520f, 0.110634f, -0.665702f, -0.185021f, 0.228099f, -0.666061f, -0.036201f, 0.337743f, -0.666396f, -0.074503f, 0.376722f, -0.666513f, -0.219833f, 0.377265f, -0.666513f, -0.349036f, 0.281411f, -0.666217f, -0.588670f, 0.267564f, -0.666174f, -0.654834f, 0.080745f, -0.665602f, -0.605452f, 0.122016f, -0.662963f, -0.435280f, 0.095767f, -0.585141f, -0.607228f, 0.118944f, 0.012799f, -0.880702f, 0.061944f, 0.014564f, -0.882086f, 0.104725f, 0.108156f, -0.949130f, 0.048513f, 0.115159f, -0.952753f, 0.112696f, 0.236643f, 0.386937f, 0.128177f, 0.269757f, 0.436071f, 0.102643f, 0.315600f, 0.499370f, 0.094535f, 0.373481f, 0.474824f, 0.136270f, 0.443946f, 0.426895f, 0.157071f, 0.535923f, 0.380222f, 0.161350f, 0.591224f, 0.372630f, 0.173035f, 0.662865f, 0.417531f, 0.162808f, 0.660299f, 0.493077f, 0.148250f, 0.611070f, 0.559555f, 0.125719f, 0.576790f, 0.484702f, 0.123489f, 0.534699f, 0.614440f, 0.087621f, 0.506066f, 0.530188f, 0.055321f, 0.442365f, 0.572915f, 0.219936f, 0.568361f, 0.448571f, 0.238099f, 0.441375f, 0.498528f, 0.281711f, 0.414315f, 0.451121f, 0.263833f, 0.528513f, 0.415794f, 0.303284f, 0.533081f, 0.363998f, 0.269687f, 0.623528f, 0.380528f, 0.314255f, 0.670153f, 0.290524f, 0.272023f, 0.682273f, 0.385343f, 0.311480f, 0.775931f, 0.308527f, 0.240239f, 0.652714f, 0.466159f, 0.265619f, 0.756464f, 0.504187f, 0.192562f, 0.467341f, 0.522972f, 0.201605f, 0.524885f, 0.478417f, 0.215743f, 0.564193f, 0.538084f, 0.264969f, 0.641527f, 0.605317f, 0.201031f, 0.477940f, 0.584002f, 0.263086f, 0.512567f, 0.637832f, 0.238615f, 0.526867f, 0.672237f, 0.105309f, 0.455123f, 0.658482f, 0.183993f, 0.102195f, 0.804872f, 0.161563f, 0.060042f, 0.808692f, 0.180748f, 0.077754f, 0.771600f, 0.175168f, 0.128588f, 0.746368f, 0.175075f, 0.148030f, 0.778264f, 0.175658f, 0.139265f, 0.814333f, 0.154191f, 0.067291f, 0.832578f, 0.163818f, 0.109013f, 0.842830f, 0.084760f, 0.396004f, 0.679695f, 0.238888f, 0.310760f, 0.590775f, 0.213380f, 0.308625f, 0.644905f, 0.199666f, 0.409678f, 0.683003f, 0.190143f, 0.128597f, 0.733463f, 0.184833f, 0.063516f, 0.762902f, 0.166070f, 0.035644f, 0.818261f, 0.154361f, 0.056943f, 0.857042f, 0.168542f, 0.109489f, 0.862725f, 0.187387f, 0.166131f, 0.784599f, 0.180428f, 0.160135f, 0.819438f, 0.201823f, 0.163991f, 0.695756f, 0.194206f, 0.206635f, 0.782275f, 0.155438f, 0.291260f, 0.734412f, 0.177696f, 0.196424f, 0.846693f, 0.152305f, 0.125256f, 0.890786f, 0.119546f, 0.249876f, 0.859104f, 0.118369f, 0.139643f, 0.919173f, 0.079410f, 0.132973f, 0.948652f, 0.062419f, 0.036648f, 0.976547f, 0.127847f, -0.035919f, 0.947070f, 0.143624f, 0.032206f, 0.885913f, 0.074888f, -0.085173f, 0.980577f, 0.130184f, -0.104656f, 0.947620f, 0.156201f, -0.094653f, 0.899074f, 0.077366f, -0.171194f, 0.926545f, 0.127722f, -0.164729f, 0.879810f, 0.052670f, -0.184618f, 0.842019f, 0.023477f, -0.184638f, 0.889811f, 0.022626f, -0.210587f, 0.827500f, 0.223089f, 0.211976f, 0.620493f, 0.251444f, 0.113067f, 0.666494f, 0.251419f, 0.089540f, 0.673887f, 0.214360f, 0.019258f, 0.771595f, 0.158999f, 0.001490f, 0.835374f, 0.176696f, -0.059249f, 0.849218f, 0.148696f, -0.130091f, 0.793599f, 0.108290f, -0.166528f, 0.772088f, 0.049820f, -0.201382f, 0.764454f, 0.071341f, -0.215195f, 0.697209f, 0.073148f, -0.214475f, 0.623510f, 0.140502f, -0.169461f, 0.699354f, 0.163374f, -0.157073f, 0.611416f, 0.189466f, -0.138550f, 0.730366f, 0.247593f, -0.082554f, 0.759610f, 0.227468f, -0.121982f, 0.590197f, 0.284702f, -0.006586f, 0.535347f, 0.275741f, 0.125287f, 0.446676f, 0.266650f, 0.192594f, 0.506044f, 0.300086f, 0.053287f, 0.629620f, 0.055450f, -0.663935f, 0.375065f, 0.122854f, -0.664138f, 0.482323f, 0.046520f, -0.531571f, 0.391918f, 0.024824f, -0.568450f, 0.275106f, 0.053855f, -0.663931f, 0.328224f, 0.112829f, -0.453549f, 0.305788f, 0.131265f, -0.510617f, 0.080746f, 0.061174f, -0.430716f, -0.042710f, 0.341019f, -0.532887f, -0.208150f, 0.347705f, -0.623533f, -0.081139f, 0.238040f, -0.610732f, -0.038037f, 0.211764f, -0.514274f, -0.132078f, 0.120605f, -0.600219f, -0.186856f, 0.096985f, -0.584476f, -0.293357f, 0.127621f, -0.581941f, -0.437170f, 0.165902f, -0.477425f, -0.291453f, 0.077720f, -0.417975f, -0.220519f, 0.320892f, -0.506363f, -0.320874f, 0.248214f, -0.465684f, -0.239842f, 0.118764f, -0.383338f, -0.187114f, 0.118816f, -0.430106f, -0.123307f, 0.094131f, -0.419464f, -0.044777f, 0.274526f, -0.261706f, 0.005110f, 0.259842f, -0.283292f, -0.003185f, 0.222861f, -0.340431f, -0.038210f, 0.204445f, -0.664380f, 0.513353f, 0.259286f, -0.664547f, 0.471281f, 0.185402f, -0.476020f, 0.421718f, 0.279163f, -0.664604f, 0.417328f, 0.277157f, -0.528122f, 0.400208f, 0.183069f, -0.509812f, 0.329995f, 0.282599f, -0.429210f, 0.059242f, 0.254816f, -0.664541f, 0.290687f, 0.271436f, -0.567707f, 0.263966f, 0.386561f, -0.625221f, -0.216870f, 0.387086f, -0.630883f, -0.346073f, 0.380021f, -0.596021f, -0.318679f, 0.291269f, -0.619007f, -0.585707f, 0.339280f, -0.571198f, -0.461946f, 0.400045f, -0.489778f, -0.422640f, 0.406817f, -0.314349f, -0.371230f, 0.300588f, -0.281718f, -0.170549f, 0.290866f, -0.277304f, -0.061905f, 0.187735f, -0.241545f, 0.509437f, 0.188032f, -0.287569f, 0.424234f, 0.227520f, -0.373262f, 0.293102f, 0.266526f, -0.273650f, 0.039597f, 0.291592f, -0.291676f, 0.111386f, 0.291914f, -0.122741f, 0.422683f, 0.297574f, -0.156119f, 0.373368f, 0.286603f, -0.232731f, 0.027162f, 0.364663f, -0.201399f, 0.206850f, 0.353855f, -0.132408f, 0.149228f, 0.282208f, -0.019715f, 0.314960f, 0.331187f, -0.099266f, 0.092701f, 0.375463f, -0.093120f, -0.006467f, 0.375917f, -0.101236f, -0.154882f, 0.466635f, -0.094416f, -0.305669f, 0.455805f, -0.119881f, -0.460632f, 0.277465f, -0.604242f, -0.651871f, 0.261022f, -0.551176f, -0.554667f, 0.093627f, 0.258494f, -0.920589f, 0.114248f, 0.310608f, -0.798070f, 0.144232f, 0.211434f, -0.835001f, 0.119916f, 0.176940f, -0.951159f, 0.184061f, 0.101854f, -0.918220f, 0.092431f, 0.276521f, -0.738231f, 0.133504f, 0.218403f, -0.758602f, 0.194987f, 0.097655f, -0.812476f, 0.185542f, 0.011005f, -0.879202f, 0.230315f, -0.127450f, -0.884202f, 0.260471f, 0.255056f, -0.624378f, 0.351567f, -0.042194f, -0.663976f, 0.253742f, 0.323524f, -0.433716f, 0.411612f, 0.132299f, -0.438264f, 0.270513f, 0.356530f, -0.289984f, 0.422146f, 0.162819f, -0.273130f, 0.164724f, 0.237490f, 0.208912f, 0.253806f, 0.092900f, 0.240640f, 0.203608f, 0.284597f, 0.096223f, 0.241006f, 0.343093f, -0.171396f, 0.356076f, 0.149288f, -0.143443f, 0.337656f, 0.131992f, 0.066374f }; dTriIndex Indices[IndexCount / 3][3] = { {126,134,133}, {342,138,134}, {133,134,138}, {126,342,134}, {312,316,317}, {169,163,162}, {312,317,319}, {312,319,318}, {169,162,164}, {169,168,163}, {312,314,315}, {169,164,165}, {169,167,168}, {312,315,316}, {312,313,314}, {169,165,166}, {169,166,167}, {312,318,313}, {308,304,305}, {308,305,306}, {179,181,188}, {177,173,175}, {177,175,176}, {302,293,300}, {322,294,304}, {188,176,175}, {188,175,179}, {158,177,187}, {305,293,302}, {305,302,306}, {322,304,308}, {188,181,183}, {158,173,177}, {293,298,300}, {304,294,296}, {304,296,305}, {185,176,188}, {185,188,183}, {187,177,176}, {187,176,185}, {305,296,298}, {305,298,293}, {436,432, 28}, {436, 28, 23}, {434,278,431}, { 30,208,209}, { 30,209, 29}, { 19, 20, 24}, {208,207,211}, {208,211,209}, { 19,210,212}, {433,434,431}, {433,431,432}, {433,432,436}, {436,437,433}, {277,275,276}, {277,276,278}, {209,210, 25}, { 21, 26, 24}, { 21, 24, 20}, { 25, 26, 27}, { 25, 27, 29}, {435,439,277}, {439,275,277}, {432,431, 30}, {432, 30, 28}, {433,437,438}, {433,438,435}, {434,277,278}, { 24, 25,210}, { 24, 26, 25}, { 29, 27, 28}, { 29, 28, 30}, { 19, 24,210}, {208, 30,431}, {208,431,278}, {435,434,433}, {435,277,434}, { 25, 29,209}, { 27, 22, 23}, { 27, 23, 28}, { 26, 22, 27}, { 26, 21, 22}, {212,210,209}, {212,209,211}, {207,208,278}, {207,278,276}, {439,435,438}, { 12, 9, 10}, { 12, 10, 13}, { 2, 3, 5}, { 2, 5, 4}, { 16, 13, 14}, { 16, 14, 17}, { 22, 21, 16}, { 13, 10, 11}, { 13, 11, 14}, { 1, 0, 3}, { 1, 3, 2}, { 15, 12, 16}, { 19, 18, 15}, { 19, 15, 16}, { 19, 16, 20}, { 9, 1, 2}, { 9, 2, 10}, { 3, 7, 8}, { 3, 8, 5}, { 16, 17, 23}, { 16, 23, 22}, { 21, 20, 16}, { 10, 2, 4}, { 10, 4, 11}, { 0, 6, 7}, { 0, 7, 3}, { 12, 13, 16}, {451,446,445}, {451,445,450}, {442,440,439}, {442,439,438}, {442,438,441}, {421,420,422}, {412,411,426}, {412,426,425}, {408,405,407}, {413, 67, 68}, {413, 68,414}, {391,390,412}, { 80,384,386}, {404,406,378}, {390,391,377}, {390,377, 88}, {400,415,375}, {398,396,395}, {398,395,371}, {398,371,370}, {112,359,358}, {112,358,113}, {351,352,369}, {125,349,348}, {345,343,342}, {342,340,339}, {341,335,337}, {328,341,327}, {331,323,333}, {331,322,323}, {327,318,319}, {327,319,328}, {315,314,324}, {302,300,301}, {302,301,303}, {320,311,292}, {285,284,289}, {310,307,288}, {310,288,290}, {321,350,281}, {321,281,282}, {423,448,367}, {272,273,384}, {272,384,274}, {264,265,382}, {264,382,383}, {440,442,261}, {440,261,263}, {252,253,254}, {252,254,251}, {262,256,249}, {262,249,248}, {228,243,242}, {228, 31,243}, {213,215,238}, {213,238,237}, { 19,212,230}, {224,225,233}, {224,233,231}, {217,218, 56}, {217, 56, 54}, {217,216,239}, {217,239,238}, {217,238,215}, {218,217,215}, {218,215,214}, { 6,102,206}, {186,199,200}, {197,182,180}, {170,171,157}, {201,200,189}, {170,190,191}, {170,191,192}, {175,174,178}, {175,178,179}, {168,167,155}, {122,149,158}, {122,158,159}, {135,153,154}, {135,154,118}, {143,140,141}, {143,141,144}, {132,133,136}, {130,126,133}, {124,125,127}, {122,101,100}, {122,100,121}, {110,108,107}, {110,107,109}, { 98, 99, 97}, { 98, 97, 64}, { 98, 64, 66}, { 87, 55, 57}, { 83, 82, 79}, { 83, 79, 84}, { 78, 74, 50}, { 49, 71, 41}, { 49, 41, 37}, { 49, 37, 36}, { 58, 44, 60}, { 60, 59, 58}, { 51, 34, 33}, { 39, 40, 42}, { 39, 42, 38}, {243,240, 33}, {243, 33,229}, { 39, 38, 6}, { 44, 46, 40}, { 55, 56, 57}, { 64, 62, 65}, { 64, 65, 66}, { 41, 71, 45}, { 75, 50, 51}, { 81, 79, 82}, { 77, 88, 73}, { 93, 92, 94}, { 68, 47, 46}, { 96, 97, 99}, { 96, 99, 95}, {110,109,111}, {111,112,110}, {114,113,123}, {114,123,124}, {132,131,129}, {133,137,136}, {135,142,145}, {145,152,135}, {149,147,157}, {157,158,149}, {164,150,151}, {153,163,168}, {153,168,154}, {185,183,182}, {185,182,184}, {161,189,190}, {200,199,191}, {200,191,190}, {180,178,195}, {180,195,196}, {102,101,204}, {102,204,206}, { 43, 48,104}, { 43,104,103}, {216,217, 54}, {216, 54, 32}, {207,224,231}, {230,212,211}, {230,211,231}, {227,232,241}, {227,241,242}, {235,234,241}, {235,241,244}, {430,248,247}, {272,274,253}, {272,253,252}, {439,260,275}, {225,224,259}, {225,259,257}, {269,270,407}, {269,407,405}, {270,269,273}, {270,273,272}, {273,269,268}, {273,268,267}, {273,267,266}, {273,266,265}, {273,265,264}, {448,279,367}, {281,350,368}, {285,286,301}, {290,323,310}, {290,311,323}, {282,281,189}, {292,311,290}, {292,290,291}, {307,306,302}, {307,302,303}, {316,315,324}, {316,324,329}, {331,351,350}, {330,334,335}, {330,335,328}, {341,337,338}, {344,355,354}, {346,345,348}, {346,348,347}, {364,369,352}, {364,352,353}, {365,363,361}, {365,361,362}, {376,401,402}, {373,372,397}, {373,397,400}, {376, 92,377}, {381,378,387}, {381,387,385}, {386, 77, 80}, {390,389,412}, {416,417,401}, {403,417,415}, {408,429,430}, {419,423,418}, {427,428,444}, {427,444,446}, {437,436,441}, {450,445, 11}, {450, 11, 4}, {447,449, 5}, {447, 5, 8}, {441,438,437}, {425,426,451}, {425,451,452}, {417,421,415}, {408,407,429}, {399,403,400}, {399,400,397}, {394,393,416}, {389,411,412}, {386,383,385}, {408,387,378}, {408,378,406}, {377,391,376}, { 94,375,415}, {372,373,374}, {372,374,370}, {359,111,360}, {359,112,111}, {113,358,349}, {113,349,123}, {346,343,345}, {343,340,342}, {338,336,144}, {338,144,141}, {327,341,354}, {327,354,326}, {331,350,321}, {331,321,322}, {314,313,326}, {314,326,325}, {300,298,299}, {300,299,301}, {288,287,289}, {189,292,282}, {287,288,303}, {284,285,297}, {368,280,281}, {448,447,279}, {274,226,255}, {267,268,404}, {267,404,379}, {429,262,430}, {439,440,260}, {257,258,249}, {257,249,246}, {430,262,248}, {234,228,242}, {234,242,241}, {237,238,239}, {237,239,236}, { 15, 18,227}, { 15,227,229}, {222,223, 82}, {222, 82, 83}, {214,215,213}, {214,213, 81}, { 38,102, 6}, {122,159,200}, {122,200,201}, {174,171,192}, {174,192,194}, {197,193,198}, {190,170,161}, {181,179,178}, {181,178,180}, {166,156,155}, {163,153,152}, {163,152,162}, {120,156,149}, {120,149,121}, {152,153,135}, {140,143,142}, {135,131,132}, {135,132,136}, {130,129,128}, {130,128,127}, {100,105,119}, {100,119,120}, {106,104,107}, {106,107,108}, { 91, 95, 59}, { 93, 94, 68}, { 91, 89, 92}, { 76, 53, 55}, { 76, 55, 87}, { 81, 78, 79}, { 74, 73, 49}, { 69, 60, 45}, { 58, 62, 64}, { 58, 64, 61}, { 53, 31, 32}, { 32, 54, 53}, { 42, 43, 38}, { 35, 36, 0}, { 35, 0, 1}, { 34, 35, 1}, { 34, 1, 9}, { 44, 40, 41}, { 44, 41, 45}, { 33,240, 51}, { 63, 62, 58}, { 63, 58, 59}, { 45, 71, 70}, { 76, 75, 51}, { 76, 51, 52}, { 86, 85, 84}, { 86, 84, 87}, { 89, 72, 73}, { 89, 73, 88}, { 91, 92, 96}, { 91, 96, 95}, { 72, 91, 60}, { 72, 60, 69}, {104,106,105}, {119,105,117}, {119,117,118}, {124,127,128}, {117,116,129}, {117,129,131}, {118,117,131}, {135,140,142}, {146,150,152}, {146,152,145}, {149,122,121}, {166,165,151}, {166,151,156}, {158,172,173}, {161,160,189}, {199,198,193}, {199,193,191}, {204,201,202}, {178,174,194}, {200,159,186}, {109, 48, 67}, { 48,107,104}, {216, 32,236}, {216,236,239}, {223,214, 81}, {223, 81, 82}, { 33, 12, 15}, { 32,228,234}, { 32,234,236}, {240, 31, 52}, {256,255,246}, {256,246,249}, {258,263,248}, {258,248,249}, {275,260,259}, {275,259,276}, {207,276,259}, {270,271,429}, {270,429,407}, {413,418,366}, {413,366,365}, {368,367,279}, {368,279,280}, {303,301,286}, {303,286,287}, {283,282,292}, {283,292,291}, {320,292,189}, {298,296,297}, {298,297,299}, {318,327,326}, {318,326,313}, {329,330,317}, {336,333,320}, {326,354,353}, {334,332,333}, {334,333,336}, {342,339,139}, {342,139,138}, {345,342,126}, {347,357,356}, {369,368,351}, {363,356,357}, {363,357,361}, {366,367,368}, {366,368,369}, {375,373,400}, { 92, 90,377}, {409,387,408}, {386,385,387}, {386,387,388}, {412,394,391}, {396,398,399}, {408,406,405}, {415,421,419}, {415,419,414}, {425,452,448}, {425,448,424}, {444,441,443}, {448,452,449}, {448,449,447}, {446,444,443}, {446,443,445}, {250,247,261}, {250,261,428}, {421,422,423}, {421,423,419}, {427,410,250}, {417,403,401}, {403,402,401}, {420,392,412}, {420,412,425}, {420,425,424}, {386,411,389}, {383,382,381}, {383,381,385}, {378,379,404}, {372,371,395}, {372,395,397}, {371,372,370}, {361,359,360}, {361,360,362}, {368,350,351}, {349,347,348}, {356,355,344}, {356,344,346}, {344,341,340}, {344,340,343}, {338,337,336}, {328,335,341}, {324,352,351}, {324,351,331}, {320,144,336}, {314,325,324}, {322,308,309}, {310,309,307}, {287,286,289}, {203,280,279}, {203,279,205}, {297,295,283}, {297,283,284}, {447,205,279}, {274,384, 80}, {274, 80,226}, {266,267,379}, {266,379,380}, {225,257,246}, {225,246,245}, {256,254,253}, {256,253,255}, {430,247,250}, {226,235,244}, {226,244,245}, {232,233,244}, {232,244,241}, {230, 18, 19}, { 32, 31,228}, {219,220, 86}, {219, 86, 57}, {226,213,235}, {206, 7, 6}, {122,201,101}, {201,204,101}, {180,196,197}, {170,192,171}, {200,190,189}, {194,193,195}, {183,181,180}, {183,180,182}, {155,154,168}, {149,156,151}, {149,151,148}, {155,156,120}, {145,142,143}, {145,143,146}, {136,137,140}, {133,132,130}, {128,129,116}, {100,120,121}, {110,112,113}, {110,113,114}, { 66, 65, 63}, { 66, 63, 99}, { 66, 99, 98}, { 96, 46, 61}, { 89, 88, 90}, { 86, 87, 57}, { 80, 78, 81}, { 72, 69, 49}, { 67, 48, 47}, { 67, 47, 68}, { 56, 55, 53}, { 50, 49, 36}, { 50, 36, 35}, { 40, 39, 41}, {242,243,229}, {242,229,227}, { 6, 37, 39}, { 42, 47, 48}, { 42, 48, 43}, { 61, 46, 44}, { 45, 70, 69}, { 69, 70, 71}, { 69, 71, 49}, { 74, 78, 77}, { 83, 84, 85}, { 73, 74, 77}, { 93, 96, 92}, { 68, 46, 93}, { 95, 99, 63}, { 95, 63, 59}, {115,108,110}, {115,110,114}, {125,126,127}, {129,130,132}, {137,133,138}, {137,138,139}, {148,146,143}, {148,143,147}, {119,118,154}, {161,147,143}, {165,164,151}, {158,157,171}, {158,171,172}, {159,158,187}, {159,187,186}, {194,192,191}, {194,191,193}, {189,202,201}, {182,197,184}, {205, 8, 7}, { 48,109,107}, {218,219, 57}, {218, 57, 56}, {207,231,211}, {232,230,231}, {232,231,233}, { 53, 52, 31}, {388,411,386}, {409,430,250}, {262,429,254}, {262,254,256}, {442,444,428}, {273,264,383}, {273,383,384}, {429,271,251}, {429,251,254}, {413,365,362}, { 67,413,360}, {282,283,295}, {285,301,299}, {202,281,280}, {284,283,291}, {284,291,289}, {320,189,160}, {308,306,307}, {307,309,308}, {319,317,330}, {319,330,328}, {353,352,324}, {332,331,333}, {340,341,338}, {354,341,344}, {349,358,357}, {349,357,347}, {364,355,356}, {364,356,363}, {364,365,366}, {364,366,369}, {374,376,402}, {375, 92,373}, { 77,389,390}, {382,380,381}, {389, 77,386}, {393,394,412}, {393,412,392}, {401,394,416}, {415,400,403}, {411,410,427}, {411,427,426}, {422,420,424}, {247,248,263}, {247,263,261}, {445,443, 14}, {445, 14, 11}, {449,450, 4}, {449, 4, 5}, {443,441, 17}, {443, 17, 14}, {436, 23, 17}, {436, 17,441}, {424,448,422}, {448,423,422}, {414,419,418}, {414,418,413}, {406,404,405}, {399,397,395}, {399,395,396}, {420,416,392}, {388,410,411}, {386,384,383}, {390, 88, 77}, {375, 94, 92}, {415,414, 68}, {415, 68, 94}, {370,374,402}, {370,402,398}, {361,357,358}, {361,358,359}, {125,348,126}, {346,344,343}, {340,338,339}, {337,335,334}, {337,334,336}, {325,353,324}, {324,331,332}, {324,332,329}, {323,322,309}, {323,309,310}, {294,295,297}, {294,297,296}, {289,286,285}, {202,280,203}, {288,307,303}, {282,295,321}, { 67,360,111}, {418,423,367}, {418,367,366}, {272,252,251}, {272,251,271}, {272,271,270}, {255,253,274}, {265,266,380}, {265,380,382}, {442,428,261}, {440,263,258}, {440,258,260}, {409,250,410}, {255,226,245}, {255,245,246}, { 31,240,243}, {236,234,235}, {236,235,237}, {233,225,245}, {233,245,244}, {220,221, 85}, {220, 85, 86}, { 81,213,226}, { 81,226, 80}, { 7,206,205}, {186,184,198}, {186,198,199}, {204,203,205}, {204,205,206}, {195,193,196}, {171,174,172}, {173,174,175}, {173,172,174}, {155,167,166}, {160,161,143}, {160,143,144}, {119,154,155}, {148,151,150}, {148,150,146}, {140,137,139}, {140,139,141}, {127,126,130}, {114,124,128}, {114,128,115}, {117,105,106}, {117,106,116}, {104,105,100}, {104,100,103}, { 59, 60, 91}, { 97, 96, 61}, { 97, 61, 64}, { 91, 72, 89}, { 87, 84, 79}, { 87, 79, 76}, { 78, 80, 77}, { 49, 50, 74}, { 60, 44, 45}, { 61, 44, 58}, { 51, 50, 35}, { 51, 35, 34}, { 39, 37, 41}, { 33, 34, 9}, { 33, 9, 12}, { 0, 36, 37}, { 0, 37, 6}, { 40, 46, 47}, { 40, 47, 42}, { 53, 54, 56}, { 65, 62, 63}, { 72, 49, 73}, { 79, 78, 75}, { 79, 75, 76}, { 52, 53, 76}, { 92, 89, 90}, { 96, 93, 46}, {102,103,100}, {102,100,101}, {116,106,108}, {116,108,115}, {123,125,124}, {116,115,128}, {118,131,135}, {140,135,136}, {148,147,149}, {120,119,155}, {164,162,152}, {164,152,150}, {157,147,161}, {157,161,170}, {186,187,185}, {186,185,184}, {193,197,196}, {202,203,204}, {194,195,178}, {198,184,197}, { 67,111,109}, { 38, 43,103}, { 38,103,102}, {214,223,222}, {214,222,221}, {214,221,220}, {214,220,219}, {214,219,218}, {213,237,235}, {221,222, 83}, {221, 83, 85}, { 15,229, 33}, {227, 18,230}, {227,230,232}, { 52, 51,240}, { 75, 78, 50}, {408,430,409}, {260,258,257}, {260,257,259}, {224,207,259}, {268,269,405}, {268,405,404}, {413,362,360}, {447, 8,205}, {299,297,285}, {189,281,202}, {290,288,289}, {290,289,291}, {322,321,295}, {322,295,294}, {333,323,311}, {333,311,320}, {317,316,329}, {320,160,144}, {353,325,326}, {329,332,334}, {329,334,330}, {339,338,141}, {339,141,139}, {348,345,126}, {347,356,346}, {123,349,125}, {364,353,354}, {364,354,355}, {365,364,363}, {376,391,394}, {376,394,401}, { 92,376,374}, { 92,374,373}, {377, 90, 88}, {380,379,378}, {380,378,381}, {388,387,409}, {388,409,410}, {416,393,392}, {399,398,402}, {399,402,403}, {250,428,427}, {421,417,416}, {421,416,420}, {426,427,446}, {426,446,451}, {444,442,441}, {452,451,450}, {452,450,449} }; ode-0.14/ode/demo/convex_bunny_geom.h0000644000000000000000000003335412635011627016306 0ustar rootrootconst unsigned int convexBunnyPlaneCount = 176; dReal convexBunnyPlanes[] = { 0.986167, -0.0612533, -0.154021, 0.399481, 0.982735, -0.0691036, -0.171628, 0.409884, -0.984387, -0.0582774, -0.166089, 0.403079, 0.985044, -0.172279, 0.00302105, 0.437531, 0.976915, -0.184361, 0.107929, 0.465334, 0.951478, -0.281619, 0.124019, 0.475223, 0.798136, -0.502214, 0.332805, 0.535555, 0.949728, -0.211128, -0.231176, 0.528156, -0.000894561, -0.995066, -0.0992088, 0.80299, -0.000896015, -0.995066, -0.0992131, 0.802991, -0.0035709, -0.935822, 0.352454, 0.618504, -0.291551, -0.828515, 0.478081, 0.681579, -0.978715, -0.181408, 0.0959605, 0.468907, -0.985523, -0.169302, -0.00904739, 0.441129, -0.953768, -0.278749, 0.11236, 0.478704, 0.372745, -0.827499, 0.419888, 0.630174, 0.976911, -0.18316, 0.109991, 0.466086, 0.817827, -0.387738, 0.425227, 0.569153, -0.978732, -0.180211, 0.0980152, 0.469656, 0.662794, -0.0277654, 0.748287, 0.803459, 0.00359857, -0.660581, -0.750746, 0.877267, 0.00359952, -0.660579, -0.750748, 0.877266, -0.947456, -0.208272, -0.242797, 0.531628, -0.980764, -0.0661375, -0.18365, 0.413468, -0.940835, -0.0698657, -0.331585, 0.494827, 0.983751, 0.0529367, -0.171556, 0.403533, 0.981839, 0.0996302, -0.16145, 0.410144, 0.977938, 0.0857834, -0.190468, 0.411823, 0.959636, 0.106068, -0.260476, 0.44898, 0.85334, -0.0495414, -0.518996, 0.60489, -0.803667, -0.499793, 0.322995, 0.538478, -0.689742, -0.615484, 0.381361, 0.574754, -0.380353, -0.826364, 0.415277, 0.63155, -0.39985, -0.817283, 0.414933, 0.630682, -0.380309, -0.826285, 0.415473, 0.631677, -0.981411, 0.0559147, -0.183592, 0.407121, -0.979526, 0.101914, -0.173615, 0.413635, -0.975381, 0.0881975, -0.202119, 0.415257, 0.988445, 0.140182, 0.0576755, 0.485174, 0.876515, 0.0408992, 0.479634, 0.620093, 0.848907, -0.0996824, 0.519057, 0.631268, 0.895754, -0.195088, 0.399457, 0.563346, 0.861448, -0.256989, 0.438023, 0.574909, 0.775672, -0.447481, 0.445076, 0.586422, 0.683157, -0.617557, 0.389768, 0.572247, 0.391755, -0.818722, 0.419789, 0.629264, 0.28317, -0.829384, 0.481599, 0.680529, 0.3727, -0.827422, 0.420079, 0.630298, -0.824143, -0.385255, 0.415171, 0.57215, -0.782413, -0.445128, 0.435536, 0.589267, 0.00152876, 0.999994, -0.00308275, 0.665646, 0.00242466, 0.999989, -0.0038994, 0.665879, -0.979892, 0.121321, -0.158406, 0.420287, 0.767537, -0.190214, -0.612132, 0.695479, 0.372649, -0.42747, -0.823652, 0.869878, 0.537245, -0.335515, -0.77382, 0.82472, 0.0263648, -0.598975, -0.800334, 0.873623, 0.00393345, -0.60959, -0.792707, 0.869865, -0.0183706, -0.598907, -0.800608, 0.873704, 0.00875728, 0.676014, -0.736836, 0.825597, 0.852333, -0.0355955, -0.521786, 0.607886, 0.392036, 0.534934, -0.748434, 0.818042, 0.847696, -0.122973, -0.516033, 0.615814, 0.884763, -0.0760716, -0.45979, 0.565893, 0.9446, -0.0727144, -0.320069, 0.491401, 0.904971, -0.0675211, -0.420081, 0.541673, -0.899959, -0.0647928, -0.431134, 0.544968, -0.955972, 0.108494, -0.272667, 0.452769, -0.363823, -0.426358, -0.828161, 0.871222, -0.528689, -0.333936, -0.780368, 0.826685, 0.982068, 0.118277, -0.146811, 0.416542, 0.98951, 0.144455, 0.00164104, 0.468616, 0.50797, -0.0708041, 0.85846, 0.883126, 0.748614, -0.431275, 0.503565, 0.634026, 0.214863, -0.405791, 0.888351, 0.94048, -0.901162, -0.192379, 0.388455, 0.566627, -0.867521, -0.254376, 0.427435, 0.578065, -0.226957, -0.405135, 0.885639, 0.941284, -0.756029, -0.429007, 0.494341, 0.636765, -0.00629553, -0.188362, 0.982079, 0.968197, 0.0165684, 0.999846, -0.00581961, 0.670373, 0.00313267, 0.999987, -0.00405124, 0.666103, 0.545069, 0.472158, -0.692796, 0.780052, 0.932011, 0.148856, -0.330451, 0.498417, 0.844043, 0.227673, -0.485547, 0.599903, -0.019033, 0.999801, -0.00590978, 0.672252, -0.959662, 0.239262, -0.147656, 0.488538, 0.00151234, 0.999999, -0.000399466, 0.665855, -0.988649, 0.143168, 0.0455675, 0.488784, -0.989015, 0.147444, -0.01048, 0.472227, -0.972439, 0.232727, -0.01415, 0.518344, 0.587681, -0.160147, -0.793085, 0.823999, 0.640479, -0.269179, -0.719256, 0.778142, 0.541109, -0.332896, -0.772257, 0.823226, 0.546185, -0.14771, -0.824538, 0.84854, 0.528519, -0.026044, -0.848522, 0.873136, 0.447231, -0.0756684, -0.891212, 0.903953, 0.490619, -0.0795123, -0.867739, 0.884255, 0.279393, 0.264257, -0.923097, 0.950045, 0.374653, 0.39486, -0.83888, 0.886593, 0.00050174, 0.999994, -0.00331563, 0.665976, -0.0103777, 0.999934, -0.00487936, 0.669494, -0.927571, 0.150741, -0.341889, 0.501807, -0.267268, 0.265084, -0.926444, 0.951043, -0.845984, -0.0330207, -0.532184, 0.610986, -0.518165, -0.0244575, -0.854931, 0.875047, -0.83753, 0.228953, -0.496108, 0.603116, -0.535666, 0.472122, -0.700116, 0.78259, -0.381083, 0.534649, -0.754272, 0.820328, -0.363157, 0.395975, -0.843398, 0.88794, -0.326829, -0.256634, -0.909572, 0.922946, 0.394875, -0.128601, -0.90969, 0.920236, 0.337169, -0.257642, -0.905504, 0.921733, 0.398433, -0.193767, -0.896496, 0.910015, -0.536477, -0.146072, -0.831177, 0.850523, -0.436512, -0.0743406, -0.896622, 0.905564, -0.480187, -0.0780522, -0.873687, 0.886029, -0.384093, -0.127432, -0.914458, 0.921656, -0.388009, -0.192572, -0.901313, 0.911451, 0.977045, 0.15796, 0.14294, 0.521934, 0.930035, 0.231515, 0.28537, 0.600301, -0.855499, -0.0971121, 0.508616, 0.634376, -0.875419, 0.136849, 0.463589, 0.62897, -0.882196, 0.0435387, 0.468864, 0.623303, 0.0204398, -0.0238739, 0.999506, 0.958419, -0.0062197, -0.0777937, 0.99695, 0.962769, 0.907123, 0.250746, 0.338015, 0.623205, 0.902358, 0.173321, 0.394601, 0.607696, 0.870085, 0.134211, 0.474278, 0.625782, 0.0015108, 0.999999, 6.34978e-06, 0.665945, 0.00150567, 0.999999, 0.000568537, 0.666143, 0.00150738, 0.999999, 0.000565012, 0.666141, -0.963954, 0.266039, -0.00405118, 0.539571, 0.0015136, 0.999999, -0.000393102, 0.665856, 0.00151117, 0.999999, 4.32104e-06, 0.665944, 0.0272711, 0.999604, -0.00696439, 0.673709, 0.962047, 0.236383, -0.136341, 0.484917, 0.973236, 0.229796, -0.00223071, 0.514797, 0.964728, 0.263133, 0.00776342, 0.536054, -0.906596, 0.176056, 0.383521, 0.610999, -0.978237, 0.160918, 0.130987, 0.525513, -0.910434, 0.253486, 0.326887, 0.626522, -0.932759, 0.234321, 0.27396, 0.603697, 0.800621, -0.0921333, -0.592045, 0.665278, 0.679569, -0.15358, -0.717356, 0.765121, 0.684928, -0.199829, -0.700672, 0.756959, -0.532604, -0.33128, -0.778837, 0.82519, -0.578395, -0.158384, -0.800234, 0.826134, -0.671209, -0.151537, -0.725613, 0.767576, -0.00530287, 0.323551, 0.946196, 0.94547, -0.719766, 0.229227, 0.655281, 0.774388, -0.604194, 0.29171, 0.741522, 0.841564, -0.544989, 0.302925, 0.781808, 0.866398, -0.518662, -0.0692529, 0.85217, 0.884999, -0.671987, -0.0257512, 0.740115, 0.805898, -0.00613626, -0.00823685, 0.999947, 0.957141, -0.032747, -0.0237908, 0.99918, 0.958516, -0.00530611, 0.323546, 0.946198, 0.945471, -0.545061, 0.302657, 0.781861, 0.866377, -0.639902, 0.23832, 0.730568, 0.823722, 0.00149706, 0.999997, 0.00193434, 0.667038, 0.00149731, 0.999997, 0.00193252, 0.667037, -0.0048341, 0.44008, 0.897946, 0.936327, -0.00483143, 0.440078, 0.897947, 0.936327, -0.632454, -0.267241, -0.727039, 0.780455, -0.67691, -0.197765, -0.709, 0.759436, -0.841667, -0.120432, -0.526396, 0.618913, -0.760706, -0.187792, -0.621337, 0.698143, -0.87929, -0.0734062, -0.470597, 0.569116, -0.847068, -0.0469762, -0.529405, 0.607991, -0.793572, -0.0897399, -0.601823, 0.668201, 0.536355, 0.301024, 0.788485, 0.864403, 0.536284, 0.301291, 0.788431, 0.864424, 0.595945, 0.289897, 0.748872, 0.839373, 0.631626, 0.236397, 0.738353, 0.8214, 0.712378, 0.227061, 0.664049, 0.771772, }; const unsigned int convexBunnyPointCount = 105; dReal convexBunnyPoints[] = { -0.459488, -0.093017, -0.311341, 0.466635, -0.094416, -0.305669, -0.309239, 0.776868, 0.304726, -0.004458, -0.042526, 1.01567, 8.40779e-45, 3.00321e-39, 2.8026e-44, 0.007957, 0.282241, -0.93168, 0.204445, -0.66438, 0.513353, -0.303961, 0.054199, 0.625921, 0.265619, 0.756464, 0.504187, -0.402162, 0.133528, -0.443247, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.266772, 0.64233, 0.602061, 8.40779e-45, 3.00321e-39, 2.8026e-44, 8.40779e-45, 3.00321e-39, 2.8026e-44, 0.411612, 0.132299, -0.438264, 0.31148, 0.775931, 0.308527, 0.300086, 0.053287, 0.62962, -0.414624, 0.164083, -0.278254, -0.248382, 0.255825, -0.627493, -0.216201, -0.126776, -0.886936, 0.267564, -0.666174, -0.654834, -0.135892, -0.03552, 0.945455, -0.265837, 0.757267, 0.500933, -0.003873, 0.161605, 0.970499, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.282599, -0.663393, 0.412411, 0.007237, 0.361687, -0.794439, 0.093627, 0.258494, -0.920589, 0.422146, 0.162819, -0.27313, 0.279163, -0.664604, 0.417328, 0.263086, 0.512567, 0.637832, -0.099875, 0.310931, -0.799381, -0.446838, -0.118517, -0.466159, -0.168842, 0.102387, -0.920381, 0.455805, -0.119881, -0.460632, 0.337743, -0.666396, -0.074503, -0.134547, -0.119852, -0.959004, -0.183807, 0.19697, 0.84448, 0.264969, 0.641527, 0.605317, -0.209063, -0.663393, 0.509344, -0.364126, -0.200299, 0.202388, -0.253475, -0.081797, 0.756541, 0.260471, 0.255056, -0.624378, 0.114248, 0.310608, -0.79807, 0.364663, -0.201399, 0.20685, 0.127847, -0.035919, 0.94707, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.381071, -0.629723, -0.350777, -0.339884, -0.04115, -0.668211, -0.077913, 0.258753, -0.92164, 0.184061, 0.101854, -0.91822, -0.335166, -0.66538, -0.078623, 0.386561, -0.625221, -0.21687, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.241585, 0.527592, 0.669296, -0.086969, 0.133224, 0.947633, -0.003127, 0.28407, 0.87887, -0.004433, -0.146642, 0.985872, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.138444, -0.10425, 0.945975, -0.265676, 0.513366, 0.634594, 8.40779e-45, 3.00321e-39, 2.8026e-44, 0.247593, -0.082554, 0.75961, 0.07941, 0.132973, 0.948652, 0.238615, 0.526867, 0.672237, 8.40779e-45, 3.00321e-39, 2.8026e-44, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.382112, -0.62406, -0.221577, -0.104072, 0.177278, -0.95253, 0.351567, -0.042194, -0.663976, 0.138234, -0.293905, -0.897958, 0.119916, 0.17694, -0.951159, -0.371322, -0.665382, -0.35362, -0.263384, -0.663396, 0.466604, 0.376722, -0.666513, -0.219833, 0.387086, -0.630883, -0.346073, -0.125544, 0.140012, 0.917678, -0.070612, 0.036849, 0.975733, -0.083497, -0.084934, 0.979607, 0.259286, -0.664547, 0.471281, 8.40779e-45, 3.00321e-39, 2.8026e-44, 0.074888, -0.085173, 0.980577, 0.152305, 0.125256, 0.890786, 0.130184, -0.104656, 0.94762, -0.004249, 0.046042, 1.00324, 0.062419, 0.036648, 0.976547, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.392666, -0.488581, -0.427494, 0.230315, -0.12745, -0.884202, 8.40779e-45, 3.00321e-39, 2.8026e-44, 0.193434, -0.665946, -0.715325, 0.007865, 0.122104, -0.956137, 8.40779e-45, 3.00321e-39, 2.8026e-44, -0.257884, -0.665381, -0.658052, 0.377265, -0.666513, -0.349036, -0.372362, -0.665381, -0.22442, 0.400045, -0.489778, -0.42264, -0.159174, 0.125726, 0.888878, 0.118369, 0.139643, 0.919173, -0.124463, -0.293508, -0.899566, 0.21172, -0.302754, -0.843303, 0.149571, -0.120281, -0.957264, -0.183019, -0.665378, -0.71763, 0.177696, 0.196424, 0.846693, -0.198638, -0.302135, -0.845816, }; unsigned int convexBunnyPolygons[] = { 3, 7, 2, 0, 3, 2, 7, 11, 3, 1, 15, 16, 3, 0, 2, 17, 3, 17, 9, 0, 3, 2, 9, 17, 3, 18, 9, 2, 3, 2, 11, 22, 3, 22, 15, 2, 3, 8, 15, 22, 3, 2, 15, 26, 3, 5, 26, 27, 3, 1, 14, 28, 3, 28, 15, 1, 3, 14, 15, 28, 3, 2, 26, 31, 3, 0, 9, 32, 3, 9, 18, 33, 3, 34, 14, 1, 3, 19, 33, 36, 3, 8, 22, 38, 3, 38, 22, 11, 3, 38, 15, 8, 3, 38, 16, 15, 3, 38, 30, 16, 3, 40, 7, 0, 3, 0, 25, 40, 3, 40, 25, 7, 3, 7, 25, 41, 3, 21, 37, 41, 3, 42, 15, 14, 3, 42, 27, 15, 3, 43, 26, 15, 3, 15, 27, 43, 3, 43, 27, 26, 3, 1, 16, 44, 3, 44, 29, 1, 3, 16, 29, 44, 3, 0, 32, 47, 3, 19, 32, 48, 3, 48, 33, 19, 3, 48, 32, 9, 3, 9, 33, 48, 3, 49, 33, 18, 3, 49, 18, 2, 3, 2, 31, 49, 3, 49, 26, 5, 3, 49, 31, 26, 3, 50, 42, 14, 3, 27, 42, 50, 3, 51, 35, 6, 3, 6, 39, 51, 3, 1, 29, 52, 3, 11, 37, 54, 3, 55, 23, 11, 3, 11, 54, 55, 3, 11, 23, 56, 3, 56, 38, 11, 3, 23, 38, 56, 3, 57, 39, 6, 3, 21, 41, 59, 3, 39, 57, 59, 3, 60, 37, 11, 3, 60, 41, 37, 3, 60, 11, 7, 3, 7, 41, 60, 3, 16, 30, 62, 3, 62, 29, 16, 3, 63, 38, 23, 3, 38, 63, 64, 3, 67, 25, 0, 3, 0, 47, 67, 3, 68, 36, 33, 3, 33, 49, 68, 3, 68, 49, 5, 3, 14, 34, 69, 3, 69, 50, 14, 3, 5, 27, 71, 3, 27, 50, 71, 3, 71, 68, 5, 3, 25, 51, 73, 3, 73, 51, 39, 3, 39, 59, 73, 3, 73, 41, 25, 3, 73, 59, 41, 3, 29, 35, 74, 3, 74, 52, 29, 3, 35, 51, 74, 3, 75, 34, 1, 3, 1, 52, 75, 3, 52, 74, 75, 3, 21, 55, 76, 3, 76, 54, 37, 3, 76, 55, 54, 3, 77, 55, 21, 3, 21, 59, 78, 3, 3, 77, 78, 3, 78, 77, 21, 3, 78, 57, 3, 3, 78, 59, 57, 3, 6, 35, 79, 3, 79, 35, 29, 3, 29, 62, 79, 3, 3, 57, 81, 3, 83, 62, 45, 3, 45, 81, 83, 3, 83, 79, 62, 3, 6, 79, 83, 3, 83, 57, 6, 3, 83, 81, 57, 3, 84, 63, 23, 3, 84, 77, 3, 3, 23, 55, 84, 3, 55, 77, 84, 3, 45, 63, 85, 3, 3, 81, 85, 3, 85, 81, 45, 3, 85, 84, 3, 3, 63, 84, 85, 3, 87, 47, 32, 3, 87, 72, 47, 3, 50, 69, 88, 3, 88, 34, 20, 3, 88, 69, 34, 3, 36, 68, 91, 3, 68, 71, 91, 3, 72, 87, 93, 3, 93, 87, 32, 3, 93, 32, 19, 3, 94, 74, 72, 3, 94, 93, 20, 3, 72, 93, 94, 3, 94, 75, 74, 3, 95, 74, 51, 3, 72, 74, 95, 3, 95, 51, 25, 3, 25, 67, 95, 3, 95, 67, 47, 3, 47, 72, 95, 3, 20, 34, 96, 3, 34, 75, 96, 3, 96, 94, 20, 3, 75, 94, 96, 3, 97, 37, 21, 3, 21, 76, 97, 3, 97, 76, 37, 3, 98, 64, 63, 3, 98, 63, 45, 3, 45, 82, 98, 3, 36, 70, 99, 3, 100, 88, 20, 3, 20, 90, 100, 3, 100, 90, 70, 3, 101, 71, 50, 3, 50, 88, 101, 3, 36, 91, 101, 3, 101, 91, 71, 3, 101, 70, 36, 3, 101, 100, 70, 3, 88, 100, 101, 3, 102, 90, 20, 3, 20, 93, 102, 3, 70, 90, 102, 3, 102, 99, 70, 3, 64, 98, 103, 3, 103, 98, 82, 3, 30, 38, 103, 3, 38, 64, 103, 3, 103, 62, 30, 3, 45, 62, 103, 3, 103, 82, 45, 3, 36, 99, 104, 3, 99, 102, 104, 3, 104, 102, 93, 3, 19, 36, 104, 3, 104, 93, 19, }; ode-0.14/ode/demo/demo_I.cpp0000644000000000000000000001732512635011627014311 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* test that the rotational physics is correct. an "anchor body" has a number of other randomly positioned bodies ("particles") attached to it by ball-and-socket joints, giving it some random effective inertia tensor. the effective inertia matrix is calculated, and then this inertia is assigned to another "test" body. a random torque is applied to both bodies and the difference in angular velocity and orientation is observed after a number of iterations. typical errors for each test cycle are about 1e-5 ... 1e-4. */ #include #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define NUM 10 // number of particles #define SIDE 0.1 // visual size of the particles // dynamics objects an globals static dWorldID world=0; static dBodyID anchor_body,particle[NUM],test_body; static dJointID particle_joint[NUM]; static dReal torque[3]; static int iteration; // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {1.5572f,-1.8886f,1.5700f}; static float hpr[3] = {118.5000f,-17.0000f,0.0000f}; dsSetViewpoint (xyz,hpr); } // compute the mass parameters of a particle set. q = particle positions, // pm = particle masses #define _I(i,j) I[(i)*4+(j)] void computeMassParams (dMass *m, dReal q[NUM][3], dReal pm[NUM]) { int i,j; dMassSetZero (m); for (i=0; imass += pm[i]; for (j=0; j<3; j++) m->c[j] += pm[i]*q[i][j]; m->_I(0,0) += pm[i]*(q[i][1]*q[i][1] + q[i][2]*q[i][2]); m->_I(1,1) += pm[i]*(q[i][0]*q[i][0] + q[i][2]*q[i][2]); m->_I(2,2) += pm[i]*(q[i][0]*q[i][0] + q[i][1]*q[i][1]); m->_I(0,1) -= pm[i]*(q[i][0]*q[i][1]); m->_I(0,2) -= pm[i]*(q[i][0]*q[i][2]); m->_I(1,2) -= pm[i]*(q[i][1]*q[i][2]); } for (j=0; j<3; j++) m->c[j] /= m->mass; m->_I(1,0) = m->_I(0,1); m->_I(2,0) = m->_I(0,2); m->_I(2,1) = m->_I(1,2); } void reset_test() { int i; dMass m,anchor_m; dReal q[NUM][3], pm[NUM]; // particle positions and masses dReal pos1[3] = {1,0,1}; // point of reference (POR) dReal pos2[3] = {-1,0,1}; // point of reference (POR) // make random particle positions (relative to POR) and masses for (i=0; i= 100) { // measure the difference between the anchor and test bodies const dReal *w1 = dBodyGetAngularVel (anchor_body); const dReal *w2 = dBodyGetAngularVel (test_body); const dReal *q1 = dBodyGetQuaternion (anchor_body); const dReal *q2 = dBodyGetQuaternion (test_body); dReal maxdiff = dMaxDifference (w1,w2,1,3); printf ("w-error = %.4e (%.2f,%.2f,%.2f) and (%.2f,%.2f,%.2f)\n", maxdiff,w1[0],w1[1],w1[2],w2[0],w2[1],w2[2]); maxdiff = dMaxDifference (q1,q2,1,4); printf ("q-error = %.4e\n",maxdiff); reset_test(); } } dReal sides[3] = {SIDE,SIDE,SIDE}; dReal sides2[3] = {6*SIDE,6*SIDE,6*SIDE}; dReal sides3[3] = {3*SIDE,3*SIDE,3*SIDE}; dsSetColor (1,1,1); dsDrawBox (dBodyGetPosition(anchor_body), dBodyGetRotation(anchor_body), sides3); dsSetColor (1,0,0); dsDrawBox (dBodyGetPosition(test_body), dBodyGetRotation(test_body), sides2); dsSetColor (1,1,0); for (int i=0; i #ifdef HAVE_UNISTD_H #include #endif #include #include #include "texturepath.h" #include "basket_geom.h" // this is our world mesh #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // some constants #define RADIUS 0.14 // dynamics and collision objects (chassis, 3 wheels, environment) static dWorldID world; static dSpaceID space; static dBodyID sphbody; static dGeomID sphgeom; static dJointGroupID contactgroup; static dGeomID world_mesh; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { assert(o1); assert(o2); if (dGeomIsSpace(o1) || dGeomIsSpace(o2)) { fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2); // colliding a space with something dSpaceCollide2(o1,o2,data,&nearCallback); // Note we do not want to test intersections within a space, // only between spaces. return; } // fprintf(stderr,"testing geoms %p %p\n", o1, o2); const int N = 32; dContact contact[N]; int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact)); if (n > 0) { for (int i=0; i #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif #include "icosahedron_geom.h" //<---- Convex Object dReal planes[]= // planes for a cube, these should coincide with the face array { 1.0f ,0.0f ,0.0f ,0.25f, 0.0f ,1.0f ,0.0f ,0.25f, 0.0f ,0.0f ,1.0f ,0.25f, -1.0f,0.0f ,0.0f ,0.25f, 0.0f ,-1.0f,0.0f ,0.25f, 0.0f ,0.0f ,-1.0f,0.25f /* 1.0f ,0.0f ,0.0f ,2.0f, 0.0f ,1.0f ,0.0f ,1.0f, 0.0f ,0.0f ,1.0f ,1.0f, 0.0f ,0.0f ,-1.0f,1.0f, 0.0f ,-1.0f,0.0f ,1.0f, -1.0f,0.0f ,0.0f ,0.0f */ }; const unsigned int planecount=6; dReal points[]= // points for a cube { 0.25f,0.25f,0.25f, // point 0 -0.25f,0.25f,0.25f, // point 1 0.25f,-0.25f,0.25f, // point 2 -0.25f,-0.25f,0.25f,// point 3 0.25f,0.25f,-0.25f, // point 4 -0.25f,0.25f,-0.25f,// point 5 0.25f,-0.25f,-0.25f,// point 6 -0.25f,-0.25f,-0.25f,// point 7 }; const unsigned int pointcount=8; unsigned int polygons[] = //Polygons for a cube (6 squares) { 4,0,2,6,4, // positive X 4,1,0,4,5, // positive Y 4,0,1,3,2, // positive Z 4,3,1,5,7, // negative X 4,2,3,7,6, // negative Y 4,5,4,6,7, // negative Z }; //----> Convex Object // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawConvex dsDrawConvexD #endif // some constants #define NUM 100 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 8 // maximum number of contact points per body #define MAX_FEEDBACKNUM 20 #define GRAVITY REAL(0.5) // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? static int write_world = 0; static int show_body = 0; struct MyFeedback { dJointFeedback fb; bool first; }; static int doFeedback=0; static MyFeedback feedbacks[MAX_FEEDBACKNUM]; static int fbnum=0; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact)) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command(int cmd) { size_t i; int j,k; dReal sides[3]; dMass m; bool setBody = false; cmd = locase(cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'y' || cmd == 'v') { if (num < NUM) { // new object to be created i = num; num++; } else { // recycle existing object i = nextobj++; nextobj %= num; // wrap-around if needed // destroy the body and geoms for slot i dBodyDestroy (obj[i].body); obj[i].body = 0; for (k=0; k < GPB; k++) if (obj[i].geom[k]) { dGeomDestroy(obj[i].geom[k]); obj[i].geom[k] = 0; } } obj[i].body = dBodyCreate(world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition(obj[i].body, dRandReal()*2-1,dRandReal()*2-1,dRandReal()+2); dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { // higher than highest body position dReal maxheight = 0; for (k=0; k maxheight) maxheight = pos[2]; } dBodySetPosition(obj[i].body, 0,0,maxheight+1); dRSetIdentity(R); //dRFromAxisAndAngle (R,0,0,1,/*dRandReal()*10.0-5.0*/0); } dBodySetRotation(obj[i].body,R); if (cmd == 'b') { dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]); } else if (cmd == 'v') { dMassSetBox(&m,DENSITY,0.25,0.25,0.25); #if 0 obj[i].geom[0] = dCreateConvex(space, planes, planecount, points, pointcount, polygons); #else obj[i].geom[0] = dCreateConvex(space, Sphere_planes, Sphere_planecount, Sphere_points, Sphere_pointcount, Sphere_polygons); #endif } else if (cmd == 'y') { dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere (space,sides[0]); } else if (cmd == 'x') { setBody = true; // start accumulating masses for the composite geometries dMass m2; dMassSetZero (&m); dReal dpos[GPB][3]; // delta-positions for composite geometries dMatrix3 drot[GPB]; // set random delta positions for (j=0; j= num) selected = 0; if (selected == -1) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable(obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable(obj[selected].body); } else if (cmd == 'a') { show_aabb = !show_aabb; } else if (cmd == 't') { show_contacts = !show_contacts; } else if (cmd == 'r') { random_pos = !random_pos; } else if (cmd == '1') { write_world = 1; } else if (cmd == 'p'&& selected >= 0) { const dReal* pos = dGeomGetPosition(obj[selected].geom[0]); const dReal* rot = dGeomGetRotation(obj[selected].geom[0]); printf("POSITION:\n\t[%f,%f,%f]\n\n",pos[0],pos[1],pos[2]); printf("ROTATION:\n\t[%f,%f,%f,%f]\n\t[%f,%f,%f,%f]\n\t[%f,%f,%f,%f]\n\n", rot[0],rot[1],rot[2],rot[3], rot[4],rot[5],rot[6],rot[7], rot[8],rot[9],rot[10],rot[11]); } else if (cmd == 'f' && selected >= 0 && selected < num) { if (dBodyIsEnabled(obj[selected].body)) doFeedback = 1; } } // draw a geom void drawGeom(dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { int i; if (!g) return; if (!pos) pos = dGeomGetPosition(g); if (!R) R = dGeomGetRotation(g); int type = dGeomGetClass(g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths (g,sides); dsDrawBox(pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere(pos,R,dGeomSphereGetRadius(g)); } else if (type == dCapsuleClass) { dReal radius,length; dGeomCapsuleGetParams(g,&radius,&length); dsDrawCapsule(pos,R,length,radius); } else if (type == dConvexClass) { #if 0 dsDrawConvex(pos,R,planes, planecount, points, pointcount, polygons); #else dsDrawConvex(pos,R, Sphere_planes, Sphere_planecount, Sphere_points, Sphere_pointcount, Sphere_polygons); #endif } else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams(g,&radius,&length); dsDrawCylinder(pos,R,length,radius); } if (show_body) { dBodyID body = dGeomGetBody(g); if (body) { const dReal *bodypos = dBodyGetPosition(body); const dReal *bodyr = dBodyGetRotation(body); dReal bodySides[3] = { 0.1, 0.1, 0.1 }; dsSetColorAlpha(0,1,0,1); dsDrawBox(bodypos,bodyr,bodySides); } } if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB(g,aabb); dVector3 bbpos; for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2]; dMatrix3 RI; dRSetIdentity (RI); dsSetColorAlpha(1,0,0,0.5); dsDrawBox(bbpos,RI,bbsides); } } // simulation loop static void simLoop(int pause) { dSpaceCollide(space, 0, &nearCallback); if (!pause) dWorldQuickStep(world, 0.02); if (write_world) { FILE *f = fopen("state.dif","wt"); if (f) { dWorldExportDIF(world,f,"X"); fclose (f); } write_world = 0; } if (doFeedback) { if (fbnum>MAX_FEEDBACKNUM) printf("joint feedback buffer overflow!\n"); else { dVector3 sum = {0, 0, 0}; printf("\n"); for (int i=0; i #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define LENGTH 0.7 // chassis length #define WIDTH 0.5 // chassis width #define HEIGHT 0.2 // chassis height #define RADIUS 0.18 // wheel radius #define STARTZ 0.5 // starting height of chassis #define CMASS 1 // chassis mass #define WMASS 0.2 // wheel mass // dynamics and collision objects (chassis, 3 wheels, environment) static dWorldID world; static dSpaceID space; static dBodyID body[4]; static dJointID joint[3]; // joint[0] is the front wheel static dJointGroupID contactgroup; static dGeomID ground; static dSpaceID car_space; static dGeomID box[1]; static dGeomID sphere[3]; static dGeomID ground_box; // things that the user controls static dReal speed=0,steer=0; // user commands // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i,n; // only collide things with the ground int g1 = (o1 == ground || o1 == ground_box); int g2 = (o2 == ground || o2 == ground_box); if (!(g1 ^ g2)) return; const int N = 10; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact)); if (n > 0) { for (i=0; i 0.1) v = 0.1; if (v < -0.1) v = -0.1; v *= 10.0; dJointSetHinge2Param (joint[0],dParamVel,v); dJointSetHinge2Param (joint[0],dParamFMax,0.2); dJointSetHinge2Param (joint[0],dParamLoStop,-0.75); dJointSetHinge2Param (joint[0],dParamHiStop,0.75); dJointSetHinge2Param (joint[0],dParamFudgeFactor,0.1); dSpaceCollide (space,0,&nearCallback); dWorldStep (world,0.05); // remove all contact joints dJointGroupEmpty (contactgroup); } dsSetColor (0,1,1); dsSetTexture (DS_WOOD); dReal sides[3] = {LENGTH,WIDTH,HEIGHT}; dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides); dsSetColor (1,1,1); for (i=1; i<=3; i++) dsDrawCylinder (dBodyGetPosition(body[i]), dBodyGetRotation(body[i]),0.02f,RADIUS); dVector3 ss; dGeomBoxGetLengths (ground_box,ss); dsDrawBox (dGeomGetPosition(ground_box),dGeomGetRotation(ground_box),ss); } int main (int argc, char **argv) { int i; dMass m; // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE2(0); world = dWorldCreate(); space = dHashSpaceCreate (0); contactgroup = dJointGroupCreate (0); dWorldSetGravity (world,0,0,-0.5); ground = dCreatePlane (space,0,0,1,0); // chassis body body[0] = dBodyCreate (world); dBodySetPosition (body[0],0,0,STARTZ); dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT); dMassAdjust (&m,CMASS); dBodySetMass (body[0],&m); box[0] = dCreateBox (0,LENGTH,WIDTH,HEIGHT); dGeomSetBody (box[0],body[0]); // wheel bodies for (i=1; i<=3; i++) { body[i] = dBodyCreate (world); dQuaternion q; dQFromAxisAndAngle (q,1,0,0,M_PI*0.5); dBodySetQuaternion (body[i],q); dMassSetSphere (&m,1,RADIUS); dMassAdjust (&m,WMASS); dBodySetMass (body[i],&m); sphere[i-1] = dCreateSphere (0,RADIUS); dGeomSetBody (sphere[i-1],body[i]); } dBodySetPosition (body[1],0.5*LENGTH,0,STARTZ-HEIGHT*0.5); dBodySetPosition (body[2],-0.5*LENGTH, WIDTH*0.5,STARTZ-HEIGHT*0.5); dBodySetPosition (body[3],-0.5*LENGTH,-WIDTH*0.5,STARTZ-HEIGHT*0.5); // front and back wheel hinges for (i=0; i<3; i++) { joint[i] = dJointCreateHinge2 (world,0); dJointAttach (joint[i],body[0],body[i+1]); const dReal *a = dBodyGetPosition (body[i+1]); dJointSetHinge2Anchor (joint[i],a[0],a[1],a[2]); dJointSetHinge2Axis1 (joint[i],0,0,1); dJointSetHinge2Axis2 (joint[i],0,1,0); } // set joint suspension for (i=0; i<3; i++) { dJointSetHinge2Param (joint[i],dParamSuspensionERP,0.4); dJointSetHinge2Param (joint[i],dParamSuspensionCFM,0.8); } // lock back wheels along the steering axis for (i=1; i<3; i++) { // set stops to make sure wheels always stay in alignment dJointSetHinge2Param (joint[i],dParamLoStop,0); dJointSetHinge2Param (joint[i],dParamHiStop,0); // the following alternative method is no good as the wheels may get out // of alignment: // dJointSetHinge2Param (joint[i],dParamVel,0); // dJointSetHinge2Param (joint[i],dParamFMax,dInfinity); } // create car space and add it to the top level space car_space = dSimpleSpaceCreate (space); dSpaceSetCleanup (car_space,0); dSpaceAdd (car_space,box[0]); dSpaceAdd (car_space,sphere[0]); dSpaceAdd (car_space,sphere[1]); dSpaceAdd (car_space,sphere[2]); // environment ground_box = dCreateBox (space,2,1.5,1); dMatrix3 R; dRFromAxisAndAngle (R,0,1,0,-0.15); dGeomSetPosition (ground_box,2,0,-0.34); dGeomSetRotation (ground_box,R); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dGeomDestroy (box[0]); dGeomDestroy (sphere[0]); dGeomDestroy (sphere[1]); dGeomDestroy (sphere[2]); dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_cards.cpp0000644000000000000000000001505412635011627015212 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include #include "texturepath.h" #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #endif static int levels = 5; static int ncards = 0; static dSpaceID space; static dWorldID world; static dJointGroupID contactgroup; struct Card { dBodyID body; dGeomID geom; static const dReal sides[3]; Card() { body = dBodyCreate(world); geom = dCreateBox(space, sides[0], sides[1], sides[2]); dGeomSetBody(geom, body); dGeomSetData(geom, this); dMass mass; mass.setBox(1, sides[0], sides[1], sides[2]); dBodySetMass(body, &mass); } ~Card() { dBodyDestroy(body); dGeomDestroy(geom); } void draw() const { dsDrawBox(dBodyGetPosition(body), dBodyGetRotation(body), sides); } }; static const dReal cwidth=.5, cthikness=.02, clength=1; const dReal Card::sides[3] = { cwidth, cthikness, clength }; std::vector cards; int getncards(int levels) { return (3*levels*levels + levels) / 2; } void place_cards() { ncards = getncards(levels); // destroy removed cards (if any) int oldcards = cards.size(); for (int i=ncards; ibody, 0, -n*hstep + hstep*i, height ); if (i%2) dBodySetRotation(cards[c]->body, left); else dBodySetRotation(cards[c]->body, right); } if (n==1) // top of the house break; // horizontal cards for (int i=0; ibody, 0, -(n-1 - (clength-hstep)/2)*hstep + 2*hstep*i, height + vstep/2); dBodySetRotation(cards[c]->body, hrot); } } } void start() { puts("Controls:"); puts(" SPACE - reposition cards"); puts(" - - one less level"); puts(" = - one more level"); } static void nearCallback (void *, dGeomID o1, dGeomID o2) { // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); const int MAX_CONTACTS = 8; dContact contact[MAX_CONTACTS]; int numc = dCollide (o1, o2, MAX_CONTACTS, &contact[0].geom, sizeof(dContact)); for (int i=0; idraw(); } } void command(int c) { switch (c) { case '=': levels++; place_cards(); break; case '-': levels--; if (levels <= 0) levels++; place_cards(); break; case ' ': place_cards(); break; } } int main(int argc, char **argv) { dInitODE(); // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; world = dWorldCreate(); dWorldSetGravity(world, 0, 0, -0.5); dWorldSetQuickStepNumIterations(world, 50); // <-- increase for more stability space = dSimpleSpaceCreate(0); contactgroup = dJointGroupCreate(0); dGeomID ground = dCreatePlane(space, 0, 0, 1, 0); place_cards(); // run simulation dsSimulationLoop (argc, argv, 640, 480, &fn); levels = 0; place_cards(); dJointGroupDestroy(contactgroup); dWorldDestroy(world); dGeomDestroy(ground); dSpaceDestroy(space); dCloseODE(); } ode-0.14/ode/demo/demo_chain1.c0000644000000000000000000001160112635011627014713 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* exercise the C interface */ #include #include "ode/ode.h" #include "drawstuff/drawstuff.h" #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) /* for VC++, no precision loss complaints */ #endif /* select correct drawing functions */ #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif /* some constants */ #define NUM 10 /* number of boxes */ #define SIDE (0.2) /* side length of a box */ #define MASS (1.0) /* mass of a box */ #define RADIUS (0.1732f) /* sphere radius */ /* dynamics and collision objects */ static dWorldID world; static dSpaceID space; static dBodyID body[NUM]; static dJointID joint[NUM-1]; static dJointGroupID contactgroup; static dGeomID sphere[NUM]; /* this is called by dSpaceCollide when two objects in space are * potentially colliding. */ static void nearCallback (void *data, dGeomID o1, dGeomID o2) { /* exit without doing anything if the two bodies are connected by a joint */ dBodyID b1,b2; dContact contact; (void)data; b1 = dGeomGetBody(o1); b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnected (b1,b2)) return; contact.surface.mode = 0; contact.surface.mu = 0.1; contact.surface.mu2 = 0; if (dCollide (o1,o2,1,&contact.geom,sizeof(dContactGeom))) { dJointID c = dJointCreateContact (world,contactgroup,&contact); dJointAttach (c,b1,b2); } } /* start simulation - set viewpoint */ static void start() { static float xyz[3] = {2.1640f,-1.3079f,1.7600f}; static float hpr[3] = {125.5000f,-17.0000f,0.0000f}; dAllocateODEDataForThread(dAllocateMaskAll); dsSetViewpoint (xyz,hpr); } /* simulation loop */ static void simLoop (int pause) { int i; if (!pause) { static double angle = 0; angle += 0.05; dBodyAddForce (body[NUM-1],0,0,1.5*(sin(angle)+1.0)); dSpaceCollide (space,0,&nearCallback); dWorldStep (world,0.05); /* remove all contact joints */ dJointGroupEmpty (contactgroup); } dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (i=0; i #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define NUM 10 // number of boxes #define SIDE (0.2) // side length of a box #define MASS (1.0) // mass of a box #define RADIUS (0.1732f) // sphere radius //using namespace ode; // dynamics and collision objects static dWorld world; static dSimpleSpace space (0); static dBody body[NUM]; static dBallJoint joint[NUM-1]; static dJointGroup contactgroup; static dBox box[NUM]; // this is called by space.collide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnected (b1,b2)) return; // @@@ it's still more convenient to use the C interface here. dContact contact; contact.surface.mode = 0; contact.surface.mu = dInfinity; if (dCollide (o1,o2,1,&contact.geom,sizeof(dContactGeom))) { dJointID c = dJointCreateContact (world.id(),contactgroup.id(),&contact); dJointAttach (c,b1,b2); } } // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {2.1640f,-1.3079f,1.7600f}; static float hpr[3] = {125.5000f,-17.0000f,0.0000f}; dsSetViewpoint (xyz,hpr); } // simulation loop static void simLoop (int pause) { if (!pause) { static double angle = 0; angle += 0.05; body[NUM-1].addForce (0,0,1.5*(sin(angle)+1.0)); space.collide (0,&nearCallback); world.step (0.05); // remove all contact joints contactgroup.empty(); } dReal sides[3] = {SIDE,SIDE,SIDE}; dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (int i=0; i #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawSphere dsDrawSphereD #define dsDrawBox dsDrawBoxD #define dsDrawLine dsDrawLineD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawCylinder dsDrawCylinderD #endif //**************************************************************************** // test infrastructure, including constants and macros #define TEST_REPS1 1000 // run each test this many times (first batch) #define TEST_REPS2 10000 // run each test this many times (second batch) const dReal tol = 1e-8; // tolerance used for numerical checks #define MAX_TESTS 1000 // maximum number of test slots #define Z_OFFSET 2 // z offset for drawing (to get above ground) //using namespace ode; // test function. returns 1 if the test passed or 0 if it failed typedef int test_function_t(); struct TestSlot { int number; // number of test const char *name; // name of test int failcount; test_function_t *test_fn; int last_failed_line; }; TestSlot testslot[MAX_TESTS]; // globals used by the test functions int graphical_test=0; // show graphical results of this test, 0=none int current_test; // currently execiting test int draw_all_objects_called; #define MAKE_TEST(number,function) \ if (testslot[number].name) dDebug (0,"test number already used"); \ if (number <= 0 || number >= MAX_TESTS) dDebug (0,"bad test number"); \ testslot[number].name = # function; \ testslot[number].test_fn = function; #define FAILED() { if (graphical_test==0) { \ testslot[current_test].last_failed_line=__LINE__; return 0; } } #define PASSED() { return 1; } //**************************************************************************** // globals /* int dBoxBox (const dVector3 p1, const dMatrix3 R1, const dVector3 side1, const dVector3 p2, const dMatrix3 R2, const dVector3 side2, dVector3 normal, dReal *depth, int *code, int maxc, dContactGeom *contact, int skip); */ void dLineClosestApproach (const dVector3 pa, const dVector3 ua, const dVector3 pb, const dVector3 ub, dReal *alpha, dReal *beta); //**************************************************************************** // draw all objects in a space, and draw all the collision contact points void nearCallback (void *, dGeomID o1, dGeomID o2) { int i,j,n; const int N = 100; dContactGeom contact[N]; if (dGeomGetClass (o2) == dRayClass) { n = dCollide (o2,o1,N,&contact[0],sizeof(dContactGeom)); } else { n = dCollide (o1,o2,N,&contact[0],sizeof(dContactGeom)); } if (n > 0) { dMatrix3 RI; dRSetIdentity (RI); const dReal ss[3] = {0.01,0.01,0.01}; for (i=0; i tol) FAILED(); // ********** test point on surface has depth 0 for (j=0; j<3; j++) q[j] = dRandReal()-0.5; dNormalize3 (q); for (j=0; j<3; j++) q[j] = q[j]*r + p[j]; if (dFabs(dGeomSpherePointDepth (sphere,q[0],q[1],q[2])) > tol) FAILED(); // ********** test point at random depth d = (dRandReal()*2-1) * r; for (j=0; j<3; j++) q[j] = dRandReal()-0.5; dNormalize3 (q); for (j=0; j<3; j++) q[j] = q[j]*(r-d) + p[j]; if (dFabs(dGeomSpherePointDepth (sphere,q[0],q[1],q[2])-d) > tol) FAILED(); PASSED(); } int test_box_point_depth() { int i,j; dVector3 s,p,q,q2; // s = box sides dMatrix3 R; dReal ss,d; // ss = smallest side dSimpleSpace space(0); dGeomID box = dCreateBox (0,1,1,1); dSpaceAdd (space,box); // ********** make a random box for (j=0; j<3; j++) s[j] = dRandReal() + 0.1; dGeomBoxSetLengths (box,s[0],s[1],s[2]); dMakeRandomVector (p,3,1.0); dGeomSetPosition (box,p[0],p[1],p[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (box,R); // ********** test center point has depth of smallest side ss = 1e9; for (j=0; j<3; j++) if (s[j] < ss) ss = s[j]; if (dFabs(dGeomBoxPointDepth (box,p[0],p[1],p[2]) - 0.5*ss) > tol) FAILED(); // ********** test point on surface has depth 0 for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j]; i = dRandInt (3); if (dRandReal() > 0.5) q[i] = 0.5*s[i]; else q[i] = -0.5*s[i]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; if (dFabs(dGeomBoxPointDepth (box,q2[0],q2[1],q2[2])) > tol) FAILED(); // ********** test points outside box have -ve depth for (j=0; j<3; j++) { q[j] = 0.5*s[j] + dRandReal() + 0.01; if (dRandReal() > 0.5) q[j] = -q[j]; } dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; if (dGeomBoxPointDepth (box,q2[0],q2[1],q2[2]) >= 0) FAILED(); // ********** test points inside box have +ve depth for (j=0; j<3; j++) q[j] = s[j] * 0.99 * (dRandReal()-0.5); dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; if (dGeomBoxPointDepth (box,q2[0],q2[1],q2[2]) <= 0) FAILED(); // ********** test random depth of point aligned along axis (up to ss deep) i = dRandInt (3); for (j=0; j<3; j++) q[j] = 0; d = (dRandReal()*(ss*0.5+1)-1); q[i] = s[i]*0.5 - d; if (dRandReal() > 0.5) q[i] = -q[i]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; if (dFabs(dGeomBoxPointDepth (box,q2[0],q2[1],q2[2]) - d) >= tol) FAILED(); PASSED(); } int test_ccylinder_point_depth() { int j; dVector3 p,a; dMatrix3 R; dReal r,l,beta,x,y,d; dSimpleSpace space(0); dGeomID ccyl = dCreateCapsule (0,1,1); dSpaceAdd (space,ccyl); // ********** make a random ccyl r = dRandReal()*0.5 + 0.01; l = dRandReal()*1 + 0.01; dGeomCapsuleSetParams (ccyl,r,l); dMakeRandomVector (p,3,1.0); dGeomSetPosition (ccyl,p[0],p[1],p[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (ccyl,R); // ********** test point on axis has depth of 'radius' beta = dRandReal()-0.5; for (j=0; j<3; j++) a[j] = p[j] + l*beta*R[j*4+2]; if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) - r) >= tol) FAILED(); // ********** test point on surface (excluding caps) has depth 0 beta = dRandReal()*2*M_PI; x = r*sin(beta); y = r*cos(beta); beta = dRandReal()-0.5; for (j=0; j<3; j++) a[j] = p[j] + x*R[j*4+0] + y*R[j*4+1] + l*beta*R[j*4+2]; if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2])) >= tol) FAILED(); // ********** test point on surface of caps has depth 0 for (j=0; j<3; j++) a[j] = dRandReal()-0.5; dNormalize3 (a); if (dCalcVectorDot3_14(a,R+2) > 0) { for (j=0; j<3; j++) a[j] = p[j] + a[j]*r + l*0.5*R[j*4+2]; } else { for (j=0; j<3; j++) a[j] = p[j] + a[j]*r - l*0.5*R[j*4+2]; } if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2])) >= tol) FAILED(); // ********** test point inside ccyl has positive depth for (j=0; j<3; j++) a[j] = dRandReal()-0.5; dNormalize3 (a); beta = dRandReal()-0.5; for (j=0; j<3; j++) a[j] = p[j] + a[j]*r*0.99 + l*beta*R[j*4+2]; if (dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) < 0) FAILED(); // ********** test point depth (1) d = (dRandReal()*2-1) * r; beta = dRandReal()*2*M_PI; x = (r-d)*sin(beta); y = (r-d)*cos(beta); beta = dRandReal()-0.5; for (j=0; j<3; j++) a[j] = p[j] + x*R[j*4+0] + y*R[j*4+1] + l*beta*R[j*4+2]; if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) - d) >= tol) FAILED(); // ********** test point depth (2) d = (dRandReal()*2-1) * r; for (j=0; j<3; j++) a[j] = dRandReal()-0.5; dNormalize3 (a); if (dCalcVectorDot3_14(a,R+2) > 0) { for (j=0; j<3; j++) a[j] = p[j] + a[j]*(r-d) + l*0.5*R[j*4+2]; } else { for (j=0; j<3; j++) a[j] = p[j] + a[j]*(r-d) - l*0.5*R[j*4+2]; } if (dFabs(dGeomCapsulePointDepth (ccyl,a[0],a[1],a[2]) - d) >= tol) FAILED(); PASSED(); } int test_plane_point_depth() { int j; dVector3 n,p,q,a,b; // n = plane normal dReal d; dSimpleSpace space(0); dGeomID plane = dCreatePlane (0,0,0,1,0); dSpaceAdd (space,plane); // ********** make a random plane for (j=0; j<3; j++) n[j] = dRandReal() - 0.5; dNormalize3 (n); d = dRandReal() - 0.5; dGeomPlaneSetParams (plane,n[0],n[1],n[2],d); dPlaneSpace (n,p,q); // ********** test point on plane has depth 0 a[0] = dRandReal() - 0.5; a[1] = dRandReal() - 0.5; a[2] = 0; for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j]; if (dFabs(dGeomPlanePointDepth (plane,b[0],b[1],b[2])) >= tol) FAILED(); // ********** test arbitrary depth point a[0] = dRandReal() - 0.5; a[1] = dRandReal() - 0.5; a[2] = dRandReal() - 0.5; for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j]; if (dFabs(dGeomPlanePointDepth (plane,b[0],b[1],b[2]) + a[2]) >= tol) FAILED(); // ********** test depth-1 point a[0] = dRandReal() - 0.5; a[1] = dRandReal() - 0.5; a[2] = -1; for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j]; if (dFabs(dGeomPlanePointDepth (plane,b[0],b[1],b[2]) - 1) >= tol) FAILED(); PASSED(); } //**************************************************************************** // ray tests int test_ray_and_sphere() { int j; dContactGeom contact; dVector3 p,q,q2,n,v1; dMatrix3 R; dReal r,k; dSimpleSpace space(0); dGeomID ray = dCreateRay (0,0); dGeomID sphere = dCreateSphere (0,1); dSpaceAdd (space,ray); dSpaceAdd (space,sphere); // ********** make a random sphere of radius r at position p r = dRandReal()+0.1; dGeomSphereSetRadius (sphere,r); dMakeRandomVector (p,3,1.0); dGeomSetPosition (sphere,p[0],p[1],p[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (sphere,R); // ********** test zero length ray just inside sphere dGeomRaySetLength (ray,0); dMakeRandomVector (q,3,1.0); dNormalize3 (q); for (j=0; j<3; j++) q[j] = 0.99*r * q[j] + p[j]; dGeomSetPosition (ray,q[0],q[1],q[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (ray,R); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test zero length ray just outside that sphere dGeomRaySetLength (ray,0); dMakeRandomVector (q,3,1.0); dNormalize3 (q); for (j=0; j<3; j++) q[j] = 1.01*r * q[j] + p[j]; dGeomSetPosition (ray,q[0],q[1],q[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (ray,R); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test finite length ray totally contained inside the sphere dMakeRandomVector (q,3,1.0); dNormalize3 (q); k = dRandReal(); for (j=0; j<3; j++) q[j] = k*r*0.99 * q[j] + p[j]; dMakeRandomVector (q2,3,1.0); dNormalize3 (q2); k = dRandReal(); for (j=0; j<3; j++) q2[j] = k*r*0.99 * q2[j] + p[j]; for (j=0; j<3; j++) n[j] = q2[j] - q[j]; dNormalize3 (n); dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,dCalcPointsDistance3(q,q2)); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test finite length ray totally outside the sphere dMakeRandomVector (q,3,1.0); dNormalize3 (q); do { dMakeRandomVector (n,3,1.0); dNormalize3 (n); } while (dCalcVectorDot3(n,q) < 0); // make sure normal goes away from sphere for (j=0; j<3; j++) q[j] = 1.01*r * q[j] + p[j]; dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,100); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray from outside to just above surface dMakeRandomVector (q,3,1.0); dNormalize3 (q); for (j=0; j<3; j++) n[j] = -q[j]; for (j=0; j<3; j++) q2[j] = 2*r * q[j] + p[j]; dGeomRaySet (ray,q2[0],q2[1],q2[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,0.99*r); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray from outside to just below surface dGeomRaySetLength (ray,1.01*r); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); for (j=0; j<3; j++) q2[j] = r * q[j] + p[j]; if (dCalcPointsDistance3 (contact.pos,q2) > tol) FAILED(); // ********** test contact point distance for random rays dMakeRandomVector (q,3,1.0); dNormalize3 (q); k = dRandReal()+0.5; for (j=0; j<3; j++) q[j] = k*r * q[j] + p[j]; dMakeRandomVector (n,3,1.0); dNormalize3 (n); dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,100); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom))) { k = dCalcPointsDistance3 (contact.pos,dGeomGetPosition(sphere)); if (dFabs(k - r) > tol) FAILED(); // also check normal signs if (dCalcVectorDot3 (n,contact.normal) > 0) FAILED(); // also check depth of contact point if (dFabs (dGeomSpherePointDepth (sphere,contact.pos[0],contact.pos[1],contact.pos[2])) > tol) FAILED(); draw_all_objects (space); } // ********** test tangential grazing - miss dMakeRandomVector (q,3,1.0); dNormalize3 (q); dPlaneSpace (q,n,v1); for (j=0; j<3; j++) q[j] = 1.01*r * q[j] + p[j]; for (j=0; j<3; j++) q[j] -= n[j]; dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,2); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test tangential grazing - hit dMakeRandomVector (q,3,1.0); dNormalize3 (q); dPlaneSpace (q,n,v1); for (j=0; j<3; j++) q[j] = 0.99*r * q[j] + p[j]; for (j=0; j<3; j++) q[j] -= n[j]; dGeomRaySet (ray,q[0],q[1],q[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,2); if (dCollide (ray,sphere,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); PASSED(); } int test_ray_and_box() { int i,j; dContactGeom contact; dVector3 s,p,q,n,q2,q3,q4; // s = box sides dMatrix3 R; dReal k; dSimpleSpace space(0); dGeomID ray = dCreateRay (0,0); dGeomID box = dCreateBox (0,1,1,1); dSpaceAdd (space,ray); dSpaceAdd (space,box); // ********** make a random box for (j=0; j<3; j++) s[j] = dRandReal() + 0.1; dGeomBoxSetLengths (box,s[0],s[1],s[2]); dMakeRandomVector (p,3,1.0); dGeomSetPosition (box,p[0],p[1],p[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (box,R); // ********** test zero length ray just inside box dGeomRaySetLength (ray,0); for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j]; i = dRandInt (3); if (dRandReal() > 0.5) q[i] = 0.99*0.5*s[i]; else q[i] = -0.99*0.5*s[i]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; dGeomSetPosition (ray,q2[0],q2[1],q2[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (ray,R); if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test zero length ray just outside box dGeomRaySetLength (ray,0); for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j]; i = dRandInt (3); if (dRandReal() > 0.5) q[i] = 1.01*0.5*s[i]; else q[i] = -1.01*0.5*s[i]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; dGeomSetPosition (ray,q2[0],q2[1],q2[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (ray,R); if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test finite length ray totally contained inside the box for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*0.99*s[j]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; for (j=0; j<3; j++) q3[j] = (dRandReal()-0.5)*0.99*s[j]; dMultiply0 (q4,dGeomGetRotation(box),q3,3,3,1); for (j=0; j<3; j++) q4[j] += p[j]; for (j=0; j<3; j++) n[j] = q4[j] - q2[j]; dNormalize3 (n); dGeomRaySet (ray,q2[0],q2[1],q2[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,dCalcPointsDistance3(q2,q4)); if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test finite length ray totally outside the box for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j]; i = dRandInt (3); if (dRandReal() > 0.5) q[i] = 1.01*0.5*s[i]; else q[i] = -1.01*0.5*s[i]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q3[j] = q2[j] + p[j]; dNormalize3 (q2); dGeomRaySet (ray,q3[0],q3[1],q3[2],q2[0],q2[1],q2[2]); dGeomRaySetLength (ray,10); if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray from outside to just above surface for (j=0; j<3; j++) q[j] = (dRandReal()-0.5)*s[j]; i = dRandInt (3); if (dRandReal() > 0.5) q[i] = 1.01*0.5*s[i]; else q[i] = -1.01*0.5*s[i]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q3[j] = 2*q2[j] + p[j]; k = dSqrt(q2[0]*q2[0] + q2[1]*q2[1] + q2[2]*q2[2]); for (j=0; j<3; j++) q2[j] = -q2[j]; dGeomRaySet (ray,q3[0],q3[1],q3[2],q2[0],q2[1],q2[2]); dGeomRaySetLength (ray,k*0.99); if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray from outside to just below surface dGeomRaySetLength (ray,k*1.01); if (dCollide (ray,box,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); // ********** test contact point position for random rays for (j=0; j<3; j++) q[j] = dRandReal()*s[j]; dMultiply0 (q2,dGeomGetRotation(box),q,3,3,1); for (j=0; j<3; j++) q2[j] += p[j]; for (j=0; j<3; j++) q3[j] = dRandReal()-0.5; dNormalize3 (q3); dGeomRaySet (ray,q2[0],q2[1],q2[2],q3[0],q3[1],q3[2]); dGeomRaySetLength (ray,10); if (dCollide (ray,box,1,&contact,sizeof(dContactGeom))) { // check depth of contact point if (dFabs (dGeomBoxPointDepth (box,contact.pos[0],contact.pos[1],contact.pos[2])) > tol) FAILED(); // check position of contact point for (j=0; j<3; j++) contact.pos[j] -= p[j]; dMultiply1 (q,dGeomGetRotation(box),contact.pos,3,3,1); if ( dFabs(dFabs (q[0]) - 0.5*s[0]) > tol && dFabs(dFabs (q[1]) - 0.5*s[1]) > tol && dFabs(dFabs (q[2]) - 0.5*s[2]) > tol) { FAILED(); } // also check normal signs if (dCalcVectorDot3 (q3,contact.normal) > 0) FAILED(); draw_all_objects (space); } PASSED(); } int test_ray_and_ccylinder() { int j; dContactGeom contact; dVector3 p,a,b,n; dMatrix3 R; dReal r,l,k,x,y; dSimpleSpace space(0); dGeomID ray = dCreateRay (0,0); dGeomID ccyl = dCreateCapsule (0,1,1); dSpaceAdd (space,ray); dSpaceAdd (space,ccyl); // ********** make a random capped cylinder r = dRandReal()*0.5 + 0.01; l = dRandReal()*1 + 0.01; dGeomCapsuleSetParams (ccyl,r,l); dMakeRandomVector (p,3,1.0); dGeomSetPosition (ccyl,p[0],p[1],p[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (ccyl,R); // ********** test ray completely within ccyl for (j=0; j<3; j++) a[j] = dRandReal()-0.5; dNormalize3 (a); k = (dRandReal()-0.5)*l; for (j=0; j<3; j++) a[j] = p[j] + r*0.99*a[j] + k*0.99*R[j*4+2]; for (j=0; j<3; j++) b[j] = dRandReal()-0.5; dNormalize3 (b); k = (dRandReal()-0.5)*l; for (j=0; j<3; j++) b[j] = p[j] + r*0.99*b[j] + k*0.99*R[j*4+2]; dGeomRaySetLength (ray,dCalcPointsDistance3(a,b)); for (j=0; j<3; j++) b[j] -= a[j]; dNormalize3 (b); dGeomRaySet (ray,a[0],a[1],a[2],b[0],b[1],b[2]); if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray outside ccyl that just misses (between caps) k = dRandReal()*2*M_PI; x = sin(k); y = cos(k); for (j=0; j<3; j++) a[j] = x*R[j*4+0] + y*R[j*4+1]; k = (dRandReal()-0.5)*l; for (j=0; j<3; j++) b[j] = -a[j]*r*2 + k*R[j*4+2] + p[j]; dGeomRaySet (ray,b[0],b[1],b[2],a[0],a[1],a[2]); dGeomRaySetLength (ray,r*0.99); if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray outside ccyl that just hits (between caps) dGeomRaySetLength (ray,r*1.01); if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); // check depth of contact point if (dFabs (dGeomCapsulePointDepth (ccyl,contact.pos[0],contact.pos[1],contact.pos[2])) > tol) FAILED(); // ********** test ray outside ccyl that just misses (caps) for (j=0; j<3; j++) a[j] = dRandReal()-0.5; dNormalize3 (a); if (dCalcVectorDot3_14(a,R+2) < 0) { for (j=0; j<3; j++) b[j] = p[j] - a[j]*2*r + l*0.5*R[j*4+2]; } else { for (j=0; j<3; j++) b[j] = p[j] - a[j]*2*r - l*0.5*R[j*4+2]; } dGeomRaySet (ray,b[0],b[1],b[2],a[0],a[1],a[2]); dGeomRaySetLength (ray,r*0.99); if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray outside ccyl that just hits (caps) dGeomRaySetLength (ray,r*1.01); if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); // check depth of contact point if (dFabs (dGeomCapsulePointDepth (ccyl,contact.pos[0],contact.pos[1],contact.pos[2])) > tol) FAILED(); // ********** test random rays for (j=0; j<3; j++) a[j] = dRandReal()-0.5; for (j=0; j<3; j++) n[j] = dRandReal()-0.5; dNormalize3 (n); dGeomRaySet (ray,a[0],a[1],a[2],n[0],n[1],n[2]); dGeomRaySetLength (ray,10); if (dCollide (ray,ccyl,1,&contact,sizeof(dContactGeom))) { // check depth of contact point if (dFabs (dGeomCapsulePointDepth (ccyl,contact.pos[0],contact.pos[1],contact.pos[2])) > tol) FAILED(); // check normal signs if (dCalcVectorDot3 (n,contact.normal) > 0) FAILED(); draw_all_objects (space); } PASSED(); } /* Test rays within the cylinder -completely inside -exiting through side -exiting through cap -exiting through corner Test rays outside the cylinder */ int test_ray_and_cylinder() { dVector3 a,b; dSimpleSpace space(0); dGeomID ray = dCreateRay(space,4); // The first thing that happens is the ray is // rotated into cylinder coordinates. We'll trust that's // done right. The major axis is in the z-dir. // Random tests /*b[0]=4*dRandReal()-2; b[1]=4*dRandReal()-2; b[2]=4*dRandReal()-2; a[0]=2*dRandReal()-1; a[1]=2*dRandReal()-1; a[2]=2*dRandReal()-1;*/ // Inside out b[0]=dRandReal()-0.5; b[1]=dRandReal()-0.5; b[2]=dRandReal()-0.5; a[0]=2*dRandReal()-1; a[1]=2*dRandReal()-1; a[2]=2*dRandReal()-1; // Outside in /*b[0]=4*dRandReal()-2; b[1]=4*dRandReal()-2; b[2]=4*dRandReal()-2; a[0]=-b[0]; a[1]=-b[1]; a[2]=-b[2];*/ dGeomRaySet (ray,b[0],b[1],b[2],a[0],a[1],a[2]); // This is just for visual inspection right now. //if (dCollide (ray,cyl,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); draw_all_objects (space); PASSED(); } int test_ray_and_plane() { int j; dContactGeom contact; dVector3 n,p,q,a,b,g,h; // n,d = plane parameters dMatrix3 R; dReal d; dSimpleSpace space(0); dGeomID ray = dCreateRay (0,0); dGeomID plane = dCreatePlane (0,0,0,1,0); dSpaceAdd (space,ray); dSpaceAdd (space,plane); // ********** make a random plane for (j=0; j<3; j++) n[j] = dRandReal() - 0.5; dNormalize3 (n); d = dRandReal() - 0.5; dGeomPlaneSetParams (plane,n[0],n[1],n[2],d); dPlaneSpace (n,p,q); // ********** test finite length ray below plane dGeomRaySetLength (ray,0.09); a[0] = dRandReal()-0.5; a[1] = dRandReal()-0.5; a[2] = -dRandReal()*0.5 - 0.1; for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j]; dGeomSetPosition (ray,b[0],b[1],b[2]); dRFromAxisAndAngle (R,dRandReal()*2-1,dRandReal()*2-1, dRandReal()*2-1,dRandReal()*10-5); dGeomSetRotation (ray,R); if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test finite length ray above plane a[0] = dRandReal()-0.5; a[1] = dRandReal()-0.5; a[2] = dRandReal()*0.5 + 0.01; for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j]; g[0] = dRandReal()-0.5; g[1] = dRandReal()-0.5; g[2] = dRandReal() + 0.01; for (j=0; j<3; j++) h[j] = g[0]*p[j] + g[1]*q[j] + g[2]*n[j]; dNormalize3 (h); dGeomRaySet (ray,b[0],b[1],b[2],h[0],h[1],h[2]); dGeomRaySetLength (ray,10); if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test finite length ray that intersects plane a[0] = dRandReal()-0.5; a[1] = dRandReal()-0.5; a[2] = dRandReal()-0.5; for (j=0; j<3; j++) b[j] = a[0]*p[j] + a[1]*q[j] + (a[2]+d)*n[j]; g[0] = dRandReal()-0.5; g[1] = dRandReal()-0.5; g[2] = dRandReal()-0.5; for (j=0; j<3; j++) h[j] = g[0]*p[j] + g[1]*q[j] + g[2]*n[j]; dNormalize3 (h); dGeomRaySet (ray,b[0],b[1],b[2],h[0],h[1],h[2]); dGeomRaySetLength (ray,10); if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom))) { // test that contact is on plane surface if (dFabs (dCalcVectorDot3(contact.pos,n) - d) > tol) FAILED(); // also check normal signs if (dCalcVectorDot3 (h,contact.normal) > 0) FAILED(); // also check contact point depth if (dFabs (dGeomPlanePointDepth (plane,contact.pos[0],contact.pos[1],contact.pos[2])) > tol) FAILED(); draw_all_objects (space); } // ********** test ray that just misses for (j=0; j<3; j++) b[j] = (1+d)*n[j]; for (j=0; j<3; j++) h[j] = -n[j]; dGeomRaySet (ray,b[0],b[1],b[2],h[0],h[1],h[2]); dGeomRaySetLength (ray,0.99); if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 0) FAILED(); // ********** test ray that just hits dGeomRaySetLength (ray,1.01); if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); // ********** test polarity with typical ground plane dGeomPlaneSetParams (plane,0,0,1,0); for (j=0; j<3; j++) a[j] = 0.1; for (j=0; j<3; j++) b[j] = 0; a[2] = 1; b[2] = -1; dGeomRaySet (ray,a[0],a[1],a[2],b[0],b[1],b[2]); dGeomRaySetLength (ray,2); if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); if (dFabs (contact.depth - 1) > tol) FAILED(); a[2] = -1; b[2] = 1; dGeomRaySet (ray,a[0],a[1],a[2],b[0],b[1],b[2]); if (dCollide (ray,plane,1,&contact,sizeof(dContactGeom)) != 1) FAILED(); if (dFabs (contact.depth - 1) > tol) FAILED(); PASSED(); } //**************************************************************************** // a really inefficient, but hopefully correct implementation of // dBoxTouchesBox(), that does 144 edge-face tests. // return 1 if edge v1 -> v2 hits the rectangle described by p1,p2,p3 static int edgeIntersectsRect (dVector3 v1, dVector3 v2, dVector3 p1, dVector3 p2, dVector3 p3) { int k; dVector3 u1,u2,n,tmp; for (k=0; k<3; k++) u1[k] = p3[k]-p1[k]; for (k=0; k<3; k++) u2[k] = p2[k]-p1[k]; dReal d1 = dSqrt(dCalcVectorDot3(u1,u1)); dReal d2 = dSqrt(dCalcVectorDot3(u2,u2)); dNormalize3 (u1); dNormalize3 (u2); if (dFabs(dCalcVectorDot3(u1,u2)) > 1e-6) dDebug (0,"bad u1/u2"); dCalcVectorCross3(n,u1,u2); for (k=0; k<3; k++) tmp[k] = v2[k]-v1[k]; dReal d = -dCalcVectorDot3(n,p1); if (dFabs(dCalcVectorDot3(n,p1)+d) > 1e-8) dDebug (0,"bad n wrt p1"); if (dFabs(dCalcVectorDot3(n,p2)+d) > 1e-8) dDebug (0,"bad n wrt p2"); if (dFabs(dCalcVectorDot3(n,p3)+d) > 1e-8) dDebug (0,"bad n wrt p3"); dReal alpha = -(d+dCalcVectorDot3(n,v1))/dCalcVectorDot3(n,tmp); for (k=0; k<3; k++) tmp[k] = v1[k]+alpha*(v2[k]-v1[k]); if (dFabs(dCalcVectorDot3(n,tmp)+d) > 1e-6) dDebug (0,"bad tmp"); if (alpha < 0) return 0; if (alpha > 1) return 0; for (k=0; k<3; k++) tmp[k] -= p1[k]; dReal a1 = dCalcVectorDot3(u1,tmp); dReal a2 = dCalcVectorDot3(u2,tmp); if (a1<0 || a2<0 || a1>d1 || a2>d2) return 0; return 1; } // return 1 if box 1 is completely inside box 2 static int box1inside2 (const dVector3 p1, const dMatrix3 R1, const dVector3 side1, const dVector3 p2, const dMatrix3 R2, const dVector3 side2) { for (int i=-1; i<=1; i+=2) { for (int j=-1; j<=1; j+=2) { for (int k=-1; k<=1; k+=2) { dVector3 v,vv; v[0] = i*0.5*side1[0]; v[1] = j*0.5*side1[1]; v[2] = k*0.5*side1[2]; dMultiply0_331 (vv,R1,v); vv[0] += p1[0] - p2[0]; vv[1] += p1[1] - p2[1]; vv[2] += p1[2] - p2[2]; for (int axis=0; axis < 3; axis++) { dReal z = dCalcVectorDot3_14(vv,R2+axis); if (z < (-side2[axis]*0.5) || z > (side2[axis]*0.5)) return 0; } } } } return 1; } // test if any edge from box 1 hits a face from box 2 static int testBoxesTouch2 (const dVector3 p1, const dMatrix3 R1, const dVector3 side1, const dVector3 p2, const dMatrix3 R2, const dVector3 side2) { int j,k,j1,j2; // for 6 faces from box 2 for (int fd=0; fd<3; fd++) { // direction for face for (int fo=0; fo<2; fo++) { // offset of face // get four points on the face. first get 2 indexes that are not fd int k1=0,k2=0; if (fd==0) { k1 = 1; k2 = 2; } if (fd==1) { k1 = 0; k2 = 2; } if (fd==2) { k1 = 0; k2 = 1; } dVector3 fp[4],tmp; k=0; for (j1=-1; j1<=1; j1+=2) { for (j2=-1; j2<=1; j2+=2) { fp[k][k1] = j1; fp[k][k2] = j2; fp[k][fd] = fo*2-1; k++; } } for (j=0; j<4; j++) { for (k=0; k<3; k++) fp[j][k] *= 0.5*side2[k]; dMultiply0_331 (tmp,R2,fp[j]); for (k=0; k<3; k++) fp[j][k] = tmp[k] + p2[k]; } // for 8 vertices dReal v1[3]; for (v1[0]=-1; v1[0] <= 1; v1[0] += 2) { for (v1[1]=-1; v1[1] <= 1; v1[1] += 2) { for (v1[2]=-1; v1[2] <= 1; v1[2] += 2) { // for all possible +ve leading edges from those vertices for (int ei=0; ei < 3; ei ++) { if (v1[ei] < 0) { // get vertex1 -> vertex2 = an edge from box 1 dVector3 vv1,vv2; for (k=0; k<3; k++) vv1[k] = v1[k] * 0.5*side1[k]; for (k=0; k<3; k++) vv2[k] = (v1[k] + (k==ei)*2)*0.5*side1[k]; dVector3 vertex1,vertex2; dMultiply0_331 (vertex1,R1,vv1); dMultiply0_331 (vertex2,R1,vv2); for (k=0; k<3; k++) vertex1[k] += p1[k]; for (k=0; k<3; k++) vertex2[k] += p1[k]; // see if vertex1 -> vertex2 interesects face if (edgeIntersectsRect (vertex1,vertex2,fp[0],fp[1],fp[2])) return 1; } } } } } } } if (box1inside2 (p1,R1,side1,p2,R2,side2)) return 1; if (box1inside2 (p2,R2,side2,p1,R1,side1)) return 1; return 0; } //**************************************************************************** // dBoxTouchesBox() test int test_dBoxTouchesBox() { int k,bt1,bt2; dVector3 p1,p2,side1,side2; dMatrix3 R1,R2; dSimpleSpace space(0); dGeomID box1 = dCreateBox (0,1,1,1); dSpaceAdd (space,box1); dGeomID box2 = dCreateBox (0,1,1,1); dSpaceAdd (space,box2); dMakeRandomVector (p1,3,0.5); dMakeRandomVector (p2,3,0.5); for (k=0; k<3; k++) side1[k] = dRandReal() + 0.01; for (k=0; k<3; k++) side2[k] = dRandReal() + 0.01; dRFromAxisAndAngle (R1,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); dRFromAxisAndAngle (R2,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); dGeomBoxSetLengths (box1,side1[0],side1[1],side1[2]); dGeomBoxSetLengths (box2,side2[0],side2[1],side2[2]); dGeomSetPosition (box1,p1[0],p1[1],p1[2]); dGeomSetRotation (box1,R1); dGeomSetPosition (box2,p2[0],p2[1],p2[2]); dGeomSetRotation (box2,R2); draw_all_objects (space); int t1 = testBoxesTouch2 (p1,R1,side1,p2,R2,side2); int t2 = testBoxesTouch2 (p2,R2,side2,p1,R1,side1); bt1 = t1 || t2; bt2 = dBoxTouchesBox (p1,R1,side1,p2,R2,side2); if (bt1 != bt2) FAILED(); /* // some more debugging info if necessary if (bt1 && bt2) printf ("agree - boxes touch\n"); if (!bt1 && !bt2) printf ("agree - boxes don't touch\n"); if (bt1 && !bt2) printf ("disagree - boxes touch but dBoxTouchesBox " "says no\n"); if (!bt1 && bt2) printf ("disagree - boxes don't touch but dBoxTouchesBox " "says yes\n"); */ PASSED(); } //**************************************************************************** // test box-box collision int test_dBoxBox() { int k,bt; dVector3 p1,p2,side1,side2,normal,normal2; dMatrix3 R1,R2; dReal depth,depth2; int code; dContactGeom contact[48]; dSimpleSpace space(0); dGeomID box1 = dCreateBox (0,1,1,1); dSpaceAdd (space,box1); dGeomID box2 = dCreateBox (0,1,1,1); dSpaceAdd (space,box2); dMakeRandomVector (p1,3,0.5); dMakeRandomVector (p2,3,0.5); for (k=0; k<3; k++) side1[k] = dRandReal() + 0.01; for (k=0; k<3; k++) side2[k] = dRandReal() + 0.01; dRFromAxisAndAngle (R1,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); dRFromAxisAndAngle (R2,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); // dRSetIdentity (R1); // we can also try this // dRSetIdentity (R2); dGeomBoxSetLengths (box1,side1[0],side1[1],side1[2]); dGeomBoxSetLengths (box2,side2[0],side2[1],side2[2]); dGeomSetPosition (box1,p1[0],p1[1],p1[2]); dGeomSetRotation (box1,R1); dGeomSetPosition (box2,p2[0],p2[1],p2[2]); dGeomSetRotation (box2,R2); code = 0; depth = 0; bt = dBoxBox (p1,R1,side1,p2,R2,side2,normal,&depth,&code,8,contact, sizeof(dContactGeom)); if (bt==1) { p2[0] += normal[0] * 0.96 * depth; p2[1] += normal[1] * 0.96 * depth; p2[2] += normal[2] * 0.96 * depth; bt = dBoxBox (p1,R1,side1,p2,R2,side2,normal2,&depth2,&code,8,contact, sizeof(dContactGeom)); /* dGeomSetPosition (box2,p2[0],p2[1],p2[2]); draw_all_objects (space); */ if (bt != 1) { FAILED(); dGeomSetPosition (box2,p2[0],p2[1],p2[2]); draw_all_objects (space); } p2[0] += normal[0] * 0.08 * depth; p2[1] += normal[1] * 0.08 * depth; p2[2] += normal[2] * 0.08 * depth; bt = dBoxBox (p1,R1,side1,p2,R2,side2,normal2,&depth2,&code,8,contact, sizeof(dContactGeom)); if (bt != 0) FAILED(); // dGeomSetPosition (box2,p2[0],p2[1],p2[2]); // draw_all_objects (space); } // printf ("code=%2d depth=%.4f ",code,depth); PASSED(); } //**************************************************************************** // graphics int space_pressed = 0; // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {2.4807,-1.8023,2.7600}; static float hpr[3] = {141.5000,-18.5000,0.0000}; dsSetViewpoint (xyz,hpr); } // called when a key pressed static void command (int cmd) { if (cmd == ' ') space_pressed = 1; } // simulation loop static void simLoop (int) { do { draw_all_objects_called = 0; unsigned long seed = dRandGetSeed(); testslot[graphical_test].test_fn(); if (draw_all_objects_called) { if (space_pressed) space_pressed = 0; else dRandSetSeed (seed); } } while (!draw_all_objects_called); } //**************************************************************************** // do all the tests void do_tests (int argc, char **argv) { int i,j; // process command line arguments if (argc >= 2) { graphical_test = atoi (argv[1]); } if (graphical_test) { // do one test gaphically and interactively if (graphical_test < 1 || graphical_test >= MAX_TESTS || !testslot[graphical_test].name) { dError (0,"invalid test number"); } printf ("performing test: %s\n",testslot[graphical_test].name); // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; dsSetSphereQuality (3); dsSetCapsuleQuality (8); dsSimulationLoop (argc,argv,1280,900,&fn); } else { // do all tests noninteractively for (i=0; ifailcount = 0; int total_reps=0; for (int batch=0; batch<2; batch++) { int reps = (batch==0) ? TEST_REPS1 : TEST_REPS2; total_reps += reps; printf ("testing batch %d (%d reps)...\n",batch+1,reps); // run tests for (j=0; jnumber; if (ts[i]->test_fn() != 1) ts[i]->failcount++; } } // check for failures int total_fail_count=0; for (i=0; ifailcount; if (total_fail_count) break; } // print results for (i=0; inumber,ts[i]->name); if (ts[i]->failcount) { printf ("FAILED (%.2f%%) at line %d\n", double(ts[i]->failcount)/double(total_reps)*100.0, ts[i]->last_failed_line); } else { printf ("ok\n"); } } } } //**************************************************************************** int main (int argc, char **argv) { // setup all tests memset (testslot,0,sizeof(testslot)); dInitODE2(0); MAKE_TEST(1,test_sphere_point_depth); MAKE_TEST(2,test_box_point_depth); MAKE_TEST(3,test_ccylinder_point_depth); MAKE_TEST(4,test_plane_point_depth); MAKE_TEST(10,test_ray_and_sphere); MAKE_TEST(11,test_ray_and_box); MAKE_TEST(12,test_ray_and_ccylinder); MAKE_TEST(13,test_ray_and_plane); MAKE_TEST(14,test_ray_and_cylinder); MAKE_TEST(100,test_dBoxTouchesBox); MAKE_TEST(101,test_dBoxBox); do_tests (argc,argv); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_crash.cpp0000644000000000000000000004516112635011627015220 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ // This is a demo of the QuickStep and StepFast methods, // originally by David Whittaker. #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define LENGTH 3.5 // chassis length #define WIDTH 2.5 // chassis width #define HEIGHT 1.0 // chassis height #define RADIUS 0.5 // wheel radius #define STARTZ 1.0 // starting height of chassis #define CMASS 1 // chassis mass #define WMASS 1 // wheel mass #define COMOFFSET -5 // center of mass offset #define WALLMASS 1 // wall box mass #define BALLMASS 1 // ball mass #define FMAX 25 // car engine fmax #define ROWS 1 // rows of cars #define COLS 1 // columns of cars #define ITERS 20 // number of iterations #define WBOXSIZE 1.0 // size of wall boxes #define WALLWIDTH 12 // width of wall #define WALLHEIGHT 10 // height of wall #define DISABLE_THRESHOLD 0.008 // maximum velocity (squared) a body can have and be disabled #define DISABLE_STEPS 10 // number of steps a box has to have been disable-able before it will be disabled #define CANNON_X -10 // x position of cannon #define CANNON_Y 5 // y position of cannon #define CANNON_BALL_MASS 10 // mass of the cannon ball #define CANNON_BALL_RADIUS 0.5 //#define BOX #define CARS #define WALL //#define BALLS //#define BALLSTACK //#define ONEBALL //#define CENTIPEDE #define CANNON // dynamics and collision objects (chassis, 3 wheels, environment) static dWorldID world; static dSpaceID space; static dThreadingImplementationID threading; static dThreadingThreadPoolID pool; static dBodyID body[10000]; static int bodies; static dJointID joint[100000]; static int joints; static dJointGroupID contactgroup; static dGeomID ground; static dGeomID box[10000]; static int boxes; static dGeomID sphere[10000]; static int spheres; static dGeomID wall_boxes[10000]; static dBodyID wall_bodies[10000]; static dGeomID cannon_ball_geom; static dBodyID cannon_ball_body; static int wb_stepsdis[10000]; static int wb; static bool doFast; static dBodyID b; static dMass m; // things that the user controls static dReal turn = 0, speed = 0; // user commands static dReal cannon_angle=0,cannon_elevation=-1.2; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i,n; dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnected(b1, b2)) return; const int N = 4; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact)); if (n > 0) { for (i=0; i -20; x-=RADIUS*2) { body[bodies] = dBodyCreate (world); dBodySetPosition(body[bodies], x, y, STARTZ); dMassSetSphere(&m, 1, RADIUS); dMassAdjust(&m, WMASS); dBodySetMass(body[bodies], &m); sphere[spheres] = dCreateSphere (space, RADIUS); dGeomSetBody (sphere[spheres++], body[bodies]); joint[joints] = dJointCreateHinge2 (world,0); if (x == -17) dJointAttach (joint[joints],b,body[bodies]); else dJointAttach (joint[joints],body[bodies-2],body[bodies]); const dReal *a = dBodyGetPosition (body[bodies++]); dJointSetHinge2Anchor (joint[joints],a[0],a[1],a[2]); dJointSetHinge2Axis1 (joint[joints],0,0,1); dJointSetHinge2Axis2 (joint[joints],1,0,0); dJointSetHinge2Param (joint[joints],dParamSuspensionERP,1.0); dJointSetHinge2Param (joint[joints],dParamSuspensionCFM,1e-5); dJointSetHinge2Param (joint[joints],dParamLoStop,0); dJointSetHinge2Param (joint[joints],dParamHiStop,0); dJointSetHinge2Param (joint[joints],dParamVel2,-10.0); dJointSetHinge2Param (joint[joints++],dParamFMax2,FMAX); body[bodies] = dBodyCreate (world); dBodySetPosition(body[bodies], -30 - x, y, STARTZ); dMassSetSphere(&m, 1, RADIUS); dMassAdjust(&m, WMASS); dBodySetMass(body[bodies], &m); sphere[spheres] = dCreateSphere (space, RADIUS); dGeomSetBody (sphere[spheres++], body[bodies]); joint[joints] = dJointCreateHinge2 (world,0); if (x == -17) dJointAttach (joint[joints],b,body[bodies]); else dJointAttach (joint[joints],body[bodies-2],body[bodies]); const dReal *b = dBodyGetPosition (body[bodies++]); dJointSetHinge2Anchor (joint[joints],b[0],b[1],b[2]); dJointSetHinge2Axis1 (joint[joints],0,0,1); dJointSetHinge2Axis2 (joint[joints],1,0,0); dJointSetHinge2Param (joint[joints],dParamSuspensionERP,1.0); dJointSetHinge2Param (joint[joints],dParamSuspensionCFM,1e-5); dJointSetHinge2Param (joint[joints],dParamLoStop,0); dJointSetHinge2Param (joint[joints],dParamHiStop,0); dJointSetHinge2Param (joint[joints],dParamVel2,10.0); dJointSetHinge2Param (joint[joints++],dParamFMax2,FMAX); } if (lastb) { dJointID j = dJointCreateFixed(world,0); dJointAttach (j, b, lastb); dJointSetFixed(j); } lastb = b; } #endif #ifdef BOX body[bodies] = dBodyCreate (world); dBodySetPosition (body[bodies],0,0,HEIGHT/2); dMassSetBox (&m,1,LENGTH,WIDTH,HEIGHT); dMassAdjust (&m, 1); dBodySetMass (body[bodies],&m); box[boxes] = dCreateBox (space,LENGTH,WIDTH,HEIGHT); dGeomSetBody (box[boxes++],body[bodies++]); #endif #ifdef CANNON cannon_ball_body = dBodyCreate (world); cannon_ball_geom = dCreateSphere (space,CANNON_BALL_RADIUS); dMassSetSphereTotal (&m,CANNON_BALL_MASS,CANNON_BALL_RADIUS); dBodySetMass (cannon_ball_body,&m); dGeomSetBody (cannon_ball_geom,cannon_ball_body); dBodySetPosition (cannon_ball_body,CANNON_X,CANNON_Y,CANNON_BALL_RADIUS); #endif } // called when a key pressed static void command (int cmd) { switch (cmd) { case 'a': case 'A': speed += 0.3; break; case 'z': case 'Z': speed -= 0.3; break; case ',': turn += 0.1; if (turn > 0.3) turn = 0.3; break; case '.': turn -= 0.1; if (turn < -0.3) turn = -0.3; break; case ' ': speed = 0; turn = 0; break; case 'f': case 'F': doFast = !doFast; break; case 'r': case 'R': shutdownSimulation(); setupSimulation(); break; case '[': cannon_angle += 0.1; break; case ']': cannon_angle -= 0.1; break; case '1': cannon_elevation += 0.1; break; case '2': cannon_elevation -= 0.1; break; case 'x': case 'X': { dMatrix3 R2,R3,R4; dRFromAxisAndAngle (R2,0,0,1,cannon_angle); dRFromAxisAndAngle (R3,0,1,0,cannon_elevation); dMultiply0 (R4,R2,R3,3,3,3); dReal cpos[3] = {CANNON_X,CANNON_Y,1}; for (int i=0; i<3; i++) cpos[i] += 3*R4[i*4+2]; dBodySetPosition (cannon_ball_body,cpos[0],cpos[1],cpos[2]); dReal force = 10; dBodySetLinearVel (cannon_ball_body,force*R4[2],force*R4[6],force*R4[10]); dBodySetAngularVel (cannon_ball_body,0,0,0); break; } } } // simulation loop static void simLoop (int pause) { int i, j; dsSetTexture (DS_WOOD); if (!pause) { #ifdef BOX dBodyAddForce(body[bodies-1],lspeed,0,0); #endif for (j = 0; j < joints; j++) { dReal curturn = dJointGetHinge2Angle1 (joint[j]); //dMessage (0,"curturn %e, turn %e, vel %e", curturn, turn, (turn-curturn)*1.0); dJointSetHinge2Param(joint[j],dParamVel,(turn-curturn)*1.0); dJointSetHinge2Param(joint[j],dParamFMax,dInfinity); dJointSetHinge2Param(joint[j],dParamVel2,speed); dJointSetHinge2Param(joint[j],dParamFMax2,FMAX); dBodyEnable(dJointGetBody(joint[j],0)); dBodyEnable(dJointGetBody(joint[j],1)); } if (doFast) { dSpaceCollide (space,0,&nearCallback); dWorldQuickStep (world,0.05); dJointGroupEmpty (contactgroup); } else { dSpaceCollide (space,0,&nearCallback); dWorldStep (world,0.05); dJointGroupEmpty (contactgroup); } for (i = 0; i < wb; i++) { b = dGeomGetBody(wall_boxes[i]); if (dBodyIsEnabled(b)) { bool disable = true; const dReal *lvel = dBodyGetLinearVel(b); dReal lspeed = lvel[0]*lvel[0]+lvel[1]*lvel[1]+lvel[2]*lvel[2]; if (lspeed > DISABLE_THRESHOLD) disable = false; const dReal *avel = dBodyGetAngularVel(b); dReal aspeed = avel[0]*avel[0]+avel[1]*avel[1]+avel[2]*avel[2]; if (aspeed > DISABLE_THRESHOLD) disable = false; if (disable) wb_stepsdis[i]++; else wb_stepsdis[i] = 0; if (wb_stepsdis[i] > DISABLE_STEPS) { dBodyDisable(b); dsSetColor(0.5,0.5,1); } else dsSetColor(1,1,1); } else dsSetColor(0.4,0.4,0.4); dVector3 ss; dGeomBoxGetLengths (wall_boxes[i], ss); dsDrawBox(dGeomGetPosition(wall_boxes[i]), dGeomGetRotation(wall_boxes[i]), ss); } } else { for (i = 0; i < wb; i++) { b = dGeomGetBody(wall_boxes[i]); if (dBodyIsEnabled(b)) dsSetColor(1,1,1); else dsSetColor(0.4,0.4,0.4); dVector3 ss; dGeomBoxGetLengths (wall_boxes[i], ss); dsDrawBox(dGeomGetPosition(wall_boxes[i]), dGeomGetRotation(wall_boxes[i]), ss); } } dsSetColor (0,1,1); dReal sides[3] = {LENGTH,WIDTH,HEIGHT}; for (i = 0; i < boxes; i++) dsDrawBox (dGeomGetPosition(box[i]),dGeomGetRotation(box[i]),sides); dsSetColor (1,1,1); for (i=0; i< spheres; i++) dsDrawSphere (dGeomGetPosition(sphere[i]), dGeomGetRotation(sphere[i]),RADIUS); // draw the cannon dsSetColor (1,1,0); dMatrix3 R2,R3,R4; dRFromAxisAndAngle (R2,0,0,1,cannon_angle); dRFromAxisAndAngle (R3,0,1,0,cannon_elevation); dMultiply0 (R4,R2,R3,3,3,3); dReal cpos[3] = {CANNON_X,CANNON_Y,1}; dReal csides[3] = {2,2,2}; dsDrawBox (cpos,R2,csides); for (i=0; i<3; i++) cpos[i] += 1.5*R4[i*4+2]; dsDrawCylinder (cpos,R4,3,0.5); // draw the cannon ball dsDrawSphere (dBodyGetPosition(cannon_ball_body),dBodyGetRotation(cannon_ball_body), CANNON_BALL_RADIUS); } int main (int argc, char **argv) { doFast = true; // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; dInitODE2(0); bodies = 0; joints = 0; boxes = 0; spheres = 0; setupSimulation(); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); shutdownSimulation(); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_cyl.cpp0000644000000000000000000002113312635011627014700 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ // Test for non-capped cylinder, by Bram Stolk #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include "texturepath.h" #include "world_geom3.h" // this is our world mesh #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif #define BOX #define CYL // some constants #define RADIUS 0.22 // wheel radius #define WMASS 0.2 // wheel mass #define WHEELW 0.2 // wheel width #define BOXSZ 0.4 // box size //#define CYL_GEOM_OFFSET // rotate cylinder using geom offset // dynamics and collision objects (chassis, 3 wheels, environment) static dWorldID world; static dSpaceID space; #ifdef BOX static dBodyID boxbody; static dGeomID boxgeom; #endif #ifdef CYL static dBodyID cylbody; static dGeomID cylgeom; #endif static dJointGroupID contactgroup; static dGeomID world_mesh; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { assert(o1); assert(o2); if (dGeomIsSpace(o1) || dGeomIsSpace(o2)) { fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2); // colliding a space with something dSpaceCollide2(o1,o2,data,&nearCallback); // Note we do not want to test intersections within a space, // only between spaces. return; } // fprintf(stderr,"testing geoms %p %p\n", o1, o2); const int N = 32; dContact contact[N]; int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact)); if (n > 0) { for (int i=0; i #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // dynamics and collision objects (chassis, 3 wheels, environment) static dWorldID world; static dSpaceID space; static dBodyID cylbody; static dGeomID cylgeom; static dBodyID sphbody; static dGeomID sphgeom; static dJointGroupID contactgroup; static bool show_contacts = true; #define CYLRADIUS 0.6 #define CYLLENGTH 2.0 #define SPHERERADIUS 0.5 #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawLine dsDrawLineD #endif // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { assert(o1); assert(o2); if (dGeomIsSpace(o1) || dGeomIsSpace(o2)) { fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2); // colliding a space with something dSpaceCollide2(o1,o2,data,&nearCallback); // Note we do not want to test intersections within a space, // only between spaces. return; } const int N = 32; dContact contact[N]; int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact)); if (n > 0) { for (int i=0; i #include #include "texturepath.h" #ifdef dDOUBLE #define dsDrawSphere dsDrawSphereD #define dsDrawBox dsDrawBoxD #define dsDrawLine dsDrawLineD #endif dWorldID world; dSpaceID space; dBodyID body1; dBodyID body2; dJointID joint1, joint2; void start() { world = dWorldCreate(); dWorldSetGravity (world,0,0,-9.8); dWorldSetDamping(world, 1e-4, 1e-5); // dWorldSetERP(world, 1); space = dSimpleSpaceCreate (0); body1 = dBodyCreate(world); body2 = dBodyCreate(world); dBodySetPosition(body1, 0, 0, 3); dBodySetPosition(body2, 0, 0, 1); dGeomID g; dMass mass; g = dCreateBox(space, 0.2, 0.2, 1); dGeomSetBody(g, body1); dMassSetBox(&mass, 1, 0.2, 0.2, 1); dBodySetMass(body1, &mass); g = dCreateBox(space, 0.2, 0.2, 1); dGeomSetBody(g, body2); dMassSetBox(&mass, 1, 0.2, 0.2, 1); dBodySetMass(body2, &mass); joint1 = dJointCreateDBall(world, 0); dJointAttach(joint1, body1, 0); dJointSetDBallAnchor1(joint1, 0, 0, 3.5); dJointSetDBallAnchor2(joint1, 0, 0, 4.5); joint2 = dJointCreateDBall(world, 0); dJointAttach(joint2, body1, body2); dJointSetDBallAnchor1(joint2, 0, 0, 2.5); dJointSetDBallAnchor2(joint2, 0, 0, 1.5); // initial camera position static float xyz[3] = {3.8966, -2.0614, 4.0300}; static float hpr[3] = {153.5, -16.5, 0}; dsSetViewpoint (xyz,hpr); } void stop() { dSpaceDestroy(space); dWorldDestroy(world); } void drawGeom(dGeomID g) { int gclass = dGeomGetClass(g); const dReal *pos = dGeomGetPosition(g); const dReal *rot = dGeomGetRotation(g); switch (gclass) { case dSphereClass: dsSetColorAlpha(0, 0.75, 0.5, 1); dsSetTexture (DS_CHECKERED); dsDrawSphere(pos, rot, dGeomSphereGetRadius(g)); break; case dBoxClass: { dVector3 lengths; dsSetColorAlpha(1, 1, 0, 1); dsSetTexture (DS_WOOD); dGeomBoxGetLengths(g, lengths); dsDrawBox(pos, rot, lengths); break; } default: {} } } void simLoop(int pause) { if (!pause) { static dReal t = 0; const dReal step = 0.005; const unsigned nsteps = 4; for (unsigned i=0; i #include #include "texturepath.h" #ifdef dDOUBLE #define dsDrawSphere dsDrawSphereD #define dsDrawBox dsDrawBoxD #define dsDrawLine dsDrawLineD #endif dWorldID world; dSpaceID space; dBodyID body1; dBodyID body2; dJointID joint1, joint2; bool applyForce = false; void start() { world = dWorldCreate(); dWorldSetGravity (world,0,0,-9.8); dWorldSetDamping(world, 1e-4, 1e-5); // dWorldSetERP(world, 1); space = dSimpleSpaceCreate (0); body1 = dBodyCreate(world); body2 = dBodyCreate(world); dBodySetPosition(body1, 0, 0, 3); dBodySetPosition(body2, 0, 0, 1); dGeomID g; dMass mass; g = dCreateBox(space, 0.2, 0.2, 1); dGeomSetBody(g, body1); dMassSetBox(&mass, 1, 0.2, 0.2, 1); dBodySetMass(body1, &mass); g = dCreateBox(space, 0.2, 0.2, 1); dGeomSetBody(g, body2); dMassSetBox(&mass, 1, 0.2, 0.2, 1); dBodySetMass(body2, &mass); #if 1 joint1 = dJointCreateDHinge(world, 0); dJointAttach(joint1, body1, 0); dJointSetDHingeAxis(joint1, 0, 1, 0); dJointSetDHingeAnchor1(joint1, 0, 0, 3.5); dJointSetDHingeAnchor2(joint1, 0, 0, 4.5); #endif #if 1 joint2 = dJointCreateDHinge(world, 0); dJointAttach(joint2, body1, body2); dJointSetDHingeAxis(joint2, 1, 0, 0); dJointSetDHingeAnchor1(joint2, 0, 0, 2.5); dJointSetDHingeAnchor2(joint2, 0, 0, 1.5); #else joint2 = dJointCreateDBall(world, 0); dJointAttach(joint2, body1, body2); dJointSetDBallAnchor1(joint2, 0, 0, 2.5); dJointSetDBallAnchor2(joint2, 0, 0, 1.5); #endif //dBodyAddForce(body1, 20, 0, 0); // initial camera position static float xyz[3] = {3.8966, -2.0614, 4.0300}; static float hpr[3] = {153.5, -16.5, 0}; dsSetViewpoint (xyz,hpr); } void stop() { dSpaceDestroy(space); dWorldDestroy(world); } void drawGeom(dGeomID g) { int gclass = dGeomGetClass(g); const dReal *pos = dGeomGetPosition(g); const dReal *rot = dGeomGetRotation(g); switch (gclass) { case dBoxClass: { dVector3 lengths; if (applyForce) dsSetColor(1, .5, 0); else dsSetColor(1, 1, 0); dsSetTexture (DS_WOOD); dGeomBoxGetLengths(g, lengths); dsDrawBox(pos, rot, lengths); break; } default: {} } } void simLoop(int pause) { if (!pause) { static dReal t = 0; const dReal step = 0.005; const unsigned nsteps = 2; for (unsigned i=0; i 2.; if (applyForce) { dReal f = 0.3 * sin(t*1.2); dBodyAddForceAtRelPos(body1, f, 0, 0, 0, 0, -0.5); // at the lower end dReal g = 0.3 * sin(t*0.7); dBodyAddForceAtRelPos(body2, 0, g, 0, 0, 0, -0.5); // at the lower end } t += step; if (t > 20.) t = 0.; dWorldQuickStep(world, step); } } // now we draw everything unsigned ngeoms = dSpaceGetNumGeoms(space); for (unsigned i=0; i #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawCylinder dsDrawCylinderD #endif // dynamics and collision objects (chassis, 3 wheels, environment) static dWorldID world; static dSpaceID space; static const int STACKCNT=10; // nr of weights on bridge static const int SEGMCNT=16; // nr of segments in bridge static const float SEGMDIM[3] = { 0.9, 4, 0.1 }; static dGeomID groundgeom; static dBodyID segbodies[SEGMCNT]; static dGeomID seggeoms[SEGMCNT]; static dBodyID stackbodies[STACKCNT]; static dGeomID stackgeoms[STACKCNT]; static dJointID hinges[SEGMCNT-1]; static dJointID sliders[2]; static dJointFeedback jfeedbacks[SEGMCNT-1]; static dReal colours[SEGMCNT]; static int stress[SEGMCNT-1]; static dJointGroupID contactgroup; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *data, dGeomID o1, dGeomID o2) { assert(o1); assert(o2); if (dGeomIsSpace(o1) || dGeomIsSpace(o2)) { fprintf(stderr,"testing space %p %p\n", (void*)o1, (void*)o2); // colliding a space with something dSpaceCollide2(o1,o2,data,&nearCallback); // Note we do not want to test intersections within a space, // only between spaces. return; } const int N = 32; dContact contact[N]; int n = dCollide (o1,o2,N,&(contact[0].geom),sizeof(dContact)); if (n > 0) { for (int i=0; i forcelimit || l1 > forcelimit) stress[i]++; else stress[i]=0; if (stress[i]>4) { // Low-pass filter the noisy feedback data. // Only after 4 consecutive timesteps with excessive load, snap. fprintf(stderr,"SNAP! (that was the sound of joint %d breaking)\n", i); dJointAttach (hinges[i], 0, 0); } } } } // simulation loop static void simLoop (int pause) { int i; double simstep = 0.002; // 2ms simulation steps double dt = dsElapsedTime(); int nrofsteps = (int) ceilf(dt/simstep); for (i=0; i1.0) v=1.0; if (v<0.5) { r=2*v; g=1.0; } else { r=1.0; g=2*(1.0-v); } dsSetColor (r,g,b); drawGeom(seggeoms[i]); } dsSetColor (1,1,1); for (i=0; i MU * body_mass * GRAVITY (j+1)*FORCE > MU * (i+1)*MASS * GRAVITY (j+1) > (i+1) * (MU*MASS*GRAVITY/FORCE) (j+1) > (i+1) * k this should be independent of the number of contact points, as N contact points will each have 1/N'th the normal force but the pushing force will have to overcome N contacts. the constants are chosen so that k=1. thus you should see a triangle made of half the bodies in the array start to slide. */ #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define LENGTH 0.2 // box length & width #define HEIGHT 0.05 // box height #define MASS 0.2 // mass of box[i][j] = (i+1) * MASS #define FORCE 0.05 // force applied to box[i][j] = (j+1) * FORCE #define MU 0.5 // the global mu to use #define GRAVITY 0.5 // the global gravity to use #define N1 10 // number of different forces to try #define N2 10 // number of different masses to try // dynamics and collision objects static dWorldID world; static dSpaceID space; static dBodyID body[N1][N2]; static dJointGroupID contactgroup; static dGeomID ground; static dGeomID box[N1][N2]; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; // only collide things with the ground int g1 = (o1 == ground); int g2 = (o2 == ground); if (!(g1 ^ g2)) return; dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); dContact contact[3]; // up to 3 contacts per box for (i=0; i<3; i++) { contact[i].surface.mode = dContactSoftCFM | dContactApprox1; contact[i].surface.mu = MU; contact[i].surface.soft_cfm = 0.01; } if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) { for (i=0; i #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // dynamics and collision objects static dWorldID world = 0; static const dReal dt = 1/REAL(60.0); // 60 fps // Water density if units are meters and kg static const dReal density = 1000; // A long skinny thing static dVector3 sides = {2,.5,.25}; // Initial angular velocity static dVector3 omega = {5,1,2}; static dVector3 torque = {0,10,0}; static dBodyID noGyroBody; static dBodyID expGyroBody; static dBodyID impGyroBody; // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {0,-4.0f,3.0f}; static float hpr[3] = {90.0000,-15.0000,0.0000}; dsSetViewpoint (xyz,hpr); printf ("Press:\n" "\t'a' to apply a torque\n" "\t'r' to reset simulation.\n"); } /** Delete the bodies, etc. */ static void clear() { if (world) dWorldDestroy (world); world = 0; } /** Cleanup if necessary and rebuild the world. */ static void reset() { clear(); // create world world = dWorldCreate(); // Calculate mass for a box; dMass boxMass; dMassSetBox(&boxMass,density,sides[0],sides[1],sides[2]); noGyroBody = dBodyCreate(world);// Conservation of ang-velocity expGyroBody = dBodyCreate(world);// Explicit conservation of ang-momentum impGyroBody = dBodyCreate(world);// Implicit conservation of ang-momentum dBodySetMass( noGyroBody , &boxMass ); dBodySetMass( expGyroBody, &boxMass ); dBodySetMass( impGyroBody, &boxMass ); // Try to avoid collisions. dReal sep = dCalcVectorLength3(sides); dBodySetPosition( noGyroBody , -sep, 0, sep); dBodySetPosition( expGyroBody, 0, 0, sep); dBodySetPosition( impGyroBody, sep, 0, sep); // Set the initial angular velocity dBodySetAngularVel( noGyroBody , omega[0], omega[1], omega[2]); dBodySetAngularVel( expGyroBody, omega[0], omega[1], omega[2]); dBodySetAngularVel( impGyroBody, omega[0], omega[1], omega[2]); dBodySetGyroscopicMode( noGyroBody, 0); // We compute this ourselves using the math // that was in the old stepper. dBodySetGyroscopicMode(expGyroBody, 0); // Keep things from crashing by limiting // the angular speed of the explicit body. // Note that this isn't necessary for // the other two bodies. dBodySetMaxAngularSpeed( expGyroBody, 40 ); } static void command (int cmd) { switch (cmd) { case 'a': case 'A': dBodyAddTorque( noGyroBody, torque[0], torque[1], torque[2]); dBodyAddTorque(expGyroBody, torque[0], torque[1], torque[2]); dBodyAddTorque(impGyroBody, torque[0], torque[1], torque[2]); break; case 'r': case 'R': reset(); break; } } /** This is the explicit computation of gyroscopic forces. */ static void expStep(dBodyID body) { // Explicit computation dMatrix3 I,tmp; dMass m; dBodyGetMass(body,&m); const dReal* R = dBodyGetRotation(body); // compute inertia tensor in global frame dMultiply2_333 (tmp,m.I,R); dMultiply0_333 (I,R,tmp); // compute explicit rotational force // we treat 'tmp'like a vector, but that's okay. const dReal* w = dBodyGetAngularVel(body); dMultiply0_331 (tmp,I,w); dVector3 tau; dCalcVectorCross3(tau,tmp,w); dBodyAddTorque(body,tau[0],tau[1],tau[2]); } // simulation loop static void simLoop (int pause) { if (!pause) { expStep(expGyroBody); dWorldStep (world,dt); } dsSetTexture (DS_WOOD); dsSetColor(1,0,0); dsDrawBox(dBodyGetPosition(noGyroBody ),dBodyGetRotation(noGyroBody ),sides); dsSetColor(1,1,0); dsDrawBox(dBodyGetPosition(expGyroBody),dBodyGetRotation(expGyroBody),sides); dsSetColor(0,1,0); dsDrawBox(dBodyGetPosition(impGyroBody),dBodyGetRotation(impGyroBody),sides); } int main (int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; dInitODE2(0); reset(); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); clear(); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_gyroscopic.cpp0000644000000000000000000001534412635011627016301 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawConvex dsDrawConvexD #endif bool write_world = false; bool show_contacts = false; dWorld * world; dBody *top1, *top2; dSpace *space; dJointGroup contactgroup; const dReal pinradius = 0.05f; const dReal pinlength = 1.5f; const dReal topradius = 1.0f; const dReal toplength = 0.25f; const dReal topmass = 1.0f; #define MAX_CONTACTS 4 static void nearCallback (void *, dGeomID o1, dGeomID o2) { // for drawing the contact points dMatrix3 RI; dRSetIdentity (RI); const dReal ss[3] = {0.02,0.02,0.02}; int i; dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); dContact contact[MAX_CONTACTS]; int numc = dCollide (o1,o2,MAX_CONTACTS,&contact[0].geom, sizeof(dContact)); for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void reset(); static void tilt(); static void command (int cmd) { cmd = locase (cmd); if (cmd == ' ') { reset(); } else if (cmd == 'a') { tilt(); } else if (cmd == 't') { show_contacts = !show_contacts; } else if (cmd == '1') { write_world = true; } } // simulation loop static void simLoop (int pause) { dsSetColor (0,0,2); space->collide(0,&nearCallback); if (!pause) //world->quickStep(0.02); world->step(0.02); if (write_world) { FILE *f = fopen ("state.dif","wt"); if (f) { dWorldExportDIF (*world,f,"X"); fclose (f); } write_world = false; } // remove all contact joints dJointGroupEmpty (contactgroup); dsSetTexture (DS_WOOD); dsSetColor (1,0.5f,0); dsDrawCylinder(top1->getPosition(), top1->getRotation(), toplength, topradius); dsDrawCapsule(top1->getPosition(), top1->getRotation(), pinlength, pinradius); dsSetColor (0.5f,1,0); dsDrawCylinder(top2->getPosition(), top2->getRotation(), toplength, topradius); dsDrawCapsule(top2->getPosition(), top2->getRotation(), pinlength, pinradius); } static void reset() { dMatrix3 R; dRSetIdentity(R); top1->setRotation(R); top2->setRotation(R); top1->setPosition(0.8f, -2, 2); top2->setPosition(0.8f, 2, 2); top1->setAngularVel(1,0,7); top2->setAngularVel(1,0,7); top1->setLinearVel(0,0.2f,0); top2->setLinearVel(0,0.2f,0); } static void tilt() { top1->addTorque(0, 10, 0); top2->addTorque(0, 10, 0); } int main (int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE(); world = new dWorld(); world->setGravity(0,0,-0.5f); world->setCFM(1e-5f); world->setLinearDamping(0.00001f); world->setAngularDamping(0.0001f); space = new dSimpleSpace(0); dPlane *floor = new dPlane(*space, 0,0,1,0); top1 = new dBody(*world); top2 = new dBody(*world); dMass m; m.setCylinderTotal(1, 3, topradius, toplength); top1->setMass(m); top2->setMass(m); dGeom *g1, *g2, *pin1, *pin2; g1 = new dCylinder(*space, topradius, toplength); g1->setBody(*top1); g2 = new dCylinder(*space, topradius, toplength); g2->setBody(*top2); pin1 = new dCapsule(*space, pinradius, pinlength); pin1->setBody(*top1); pin2 = new dCapsule(*space, pinradius, pinlength); pin2->setBody(*top2); top2->setGyroscopicMode(false); reset(); // run simulation dsSimulationLoop (argc,argv,512,384,&fn); delete g1; delete g2; delete pin1; delete pin2; delete floor; contactgroup.empty(); delete top1; delete top2; delete space; delete world; dCloseODE(); } ode-0.14/ode/demo/demo_heightfield.cpp0000644000000000000000000005230112635011627016366 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include "texturepath.h" #include "bunny_geom.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif #define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians int g_allow_trimesh; // Our heightfield geom dGeomID gheight; // Heightfield dimensions #define HFIELD_WSTEP 15 // Vertex count along edge >= 2 #define HFIELD_DSTEP 31 #define HFIELD_WIDTH REAL( 4.0 ) #define HFIELD_DEPTH REAL( 8.0 ) #define HFIELD_WSAMP ( HFIELD_WIDTH / ( HFIELD_WSTEP-1 ) ) #define HFIELD_DSAMP ( HFIELD_DEPTH / ( HFIELD_DSTEP-1 ) ) //<---- Convex Object dReal planes[]= // planes for a cube { 1.0f ,0.0f ,0.0f ,0.25f, 0.0f ,1.0f ,0.0f ,0.25f, 0.0f ,0.0f ,1.0f ,0.25f, 0.0f ,0.0f ,-1.0f,0.25f, 0.0f ,-1.0f,0.0f ,0.25f, -1.0f,0.0f ,0.0f ,0.25f /* 1.0f ,0.0f ,0.0f ,2.0f, 0.0f ,1.0f ,0.0f ,1.0f, 0.0f ,0.0f ,1.0f ,1.0f, 0.0f ,0.0f ,-1.0f,1.0f, 0.0f ,-1.0f,0.0f ,1.0f, -1.0f,0.0f ,0.0f ,0.0f */ }; const unsigned int planecount=6; dReal points[]= // points for a cube { 0.25f,0.25f,0.25f, // point 0 -0.25f,0.25f,0.25f, // point 1 0.25f,-0.25f,0.25f, // point 2 -0.25f,-0.25f,0.25f,// point 3 0.25f,0.25f,-0.25f, // point 4 -0.25f,0.25f,-0.25f,// point 5 0.25f,-0.25f,-0.25f,// point 6 -0.25f,-0.25f,-0.25f,// point 7 }; const unsigned int pointcount=8; unsigned int polygons[] = //Polygons for a cube (6 squares) { 4,0,2,6,4, // positive X 4,1,0,4,5, // positive Y 4,0,1,3,2, // positive Z 4,3,1,5,7, // negative X 4,2,3,7,6, // negative Y 4,5,4,6,7, // negative Z }; //----> Convex Object // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawConvex dsDrawConvexD #define dsDrawTriangle dsDrawTriangleD #endif // some constants #define NUM 100 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 64 // maximum number of contact points per body // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body // Trimesh only - double buffered matrices for 'last transform' setup dReal matrix_dblbuff[ 16 * 2 ]; int last_matrix_index; }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? static int write_world = 0; //============================ dGeomID TriMesh1; dGeomID TriMesh2; //static dTriMeshDataID TriData1, TriData2; // reusable static trimesh data //============================ dReal heightfield_callback( void*, int x, int z ) { dReal fx = ( ((dReal)x) - ( HFIELD_WSTEP-1 )/2 ) / (dReal)( HFIELD_WSTEP-1 ); dReal fz = ( ((dReal)z) - ( HFIELD_DSTEP-1 )/2 ) / (dReal)( HFIELD_DSTEP-1 ); // Create an interesting 'hump' shape dReal h = REAL( 1.0 ) + ( REAL( -16.0 ) * ( fx*fx*fx + fz*fz*fz ) ); return h; } // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact)) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command(int cmd) { size_t i; int j,k; dReal sides[3]; dMass m; bool setBody = false; cmd = locase (cmd); // // Geom Creation // if ( cmd == 'b' || cmd == 's' || cmd == 'c' || ( cmd == 'm' && g_allow_trimesh ) || cmd == 'x' || cmd == 'y' || cmd == 'v' ) { if ( num < NUM ) { i = num; num++; } else { i = nextobj++; nextobj %= num; // destroy the body and geoms for slot i dBodyDestroy(obj[i].body); obj[i].body = 0; for (k=0; k < GPB; k++) if (obj[i].geom[k]) { dGeomDestroy(obj[i].geom[k]); obj[i].geom[k] = 0; } } obj[i].body = dBodyCreate(world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition(obj[i].body, (dRandReal()-0.5)*HFIELD_WIDTH*0.75, (dRandReal()-0.5)*HFIELD_DEPTH*0.75, dRandReal() + 2 ); dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { dReal maxheight = 0; for (k=0; k maxheight) maxheight = pos[2]; } dBodySetPosition(obj[i].body, 0,maxheight+1,0); dRFromAxisAndAngle(R,0,0,1,dRandReal()*10.0-5.0); } dBodySetRotation(obj[i].body,R); if (cmd == 'b') { dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCapsule(space,sides[0],sides[1]); } else if (cmd == 'v') { dMassSetBox (&m,DENSITY,0.25,0.25,0.25); obj[i].geom[0] = dCreateConvex(space, planes, planecount, points, pointcount, polygons); } else if (cmd == 'y') { dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere(&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere(space,sides[0]); } else if (cmd == 'm' && g_allow_trimesh) { dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate(); dGeomTriMeshDataBuildSingle(new_tmdata, &Vertices[0], 3 * sizeof(float), VertexCount, &Indices[0], IndexCount, 3 * sizeof(dTriIndex)); obj[i].geom[0] = dCreateTriMesh(space, new_tmdata, 0, 0, 0); dMassSetTrimesh( &m, DENSITY, obj[i].geom[0] ); printf("mass at %f %f %f\n", m.c[0], m.c[1], m.c[2]); dGeomSetPosition(obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2]); dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]); } else if (cmd == 'x') { setBody = 1; // start accumulating masses for the composite geometries dMass m2; dMassSetZero (&m); dReal dpos[GPB][3]; // delta-positions for composite geometries dMatrix3 drot[GPB]; // set random delta positions for (j=0; j= num) selected = 0; if (selected < -1) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable(obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable(obj[selected].body); } else if (cmd == 'a') { show_aabb = !show_aabb; } else if (cmd == 't') { show_contacts = !show_contacts; } else if (cmd == 'r') { random_pos = !random_pos; } else if (cmd == '1') { write_world = 1; } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { if (!g) return; if (!pos) pos = dGeomGetPosition(g); if (!R) R = dGeomGetRotation(g); int type = dGeomGetClass(g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths(g,sides); dsDrawBox(pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere(pos,R,dGeomSphereGetRadius(g)); } else if (type == dCapsuleClass) { dReal radius,length; dGeomCapsuleGetParams(g,&radius,&length); dsDrawCapsule(pos,R,length,radius); } else if (type == dConvexClass) { //dVector3 sides={0.50,0.50,0.50}; dsDrawConvex(pos,R,planes, planecount, points, pointcount, polygons); } else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams(g,&radius,&length); dsDrawCylinder(pos,R,length,radius); } else if (type == dTriMeshClass) { dTriIndex* Indices = (dTriIndex*)::Indices; // assume all trimeshes are drawn as bunnies for (int ii = 0; ii < IndexCount / 3; ii++) { const dReal v[9] = { // explicit conversion from float to dReal Vertices[Indices[ii * 3 + 0] * 3 + 0], Vertices[Indices[ii * 3 + 0] * 3 + 1], Vertices[Indices[ii * 3 + 0] * 3 + 2], Vertices[Indices[ii * 3 + 1] * 3 + 0], Vertices[Indices[ii * 3 + 1] * 3 + 1], Vertices[Indices[ii * 3 + 1] * 3 + 2], Vertices[Indices[ii * 3 + 2] * 3 + 0], Vertices[Indices[ii * 3 + 2] * 3 + 1], Vertices[Indices[ii * 3 + 2] * 3 + 2] }; dsDrawTriangle(pos, R, &v[0], &v[3], &v[6], 1); } } else if (type == dHeightfieldClass) { // Set ox and oz to zero for DHEIGHTFIELD_CORNER_ORIGIN mode. int ox = (int) ( -HFIELD_WIDTH/2 ); int oz = (int) ( -HFIELD_DEPTH/2 ); // for ( int tx = -1; tx < 2; ++tx ) // for ( int tz = -1; tz < 2; ++tz ) dsSetColorAlpha (0.5,1,0.5,0.5); dsSetTexture( DS_WOOD ); for ( int i = 0; i < HFIELD_WSTEP - 1; ++i ) for ( int j = 0; j < HFIELD_DSTEP - 1; ++j ) { dReal a[3], b[3], c[3], d[3]; a[ 0 ] = ox + ( i ) * HFIELD_WSAMP; a[ 1 ] = heightfield_callback( NULL, i, j ); a[ 2 ] = oz + ( j ) * HFIELD_DSAMP; b[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP; b[ 1 ] = heightfield_callback( NULL, i + 1, j ); b[ 2 ] = oz + ( j ) * HFIELD_DSAMP; c[ 0 ] = ox + ( i ) * HFIELD_WSAMP; c[ 1 ] = heightfield_callback( NULL, i, j + 1 ); c[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP; d[ 0 ] = ox + ( i + 1 ) * HFIELD_WSAMP; d[ 1 ] = heightfield_callback( NULL, i + 1, j + 1 ); d[ 2 ] = oz + ( j + 1 ) * HFIELD_DSAMP; dsDrawTriangle( pos, R, a, c, b, 1 ); dsDrawTriangle( pos, R, b, c, d, 1 ); } } if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB(g,aabb); dVector3 bbpos; for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (int i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2]; dMatrix3 RI; dRSetIdentity(RI); dsSetColorAlpha(1,0,0,0.5); dsDrawBox(bbpos,RI,bbsides); } } // simulation loop static void simLoop (int pause) { int i,j; dSpaceCollide(space,0,&nearCallback); if (!pause) dWorldQuickStep(world,0.05); if (write_world) { FILE *f = fopen ("state.dif","wt"); if (f) { dWorldExportDIF(world,f,"X"); fclose (f); } write_world = 0; } // remove all contact joints dJointGroupEmpty(contactgroup); // // Draw Heightfield // drawGeom(gheight, 0, 0, 0); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (i=0; i #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #endif // some constants #define SIDE (0.5f) // side length of a box #define MASS (1.0) // mass of a box // dynamics and collision objects static dWorldID world; static dBodyID body[2]; static dJointID hinge; // state set by keyboard commands static int occasional_error = 0; // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {1.0382f,-1.0811f,1.4700f}; static float hpr[3] = {135.0000f,-19.5000f,0.0000f}; dsSetViewpoint (xyz,hpr); printf ("Press 'e' to start/stop occasional error.\n"); } // called when a key pressed static void command (int cmd) { if (cmd == 'e' || cmd == 'E') { occasional_error ^= 1; } } // simulation loop static void simLoop (int pause) { const dReal kd = -0.3; // angular damping constant if (!pause) { // add an oscillating torque to body 0, and also damp its rotational motion static dReal a=0; const dReal *w = dBodyGetAngularVel (body[0]); dBodyAddTorque (body[0],kd*w[0],kd*w[1]+0.1*cos(a),kd*w[2]+0.1*sin(a)); dWorldStep (world,0.05); a += 0.01; // occasionally re-orient one of the bodies to create a deliberate error. if (occasional_error) { static int count = 0; if ((count % 20)==0) { // randomly adjust orientation of body[0] const dReal *R1; dMatrix3 R2,R3; R1 = dBodyGetRotation (body[0]); dRFromAxisAndAngle (R2,dRandReal()-0.5,dRandReal()-0.5, dRandReal()-0.5,dRandReal()-0.5); dMultiply0 (R3,R1,R2,3,3,3); dBodySetRotation (body[0],R3); // randomly adjust position of body[0] const dReal *pos = dBodyGetPosition (body[0]); dBodySetPosition (body[0], pos[0]+0.2*(dRandReal()-0.5), pos[1]+0.2*(dRandReal()-0.5), pos[2]+0.2*(dRandReal()-0.5)); } count++; } } dReal sides1[3] = {SIDE,SIDE,SIDE}; dReal sides2[3] = {SIDE,SIDE,SIDE*0.8f}; dsSetTexture (DS_WOOD); dsSetColor (1,1,0); dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1); dsSetColor (0,1,1); dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2); } int main (int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE2(0); world = dWorldCreate(); dMass m; dMassSetBox (&m,1,SIDE,SIDE,SIDE); dMassAdjust (&m,MASS); dQuaternion q; dQFromAxisAndAngle (q,1,1,0,0.25*M_PI); body[0] = dBodyCreate (world); dBodySetMass (body[0],&m); dBodySetPosition (body[0],0.5*SIDE,0.5*SIDE,1); dBodySetQuaternion (body[0],q); body[1] = dBodyCreate (world); dBodySetMass (body[1],&m); dBodySetPosition (body[1],-0.5*SIDE,-0.5*SIDE,1); dBodySetQuaternion (body[1],q); hinge = dJointCreateHinge (world,0); dJointAttach (hinge,body[0],body[1]); dJointSetHingeAnchor (hinge,0,0,1); dJointSetHingeAxis (hinge,1,-1,1.41421356); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dWorldDestroy (world); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_jointPR.cpp0000644000000000000000000003351112635011627015501 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* This file try to demonstrate how the PR joint is working. The axisP is draw in red and the axisR is in green */ #include #include #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #endif // physics parameters #define BOX1_LENGTH 2 // Size along the X axis #define BOX1_WIDTH 1 // Size along the Y axis #define BOX1_HEIGHT 0.4 // Size along the Z axis (up) since gravity is (0,0,-10) #define BOX2_LENGTH 0.2 #define BOX2_WIDTH 0.1 #define BOX2_HEIGHT 0.4 #define Mass1 10 #define Mass2 0.1 #define PRISMATIC_ONLY 1 #define ROTOIDE_ONLY 2 int flag = 0; //camera view static float xyz[3] = {2.0f,-3.5f,2.0000f}; static float hpr[3] = {90.000f,-25.5000f,0.0000f}; //world,space,body & geom static dWorldID world; static dSpaceID space; static dSpaceID box1_space; static dBodyID box1_body[1]; static dBodyID box2_body[1]; static dJointID joint[1]; static dJointGroupID contactgroup; static dGeomID ground; static dGeomID box1[1]; static dGeomID box2[1]; //collision detection static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i,n; dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return; const int N = 10; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact)); if (n > 0) { for (i=0; i= 2 ) { for (int i=1; i < argc; ++i) { if ( 0 == strcmp("-h", argv[i]) || 0 == strcmp("--help", argv[i]) ) Help(argv); if (!flag && (0 == strcmp("-p", argv[i]) ||0 == strcmp("--prismatic-only", argv[i])) ) flag = PRISMATIC_ONLY; if (!flag && (0 == strcmp("-r", argv[i]) || 0 == strcmp("--rotoide-only", argv[i])) ) flag = ROTOIDE_ONLY; if (0 == strcmp("-t", argv[i]) || 0 == strcmp("--texture-path", argv[i])) { int j = i+1; if ( j+1 > argc || // Check if we have enough arguments argv[j] == '\0' || // We should have a path here argv[j][0] == '-' ) // We should have a path not a command line Help(argv); else fn.path_to_textures = argv[++i]; // Increase i since we use this argument } } } dInitODE2(0); // create world world = dWorldCreate(); space = dHashSpaceCreate (0); contactgroup = dJointGroupCreate (0); dWorldSetGravity (world,0,0,-10); ground = dCreatePlane (space,0,0,1,0); //create two boxes dMass m; box1_body[0] = dBodyCreate (world); dMassSetBox (&m,1,BOX1_LENGTH,BOX1_WIDTH,BOX1_HEIGHT); dMassAdjust (&m,Mass1); dBodySetMass (box1_body[0],&m); box1[0] = dCreateBox (0,BOX1_LENGTH,BOX1_WIDTH,BOX1_HEIGHT); dGeomSetBody (box1[0],box1_body[0]); box2_body[0] = dBodyCreate (world); dMassSetBox (&m,10,BOX2_LENGTH,BOX2_WIDTH,BOX2_HEIGHT); dMassAdjust (&m,Mass2); dBodySetMass (box2_body[0],&m); box2[0] = dCreateBox (0,BOX2_LENGTH,BOX2_WIDTH,BOX2_HEIGHT); dGeomSetBody (box2[0],box2_body[0]); //set the initial positions of body1 and body2 dMatrix3 R; dRSetIdentity(R); dBodySetPosition (box1_body[0],0,0,BOX1_HEIGHT/2.0); dBodySetRotation (box1_body[0], R); dBodySetPosition (box2_body[0], 2.1, 0.0, BOX2_HEIGHT/2.0); dBodySetRotation (box2_body[0], R); //set PR joint joint[0] = dJointCreatePR(world,0); dJointAttach (joint[0],box1_body[0],box2_body[0]); switch (flag) { case PRISMATIC_ONLY: dJointSetPRAnchor (joint[0], 2.1, 0.0, BOX2_HEIGHT/2.0); dJointSetPRParam (joint[0],dParamLoStop, -0.5); dJointSetPRParam (joint[0],dParamHiStop, 1.5); break; case ROTOIDE_ONLY: dJointSetPRAnchor (joint[0], 0.0, 0.0, BOX2_HEIGHT/2.0); dJointSetPRParam (joint[0],dParamLoStop, 0.0); dJointSetPRParam (joint[0],dParamHiStop, 0.0); break; default: dJointSetPRAnchor (joint[0], 1.1, 0.0, BOX2_HEIGHT/2.0); dJointSetPRParam (joint[0],dParamLoStop, -0.5); dJointSetPRParam (joint[0],dParamHiStop, 1.5); break; } dJointSetPRAxis1(joint[0],1,0,0); dJointSetPRAxis2(joint[0],0,0,1); // We position the 2 body // The position of the rotoide joint is on the second body so it can rotate on itself // and move along the X axis. // With this anchor // - A force in X will move only the body 2 inside the low and hi limit // of the prismatic // - A force in Y will make the 2 bodies to rotate around on the plane box1_space = dSimpleSpaceCreate (space); dSpaceSetCleanup (box1_space,0); dSpaceAdd(box1_space,box1[0]); // run simulation dsSimulationLoop (argc,argv,400,300,&fn); dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_jointPU.cpp0000644000000000000000000005021512635011627015504 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* This program demonstrates how the PU joint works. A PU joint is a combination of a Universal joint and a Slider joint. It is a universal joint with a slider between the anchor point and body 1. The upper yellow body is fixed to the world The lower yellow body is attached to the upper body by a PU joint The green object is one aprt of the slider. The purple object is the second part of the slider. The red object represent the axis1 of the universal part. The blue object represent the axis2 of the universal part. The gray object represent the anchor2 of the PU joint. */ #include #include #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif enum IDX_CYL_DIM { RADIUS, LENGTH, NUM_CYL_DIM }; const dVector3 boxDim = {1,1,1}; const dVector3 extDim = {0.2,0.2,1.2}; const dVector3 ancDim = {0.2,0.2,0.5}; const dReal axDim[NUM_CYL_DIM] = {0.1,1.0}; int type = dJointTypePU; const dReal VEL_INC = 0.01; // Velocity increment // physics parameters const dReal PI = 3.14159265358979323846264338327950288419716939937510; const dReal INT_EXT_RATIO = 0.8; #define X 0 #define Y 1 #define Z 2 enum INDEX { W = 0, D, EXT, INT, AXIS1, AXIS2, ANCHOR, GROUND, NUM_PARTS, ALL = NUM_PARTS, // INDEX for catBits JOINT, LAST_INDEX_CNT }; const int catBits[LAST_INDEX_CNT] = { 0x0001, ///< W Cylinder category 0x0002, ///< D Cylinder category 0x0004, ///< EXT sliderr category 0x0008, ///< INT slider category 0x0010, ///< AXIS1 universal category 0x0020, ///< AXIS2 universal category 0x0040, ///< ANCHOR category 0x0080, ///< Ground category ~0L, ///< All categories 0x0004 | 0x0008 | 0x0010 | 0x0020 ///< JOINT category }; #define Mass1 10 #define Mass2 8 //camera view static float xyz[3] = {6.0f,0.0f,6.0000f}; static float hpr[3] = {-180.000f,-25.5000f,0.0000f}; //world,space,body & geom static dWorldID world; static dSpaceID space; static dJointGroupID contactgroup; static dBodyID body[NUM_PARTS]; static dGeomID geom[NUM_PARTS]; static dJoint *joint; const dReal BOX_SIDES[3] = {1.0,1.0,1.0}; const dReal OBS_SIDES[3] = {0.4,0.4,0.4}; const dReal RECT_SIDES[3] = {0.3, 0.1, 0.2}; //collision detection static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i,n; const int N = 10; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof (dContact) ); if (n > 0) { for (i=0; igetParam (dParamVel3) - VEL_INC; joint->setParam (dParamVel3, vel); joint->setParam (dParamFMax3, 2); std::cout<<"Velocity = "<' : { dReal vel = joint->getParam (dParamVel3) + VEL_INC; joint->setParam (dParamVel3, vel); joint->setParam (dParamFMax3, 2); std::cout<<"Velocity = "<getParam (dParamFMax) ) { aLimit = dInfinity; lLimit = dInfinity; fmax = 0; } else { aLimit = 0.25*PI; lLimit = 0.5*axDim[LENGTH]; fmax = 0.02; } joint->setParam (dParamFMax1, fmax); joint->setParam (dParamFMax2, fmax); joint->setParam (dParamFMax3, fmax); switch (joint->getType() ) { case dJointTypePR : { dPRJoint *pr = reinterpret_cast (joint); pr->setParam (dParamLoStop, -lLimit); pr->setParam (dParamHiStop, -lLimit); pr->setParam (dParamLoStop2, aLimit); pr->setParam (dParamHiStop2, -aLimit); } break; case dJointTypePU : { dPUJoint *pu = reinterpret_cast (joint); pu->setParam (dParamLoStop1, -aLimit); pu->setParam (dParamHiStop1, aLimit); pu->setParam (dParamLoStop2, -aLimit); pu->setParam (dParamHiStop2, aLimit); pu->setParam (dParamLoStop3, -lLimit); pu->setParam (dParamHiStop3, lLimit); } break; default: {} // keep the compiler happy } } break; case 'g': case 'G' : { dVector3 g; dWorldGetGravity(world, g); if ( g[2]< -0.1 ) dWorldSetGravity(world, 0, 0, 0); else dWorldSetGravity(world, 0, 0, -0.5); } case 'p' :case 'P' : { switch (joint->getType() ) { case dJointTypeSlider : { dSliderJoint *sj = reinterpret_cast (joint); std::cout<<"Position ="<getPosition() <<"\n"; } break; case dJointTypePU : { dPUJoint *pu = reinterpret_cast (joint); std::cout<<"Position ="<getPosition() <<"\n"; std::cout<<"Position Rate="<getPositionRate() <<"\n"; std::cout<<"Angle1 ="<getAngle1() <<"\n"; std::cout<<"Angle1 Rate="<getAngle1Rate() <<"\n"; std::cout<<"Angle2 ="<getAngle2() <<"\n"; std::cout<<"Angle2 Rate="<getAngle2Rate() <<"\n"; } break; default: {} // keep the compiler happy } } break; } } static void drawBox (dGeomID id, int R, int G, int B) { if (!id) return; const dReal *pos = dGeomGetPosition (id); const dReal *rot = dGeomGetRotation (id); dsSetColor (R,G,B); dVector3 l; dGeomBoxGetLengths (id, l); dsDrawBox (pos, rot, l); } // simulation loop static void simLoop (int pause) { static bool todo = false; if ( todo ) { // DEBUG static int cnt = 0; ++cnt; if (cnt == 5) command ( 'q' ); if (cnt == 10) dsStop(); } if (!pause) { double simstep = 0.01; // 10ms simulation steps double dt = dsElapsedTime(); int nrofsteps = (int) ceilf (dt/simstep); if (!nrofsteps) nrofsteps = 1; for (int i=0; i (joint); ang1 = pu->getAngle1(); ang2 = pu->getAngle2(); pu->getAxis1 (axisR1); pu->getAxis2 (axisR2); pu->getAxisP (axisP); dJointGetPUAnchor (pu->id(), anchorPos); } else if ( dJointTypePR == type ) { dPRJoint *pr = dynamic_cast (joint); pr->getAxis1 (axisP); pr->getAxis2 (axisR1); dJointGetPRAnchor (pr->id(), anchorPos); } // Draw the axisR if ( geom[INT] ) { dsSetColor (1,0,1); dVector3 l; dGeomBoxGetLengths (geom[INT], l); const dReal *rotBox = dGeomGetRotation (geom[W]); dVector3 pos; for (int i=0; i<3; ++i) pos[i] = anchorPos[i] - 0.5*extDim[Z]*axisP[i]; dsDrawBox (pos, rotBox, l); } dsSetTexture (DS_CHECKERED); if ( geom[AXIS1] ) { dQuaternion q, qAng; dQFromAxisAndAngle (qAng,axisR1[X], axisR1[Y], axisR1[Z], ang1); dGeomGetQuaternion (geom[AXIS1], q); dQuaternion qq; dQMultiply1 (qq, qAng, q); dMatrix3 R; dQtoR (qq,R); dGeomCylinderGetParams (geom[AXIS1], &radius, &length); dsSetColor (1,0,0); dsDrawCylinder (anchorPos, R, length, radius); } if ( dJointTypePU == type && geom[AXIS2] ) { //dPUJoint *pu = dynamic_cast (joint); dQuaternion q, qAng, qq, qq1; dGeomGetQuaternion (geom[AXIS2], q); dQFromAxisAndAngle (qAng, 0, 1, 0, ang2); dQMultiply1 (qq, qAng, q); dQFromAxisAndAngle (qAng,axisR1[X], axisR1[Y], axisR1[Z], ang1); dQMultiply1 (qq1, qAng, qq); dMatrix3 R; dQtoR (qq1,R); dGeomCylinderGetParams (geom[AXIS2], &radius, &length); dsSetColor (0,0,1); dsDrawCylinder (anchorPos, R, length, radius); } dsSetTexture (DS_WOOD); // Draw the anchor if ( geom[ANCHOR] ) { dsSetColor (1,1,1); dVector3 l; dGeomBoxGetLengths (geom[ANCHOR], l); const dReal *rotBox = dGeomGetRotation (geom[D]); const dReal *posBox = dGeomGetPosition (geom[D]); dVector3 e; for (int i=0; i<3; ++i) e[i] = posBox[i] - anchorPos[i]; dNormalize3 (e); dVector3 pos; for (int i=0; i<3; ++i) pos[i] = anchorPos[i] + 0.5 * l[Z]*e[i]; dsDrawBox (pos, rotBox, l); } drawBox (geom[D], 1,1,0); } } void Help (char **argv) { printf ("%s ", argv[0]); printf (" -h | --help : print this help\n"); printf (" -p | --PRJoint : Use a PR joint instead of PU joint\n"); printf (" -t | --texture-path path : Path to the texture.\n"); printf (" Default = %s\n", DRAWSTUFF_TEXTURE_PATH); printf ("--------------------------------------------------\n"); printf ("Hit any key to continue:"); getchar(); exit (0); } int main (int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; if (argc >= 2 ) { for (int i=1; i < argc; ++i) { if ( 0 == strcmp ("-h", argv[i]) || 0 == strcmp ("--help", argv[i]) ) Help (argv); if ( 0 == strcmp ("-p", argv[i]) || 0 == strcmp ("--PRJoint", argv[i]) ) type = dJointTypePR; if (0 == strcmp ("-t", argv[i]) || 0 == strcmp ("--texture-path", argv[i]) ) { int j = i+1; if ( j+1 > argc || // Check if we have enough arguments argv[j] == '\0' || // We should have a path here argv[j][0] == '-' ) // We should have a path not a command line Help (argv); else fn.path_to_textures = argv[++i]; // Increase i since we use this argument } } } dInitODE2(0); world = dWorldCreate(); dWorldSetERP (world, 0.8); space = dSimpleSpaceCreate (0); contactgroup = dJointGroupCreate (0); geom[GROUND] = dCreatePlane (space, 0,0,1,0); dGeomSetCategoryBits (geom[GROUND], catBits[GROUND]); dGeomSetCollideBits (geom[GROUND], catBits[ALL]); dMass m; // Create the body attached to the World body[W] = dBodyCreate (world); // Main axis of cylinder is along X=1 m.setBox (1, boxDim[X], boxDim[Y], boxDim[Z]); m.adjust (Mass1); geom[W] = dCreateBox (space, boxDim[X], boxDim[Y], boxDim[Z]); dGeomSetBody (geom[W], body[W]); dGeomSetCategoryBits (geom[W], catBits[W]); dGeomSetCollideBits (geom[W], catBits[ALL] & (~catBits[W]) & (~catBits[JOINT]) ); dBodySetMass (body[W], &m); // Create the dandling body body[D] = dBodyCreate (world); // Main axis of capsule is along X=1 m.setBox (1, boxDim[X], boxDim[Y], boxDim[Z]); m.adjust (Mass1); geom[D] = dCreateBox (space, boxDim[X], boxDim[Y], boxDim[Z]); dGeomSetBody (geom[D], body[D]); dGeomSetCategoryBits (geom[D], catBits[D]); dGeomSetCollideBits (geom[D], catBits[ALL] & (~catBits[D]) & (~catBits[JOINT]) ); dBodySetMass (body[D], &m); // Create the external part of the slider joint geom[EXT] = dCreateBox (0, extDim[X], extDim[Y], extDim[Z]); dGeomSetCategoryBits (geom[EXT], catBits[EXT]); dGeomSetCollideBits (geom[EXT], catBits[ALL] & (~catBits[JOINT]) & (~catBits[W]) & (~catBits[D]) ); // Create the internal part of the slider joint geom[INT] = dCreateBox (0, INT_EXT_RATIO*extDim[X], INT_EXT_RATIO*extDim[Y], INT_EXT_RATIO*extDim[Z]); dGeomSetCategoryBits (geom[INT], catBits[INT]); dGeomSetCollideBits (geom[INT], catBits[ALL] & (~catBits[JOINT]) & (~catBits[W]) & (~catBits[D]) ); dMatrix3 R; // Create the first axis of the universal joi9nt //Rotation of 90deg around y geom[AXIS1] = dCreateCylinder(0, axDim[RADIUS], axDim[LENGTH]); dRFromAxisAndAngle(R, 0,1,0, 0.5*PI); dGeomSetRotation(geom[AXIS1], R); dGeomSetCategoryBits(geom[AXIS1], catBits[AXIS1]); dGeomSetCollideBits(geom[AXIS1], catBits[ALL] & ~catBits[JOINT] & ~catBits[W] & ~catBits[D]); // Create the second axis of the universal joint geom[AXIS2] = dCreateCylinder(0, axDim[RADIUS], axDim[LENGTH]); //Rotation of 90deg around y dRFromAxisAndAngle(R, 1,0,0, 0.5*PI); dGeomSetRotation(geom[AXIS2], R); dGeomSetCategoryBits(geom[AXIS2], catBits[AXIS2]); dGeomSetCollideBits(geom[AXIS2], catBits[ALL] & ~catBits[JOINT] & ~catBits[W] & ~catBits[D]); // Create the anchor geom[ANCHOR] = dCreateBox (0, ancDim[X], ancDim[Y], ancDim[Z]); dGeomSetCategoryBits(geom[ANCHOR], catBits[ANCHOR]); dGeomSetCollideBits(geom[ANCHOR], catBits[ALL] & (~catBits[JOINT]) & (~catBits[W]) & (~catBits[D]) ); if (body[W]) { dBodySetPosition(body[W], 0, 0, 5); } if (geom[EXT]) { dGeomSetPosition(geom[EXT], 0,0,3.8); } if (geom[INT]) { dGeomSetPosition(geom[INT], 0,0,2.6); } if (geom[AXIS1]) { dGeomSetPosition(geom[AXIS1], 0,0,2.5); } if (geom[AXIS2]) { dGeomSetPosition(geom[AXIS2], 0,0,2.5); } if (geom[ANCHOR]) { dGeomSetPosition(geom[ANCHOR], 0,0,2.25); } if (body[D]) { dBodySetPosition(body[D], 0,0,1.5); } // Attache the upper box to the world dJointID fixed = dJointCreateFixed (world,0); dJointAttach (fixed , NULL, body[W]); dJointSetFixed (fixed ); if (type == dJointTypePR) { dPRJoint *pr = new dPRJoint (world, 0); pr->attach (body[W], body[D]); pr->setAxis1 (0, 0, -1); pr->setAxis2 (1, 0, 0); joint = pr; dJointSetPRAnchor (pr->id(), 0, 0, 2.5); } else { dPUJoint *pu = new dPUJoint (world, 0); pu->attach (body[W], body[D]); pu->setAxis1 (1, 0, 0); pu->setAxis2 (0, 1, 0); pu->setAxisP (0, 0, -1); joint = pu; dJointSetPUAnchor (pu->id(), 0, 0, 2.5); } // run simulation dsSimulationLoop (argc,argv,400,300,&fn); delete joint; dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_joints.cpp0000644000000000000000000007743312635011627015435 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* perform tests on all the joint types. this should be done using the double precision version of the library. usage: test_joints [-nXXX] [-g] [-i] [-e] [path_to_textures] if a test number is given then that specific test is performed, otherwise all the tests are performed. the tests are numbered `xxyy', where xx corresponds to the joint type and yy is the sub-test number. not every number maps to an actual test. flags: i: the test is interactive. g: turn off graphical display (can't use this with `i'). e: turn on occasional error perturbations n: performe test XXX some tests compute and display error values. these values are scaled so <1 is good and >1 is bad. other tests just show graphical results which you must verify visually. */ #include #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #endif // some constants #define NUM_JOINTS 10 // number of joints to test (the `xx' value) #define SIDE (0.5f) // side length of a box - don't change this #define MASS (1.0) // mass of a box #define STEPSIZE 0.05 // dynamics objects static dWorldID world; static dBodyID body[2]; static dJointID joint; // data from the command line arguments static int cmd_test_num = -1; static int cmd_interactive = 0; static int cmd_graphics = 1; static char *cmd_path_to_textures = NULL; static int cmd_occasional_error = 0; // perturb occasionally // info about the current test struct TestInfo; static int test_num = 0; // number of the current test static int iteration = 0; static int max_iterations = 0; static dReal max_error = 0; //**************************************************************************** // utility stuff static dReal length (dVector3 a) { return dSqrt (a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); } // get the max difference between a 3x3 matrix and the identity dReal cmpIdentity (const dMatrix3 A) { dMatrix3 I; dSetZero (I,12); I[0] = 1; I[5] = 1; I[10] = 1; return dMaxDifference (A,I,3,3); } //**************************************************************************** // test world construction and utilities void constructWorldForTest (dReal gravity, int bodycount, /* body 1 pos */ dReal pos1x, dReal pos1y, dReal pos1z, /* body 2 pos */ dReal pos2x, dReal pos2y, dReal pos2z, /* body 1 rotation axis */ dReal ax1x, dReal ax1y, dReal ax1z, /* body 1 rotation axis */ dReal ax2x, dReal ax2y, dReal ax2z, /* rotation angles */ dReal a1, dReal a2) { // create world world = dWorldCreate(); dWorldSetERP (world,0.2); dWorldSetCFM (world,1e-6); dWorldSetGravity (world,0,0,gravity); dMass m; dMassSetBox (&m,1,SIDE,SIDE,SIDE); dMassAdjust (&m,MASS); body[0] = dBodyCreate (world); dBodySetMass (body[0],&m); dBodySetPosition (body[0], pos1x, pos1y, pos1z); dQuaternion q; dQFromAxisAndAngle (q,ax1x,ax1y,ax1z,a1); dBodySetQuaternion (body[0],q); if (bodycount==2) { body[1] = dBodyCreate (world); dBodySetMass (body[1],&m); dBodySetPosition (body[1], pos2x, pos2y, pos2z); dQFromAxisAndAngle (q,ax2x,ax2y,ax2z,a2); dBodySetQuaternion (body[1],q); } else body[1] = 0; } // add an oscillating torque to body 0 void addOscillatingTorque (dReal tscale) { static dReal a=0; dBodyAddTorque (body[0],tscale*cos(2*a),tscale*cos(2.7183*a), tscale*cos(1.5708*a)); a += 0.01; } void addOscillatingTorqueAbout(dReal tscale, dReal x, dReal y, dReal z) { static dReal a=0; dBodyAddTorque (body[0], tscale*cos(a) * x, tscale*cos(a) * y, tscale * cos(a) * z); a += 0.02; } // damp the rotational motion of body 0 a bit void dampRotationalMotion (dReal kd) { const dReal *w = dBodyGetAngularVel (body[0]); dBodyAddTorque (body[0],-kd*w[0],-kd*w[1],-kd*w[2]); } // add a spring force to keep the bodies together, otherwise they may fly // apart with some joints. void addSpringForce (dReal ks) { const dReal *p1 = dBodyGetPosition (body[0]); const dReal *p2 = dBodyGetPosition (body[1]); dBodyAddForce (body[0],ks*(p2[0]-p1[0]),ks*(p2[1]-p1[1]),ks*(p2[2]-p1[2])); dBodyAddForce (body[1],ks*(p1[0]-p2[0]),ks*(p1[1]-p2[1]),ks*(p1[2]-p2[2])); } // add an oscillating Force to body 0 void addOscillatingForce (dReal fscale) { static dReal a=0; dBodyAddForce (body[0],fscale*cos(2*a),fscale*cos(2.7183*a), fscale*cos(1.5708*a)); a += 0.01; } //**************************************************************************** // stuff specific to the tests // // 0xx : fixed // 1xx : ball and socket // 2xx : hinge // 3xx : slider // 4xx : hinge 2 // 5xx : contact // 6xx : amotor // 7xx : universal joint // 8xx : PR joint (Prismatic and Rotoide) // setup for the given test. return 0 if there is no such test int setupTest (int n) { switch (n) { // ********** fixed joint case 0: { // 2 body constructWorldForTest (0,2, 0.5*SIDE,0.5*SIDE,1, -0.5*SIDE,-0.5*SIDE,1, 1,1,0, 1,1,0, 0.25*M_PI,0.25*M_PI); joint = dJointCreateFixed (world,0); dJointAttach (joint,body[0],body[1]); dJointSetFixed (joint); return 1; } case 1: { // 1 body to static env constructWorldForTest (0,1, 0.5*SIDE,0.5*SIDE,1, 0,0,0, 1,0,0, 1,0,0, 0,0); joint = dJointCreateFixed (world,0); dJointAttach (joint,body[0],0); dJointSetFixed (joint); return 1; } case 2: { // 2 body with relative rotation constructWorldForTest (0,2, 0.5*SIDE,0.5*SIDE,1, -0.5*SIDE,-0.5*SIDE,1, 1,1,0, 1,1,0, 0.25*M_PI,-0.25*M_PI); joint = dJointCreateFixed (world,0); dJointAttach (joint,body[0],body[1]); dJointSetFixed (joint); return 1; } case 3: { // 1 body to static env with relative rotation constructWorldForTest (0,1, 0.5*SIDE,0.5*SIDE,1, 0,0,0, 1,0,0, 1,0,0, 0.25*M_PI,0); joint = dJointCreateFixed (world,0); dJointAttach (joint,body[0],0); dJointSetFixed (joint); return 1; } // ********** hinge joint case 200: // 2 body constructWorldForTest (0,2, 0.5*SIDE,0.5*SIDE,1, -0.5*SIDE,-0.5*SIDE,1, 1,1,0, 1,1,0, 0.25*M_PI,0.25*M_PI); joint = dJointCreateHinge (world,0); dJointAttach (joint,body[0],body[1]); dJointSetHingeAnchor (joint,0,0,1); dJointSetHingeAxis (joint,1,-1,1.41421356); return 1; case 220: // hinge angle polarity test case 221: // hinge angle rate test constructWorldForTest (0,2, 0.5*SIDE,0.5*SIDE,1, -0.5*SIDE,-0.5*SIDE,1, 1,0,0, 1,0,0, 0,0); joint = dJointCreateHinge (world,0); dJointAttach (joint,body[0],body[1]); dJointSetHingeAnchor (joint,0,0,1); dJointSetHingeAxis (joint,0,0,1); max_iterations = 50; return 1; case 230: // hinge motor rate (and polarity) test case 231: // ...with stops constructWorldForTest (0,2, 0.5*SIDE,0.5*SIDE,1, -0.5*SIDE,-0.5*SIDE,1, 1,0,0, 1,0,0, 0,0); joint = dJointCreateHinge (world,0); dJointAttach (joint,body[0],body[1]); dJointSetHingeAnchor (joint,0,0,1); dJointSetHingeAxis (joint,0,0,1); dJointSetHingeParam (joint,dParamFMax,1); if (n==231) { dJointSetHingeParam (joint,dParamLoStop,-0.5); dJointSetHingeParam (joint,dParamHiStop,0.5); } return 1; case 250: // limit bounce test (gravity down) case 251: { // ...gravity up constructWorldForTest ((n==251) ? 0.1 : -0.1, 2, 0.5*SIDE,0,1+0.5*SIDE, -0.5*SIDE,0,1-0.5*SIDE, 1,0,0, 1,0,0, 0,0); joint = dJointCreateHinge (world,0); dJointAttach (joint,body[0],body[1]); dJointSetHingeAnchor (joint,0,0,1); dJointSetHingeAxis (joint,0,1,0); dJointSetHingeParam (joint,dParamLoStop,-0.9); dJointSetHingeParam (joint,dParamHiStop,0.7854); dJointSetHingeParam (joint,dParamBounce,0.5); // anchor 2nd body with a fixed joint dJointID j = dJointCreateFixed (world,0); dJointAttach (j,body[1],0); dJointSetFixed (j); return 1; } // ********** slider case 300: // 2 body constructWorldForTest (0,2, 0,0,1, 0.2,0.2,1.2, 0,0,1, -1,1,0, 0,0.25*M_PI); joint = dJointCreateSlider (world,0); dJointAttach (joint,body[0],body[1]); dJointSetSliderAxis (joint,1,1,1); return 1; case 320: // slider angle polarity test case 321: // slider angle rate test constructWorldForTest (0,2, 0,0,1, 0,0,1.2, 1,0,0, 1,0,0, 0,0); joint = dJointCreateSlider (world,0); dJointAttach (joint,body[0],body[1]); dJointSetSliderAxis (joint,0,0,1); max_iterations = 50; return 1; case 330: // slider motor rate (and polarity) test case 331: // ...with stops constructWorldForTest (0, 2, 0,0,1, 0,0,1.2, 1,0,0, 1,0,0, 0,0); joint = dJointCreateSlider (world,0); dJointAttach (joint,body[0],body[1]); dJointSetSliderAxis (joint,0,0,1); dJointSetSliderParam (joint,dParamFMax,100); if (n==331) { dJointSetSliderParam (joint,dParamLoStop,-0.4); dJointSetSliderParam (joint,dParamHiStop,0.4); } return 1; case 350: // limit bounce tests case 351: { constructWorldForTest ((n==351) ? 0.1 : -0.1, 2, 0,0,1, 0,0,1.2, 1,0,0, 1,0,0, 0,0); joint = dJointCreateSlider (world,0); dJointAttach (joint,body[0],body[1]); dJointSetSliderAxis (joint,0,0,1); dJointSetSliderParam (joint,dParamLoStop,-0.5); dJointSetSliderParam (joint,dParamHiStop,0.5); dJointSetSliderParam (joint,dParamBounce,0.5); // anchor 2nd body with a fixed joint dJointID j = dJointCreateFixed (world,0); dJointAttach (j,body[1],0); dJointSetFixed (j); return 1; } // ********** hinge-2 joint case 420: // hinge-2 steering angle polarity test case 421: // hinge-2 steering angle rate test constructWorldForTest (0,2, 0.5*SIDE,0,1, -0.5*SIDE,0,1, 1,0,0, 1,0,0, 0,0); joint = dJointCreateHinge2 (world,0); dJointAttach (joint,body[0],body[1]); dJointSetHinge2Anchor (joint,-0.5*SIDE,0,1); dJointSetHinge2Axis1 (joint,0,0,1); dJointSetHinge2Axis2 (joint,1,0,0); max_iterations = 50; return 1; case 430: // hinge 2 steering motor rate (+polarity) test case 431: // ...with stops case 432: // hinge 2 wheel motor rate (+polarity) test constructWorldForTest (0,2, 0.5*SIDE,0,1, -0.5*SIDE,0,1, 1,0,0, 1,0,0, 0,0); joint = dJointCreateHinge2 (world,0); dJointAttach (joint,body[0],body[1]); dJointSetHinge2Anchor (joint,-0.5*SIDE,0,1); dJointSetHinge2Axis1 (joint,0,0,1); dJointSetHinge2Axis2 (joint,1,0,0); dJointSetHinge2Param (joint,dParamFMax,1); dJointSetHinge2Param (joint,dParamFMax2,1); if (n==431) { dJointSetHinge2Param (joint,dParamLoStop,-0.5); dJointSetHinge2Param (joint,dParamHiStop,0.5); } return 1; // ********** angular motor joint case 600: // test euler angle calculations constructWorldForTest (0,2, -SIDE*0.5,0,1, SIDE*0.5,0,1, 0,0,1, 0,0,1, 0,0); joint = dJointCreateAMotor (world,0); dJointAttach (joint,body[0],body[1]); dJointSetAMotorNumAxes (joint,3); dJointSetAMotorAxis (joint,0,1, 0,0,1); dJointSetAMotorAxis (joint,2,2, 1,0,0); dJointSetAMotorMode (joint,dAMotorEuler); max_iterations = 200; return 1; // ********** universal joint case 700: // 2 body case 701: case 702: constructWorldForTest (0,2, 0.5*SIDE,0.5*SIDE,1, -0.5*SIDE,-0.5*SIDE,1, 1,1,0, 1,1,0, 0.25*M_PI,0.25*M_PI); joint = dJointCreateUniversal (world,0); dJointAttach (joint,body[0],body[1]); dJointSetUniversalAnchor (joint,0,0,1); dJointSetUniversalAxis1 (joint, 1, -1, 1.41421356); dJointSetUniversalAxis2 (joint, 1, -1, -1.41421356); return 1; case 720: // universal transmit torque test case 721: case 722: case 730: // universal torque about axis 1 case 731: case 732: case 740: // universal torque about axis 2 case 741: case 742: constructWorldForTest (0,2, 0.5*SIDE,0.5*SIDE,1, -0.5*SIDE,-0.5*SIDE,1, 1,0,0, 1,0,0, 0,0); joint = dJointCreateUniversal (world,0); dJointAttach (joint,body[0],body[1]); dJointSetUniversalAnchor (joint,0,0,1); dJointSetUniversalAxis1 (joint,0,0,1); dJointSetUniversalAxis2 (joint, 1, -1,0); max_iterations = 100; return 1; // Joint PR (Prismatic and Rotoide) case 800: // 2 body case 801: // 2 bodies with spring force and prismatic fixed case 802: // 2 bodies with torque on body1 and prismatic fixed constructWorldForTest (0, 2, -1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1,0,0, 1,0,0, 0, 0); joint = dJointCreatePR (world, 0); dJointAttach (joint, body[0], body[1]); dJointSetPRAnchor (joint,-0.5, 0.0, 1.0); dJointSetPRAxis1 (joint, 0, 1, 0); dJointSetPRAxis2 (joint, 1, 0, 0); dJointSetPRParam (joint,dParamLoStop,-0.5); dJointSetPRParam (joint,dParamHiStop,0.5); dJointSetPRParam (joint,dParamLoStop2,0); dJointSetPRParam (joint,dParamHiStop2,0); return 1; case 803: // 2 bodies with spring force and prismatic NOT fixed case 804: // 2 bodies with torque force and prismatic NOT fixed case 805: // 2 bodies with force only on first body constructWorldForTest (0, 2, -1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1,0,0, 1,0,0, 0, 0); joint = dJointCreatePR (world, 0); dJointAttach (joint, body[0], body[1]); dJointSetPRAnchor (joint,-0.5, 0.0, 1.0); dJointSetPRAxis1 (joint, 0, 1, 0); dJointSetPRAxis2 (joint, 1, 0, 0); dJointSetPRParam (joint,dParamLoStop,-0.5); dJointSetPRParam (joint,dParamHiStop,0.5); dJointSetPRParam (joint,dParamLoStop2,-0.5); dJointSetPRParam (joint,dParamHiStop2,0.5); return 1; } return 0; } // do stuff specific to this test each iteration. you can check some // invariants for the test -- the return value is some scaled error measurement // that must be less than 1. // return a dInfinity if error is not measured for this n. dReal doStuffAndGetError (int n) { switch (n) { // ********** fixed joint case 0: { // 2 body addOscillatingTorque (0.1); dampRotationalMotion (0.1); // check the orientations are the same const dReal *R1 = dBodyGetRotation (body[0]); const dReal *R2 = dBodyGetRotation (body[1]); dReal err1 = dMaxDifference (R1,R2,3,3); // check the body offset is correct dVector3 p,pp; const dReal *p1 = dBodyGetPosition (body[0]); const dReal *p2 = dBodyGetPosition (body[1]); for (int i=0; i<3; i++) p[i] = p2[i] - p1[i]; dMultiply1_331 (pp,R1,p); pp[0] += 0.5; pp[1] += 0.5; return (err1 + length (pp)) * 300; } case 1: { // 1 body to static env addOscillatingTorque (0.1); // check the orientation is the identity dReal err1 = cmpIdentity (dBodyGetRotation (body[0])); // check the body offset is correct dVector3 p; const dReal *p1 = dBodyGetPosition (body[0]); for (int i=0; i<3; i++) p[i] = p1[i]; p[0] -= 0.25; p[1] -= 0.25; p[2] -= 1; return (err1 + length (p)) * 1e6; } case 2: { // 2 body addOscillatingTorque (0.1); dampRotationalMotion (0.1); // check the body offset is correct // Should really check body rotation too. Oh well. const dReal *R1 = dBodyGetRotation (body[0]); dVector3 p,pp; const dReal *p1 = dBodyGetPosition (body[0]); const dReal *p2 = dBodyGetPosition (body[1]); for (int i=0; i<3; i++) p[i] = p2[i] - p1[i]; dMultiply1_331 (pp,R1,p); pp[0] += 0.5; pp[1] += 0.5; return length(pp) * 300; } case 3: { // 1 body to static env with relative rotation addOscillatingTorque (0.1); // check the body offset is correct dVector3 p; const dReal *p1 = dBodyGetPosition (body[0]); for (int i=0; i<3; i++) p[i] = p1[i]; p[0] -= 0.25; p[1] -= 0.25; p[2] -= 1; return length (p) * 1e6; } // ********** hinge joint case 200: // 2 body addOscillatingTorque (0.1); dampRotationalMotion (0.1); return dInfinity; case 220: // hinge angle polarity test dBodyAddTorque (body[0],0,0,0.01); dBodyAddTorque (body[1],0,0,-0.01); if (iteration == 40) { dReal a = dJointGetHingeAngle (joint); if (a > 0.5 && a < 1) return 0; else return 10; } return 0; case 221: { // hinge angle rate test static dReal last_angle = 0; dBodyAddTorque (body[0],0,0,0.01); dBodyAddTorque (body[1],0,0,-0.01); dReal a = dJointGetHingeAngle (joint); dReal r = dJointGetHingeAngleRate (joint); dReal er = (a-last_angle)/STEPSIZE; // estimated rate last_angle = a; return fabs(r-er) * 4e4; } case 230: // hinge motor rate (and polarity) test case 231: { // ...with stops static dReal a = 0; dReal r = dJointGetHingeAngleRate (joint); dReal err = fabs (cos(a) - r); if (a==0) err = 0; a += 0.03; dJointSetHingeParam (joint,dParamVel,cos(a)); if (n==231) return dInfinity; return err * 1e6; } // ********** slider joint case 300: // 2 body addOscillatingTorque (0.05); dampRotationalMotion (0.1); addSpringForce (0.5); return dInfinity; case 320: // slider angle polarity test dBodyAddForce (body[0],0,0,0.1); dBodyAddForce (body[1],0,0,-0.1); if (iteration == 40) { dReal a = dJointGetSliderPosition (joint); if (a > 0.2 && a < 0.5) return 0; else return 10; // Failed } return 0; case 321: { // slider angle rate test static dReal last_pos = 0; dBodyAddForce (body[0],0,0,0.1); dBodyAddForce (body[1],0,0,-0.1); dReal p = dJointGetSliderPosition (joint); dReal r = dJointGetSliderPositionRate (joint); dReal er = (p-last_pos)/STEPSIZE; // estimated rate (almost exact) last_pos = p; return fabs(r-er) * 1e9; } case 330: // slider motor rate (and polarity) test case 331: { // ...with stops static dReal a = 0; dReal r = dJointGetSliderPositionRate (joint); dReal err = fabs (0.7*cos(a) - r); if (a < 0.04) err = 0; a += 0.03; dJointSetSliderParam (joint,dParamVel,0.7*cos(a)); if (n==331) return dInfinity; return err * 1e6; } // ********** hinge-2 joint case 420: // hinge-2 steering angle polarity test dBodyAddTorque (body[0],0,0,0.01); dBodyAddTorque (body[1],0,0,-0.01); if (iteration == 40) { dReal a = dJointGetHinge2Angle1 (joint); if (a > 0.5 && a < 0.6) return 0; else return 10; } return 0; case 421: { // hinge-2 steering angle rate test static dReal last_angle = 0; dBodyAddTorque (body[0],0,0,0.01); dBodyAddTorque (body[1],0,0,-0.01); dReal a = dJointGetHinge2Angle1 (joint); dReal r = dJointGetHinge2Angle1Rate (joint); dReal er = (a-last_angle)/STEPSIZE; // estimated rate last_angle = a; return fabs(r-er)*2e4; } case 430: // hinge 2 steering motor rate (+polarity) test case 431: { // ...with stops static dReal a = 0; dReal r = dJointGetHinge2Angle1Rate (joint); dReal err = fabs (cos(a) - r); if (a==0) err = 0; a += 0.03; dJointSetHinge2Param (joint,dParamVel,cos(a)); if (n==431) return dInfinity; return err * 1e6; } case 432: { // hinge 2 wheel motor rate (+polarity) test static dReal a = 0; dReal r = dJointGetHinge2Angle2Rate (joint); dReal err = fabs (cos(a) - r); if (a==0) err = 0; a += 0.03; dJointSetHinge2Param (joint,dParamVel2,cos(a)); return err * 1e6; } // ********** angular motor joint case 600: { // test euler angle calculations // desired euler angles from last iteration static dReal a1,a2,a3; // find actual euler angles dReal aa1 = dJointGetAMotorAngle (joint,0); dReal aa2 = dJointGetAMotorAngle (joint,1); dReal aa3 = dJointGetAMotorAngle (joint,2); // printf ("actual = %.4f %.4f %.4f\n\n",aa1,aa2,aa3); dReal err = dInfinity; if (iteration > 0) { err = dFabs(aa1-a1) + dFabs(aa2-a2) + dFabs(aa3-a3); err *= 1e10; } // get random base rotation for both bodies dMatrix3 Rbase; dRFromAxisAndAngle (Rbase, 3*(dRandReal()-0.5), 3*(dRandReal()-0.5), 3*(dRandReal()-0.5), 3*(dRandReal()-0.5)); dBodySetRotation (body[0],Rbase); // rotate body 2 by random euler angles w.r.t. body 1 a1 = 3.14 * 2 * (dRandReal()-0.5); a2 = 1.57 * 2 * (dRandReal()-0.5); a3 = 3.14 * 2 * (dRandReal()-0.5); dMatrix3 R1,R2,R3,Rtmp1,Rtmp2; dRFromAxisAndAngle (R1,0,0,1,-a1); dRFromAxisAndAngle (R2,0,1,0,a2); dRFromAxisAndAngle (R3,1,0,0,-a3); dMultiply0 (Rtmp1,R2,R3,3,3,3); dMultiply0 (Rtmp2,R1,Rtmp1,3,3,3); dMultiply0 (Rtmp1,Rbase,Rtmp2,3,3,3); dBodySetRotation (body[1],Rtmp1); // printf ("desired = %.4f %.4f %.4f\n",a1,a2,a3); return err; } // ********** universal joint case 700: { // 2 body: joint constraint dVector3 ax1, ax2; addOscillatingTorque (0.1); dampRotationalMotion (0.1); dJointGetUniversalAxis1(joint, ax1); dJointGetUniversalAxis2(joint, ax2); return fabs(10*dCalcVectorDot3(ax1, ax2)); } case 701: { // 2 body: angle 1 rate static dReal last_angle = 0; addOscillatingTorque (0.1); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle1(joint); dReal r = dJointGetUniversalAngle1Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; // I'm not sure why the error is so large here. return fabs(r - er) * 1e1; } case 702: { // 2 body: angle 2 rate static dReal last_angle = 0; addOscillatingTorque (0.1); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle2(joint); dReal r = dJointGetUniversalAngle2Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; // I'm not sure why the error is so large here. return fabs(r - er) * 1e1; } case 720: { // universal transmit torque test: constraint error dVector3 ax1, ax2; addOscillatingTorqueAbout (0.1, 1, 1, 0); dampRotationalMotion (0.1); dJointGetUniversalAxis1(joint, ax1); dJointGetUniversalAxis2(joint, ax2); return fabs(10*dCalcVectorDot3(ax1, ax2)); } case 721: { // universal transmit torque test: angle1 rate static dReal last_angle = 0; addOscillatingTorqueAbout (0.1, 1, 1, 0); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle1(joint); dReal r = dJointGetUniversalAngle1Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; return fabs(r - er) * 1e10; } case 722: { // universal transmit torque test: angle2 rate static dReal last_angle = 0; addOscillatingTorqueAbout (0.1, 1, 1, 0); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle2(joint); dReal r = dJointGetUniversalAngle2Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; return fabs(r - er) * 1e10; } case 730:{ dVector3 ax1, ax2; dJointGetUniversalAxis1(joint, ax1); dJointGetUniversalAxis2(joint, ax2); addOscillatingTorqueAbout (0.1, ax1[0], ax1[1], ax1[2]); dampRotationalMotion (0.1); return fabs(10*dCalcVectorDot3(ax1, ax2)); } case 731:{ dVector3 ax1; static dReal last_angle = 0; dJointGetUniversalAxis1(joint, ax1); addOscillatingTorqueAbout (0.1, ax1[0], ax1[1], ax1[2]); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle1(joint); dReal r = dJointGetUniversalAngle1Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; return fabs(r - er) * 2e3; } case 732:{ dVector3 ax1; static dReal last_angle = 0; dJointGetUniversalAxis1(joint, ax1); addOscillatingTorqueAbout (0.1, ax1[0], ax1[1], ax1[2]); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle2(joint); dReal r = dJointGetUniversalAngle2Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; return fabs(r - er) * 1e10; } case 740:{ dVector3 ax1, ax2; dJointGetUniversalAxis1(joint, ax1); dJointGetUniversalAxis2(joint, ax2); addOscillatingTorqueAbout (0.1, ax2[0], ax2[1], ax2[2]); dampRotationalMotion (0.1); return fabs(10*dCalcVectorDot3(ax1, ax2)); } case 741:{ dVector3 ax2; static dReal last_angle = 0; dJointGetUniversalAxis2(joint, ax2); addOscillatingTorqueAbout (0.1, ax2[0], ax2[1], ax2[2]); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle1(joint); dReal r = dJointGetUniversalAngle1Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; return fabs(r - er) * 1e10; } case 742:{ dVector3 ax2; static dReal last_angle = 0; dJointGetUniversalAxis2(joint, ax2); addOscillatingTorqueAbout (0.1, ax2[0], ax2[1], ax2[2]); dampRotationalMotion (0.1); dReal a = dJointGetUniversalAngle2(joint); dReal r = dJointGetUniversalAngle2Rate(joint); dReal diff = a - last_angle; if (diff > M_PI) diff -= 2*M_PI; if (diff < -M_PI) diff += 2*M_PI; dReal er = diff / STEPSIZE; // estimated rate last_angle = a; return fabs(r - er) * 1e4; } // ********** slider joint case 801: case 803: addSpringForce (0.25); return dInfinity; case 802: case 804: { static dReal a = 0; dBodyAddTorque (body[0], 0, 0.01*cos(1.5708*a), 0); a += 0.01; return dInfinity; } case 805: addOscillatingForce (0.1); return dInfinity; } return dInfinity; } //**************************************************************************** // simulation stuff common to all the tests // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {1.0382f,-1.0811f,1.4700f}; static float hpr[3] = {135.0000f,-19.5000f,0.0000f}; dsSetViewpoint (xyz,hpr); } // simulation loop static void simLoop (int pause) { // stop after a given number of iterations, as long as we are not in // interactive mode if (cmd_graphics && !cmd_interactive && (iteration >= max_iterations)) { dsStop(); return; } iteration++; if (!pause) { // do stuff for this test and check to see if the joint is behaving well dReal error = doStuffAndGetError (test_num); if (error > max_error) max_error = error; if (cmd_interactive && error < dInfinity) { printf ("scaled error = %.4e\n",error); } // take a step dWorldStep (world,STEPSIZE); // occasionally re-orient the first body to create a deliberate error. if (cmd_occasional_error) { static int count = 0; if ((count % 20)==0) { // randomly adjust orientation of body[0] const dReal *R1; dMatrix3 R2,R3; R1 = dBodyGetRotation (body[0]); dRFromAxisAndAngle (R2,dRandReal()-0.5,dRandReal()-0.5, dRandReal()-0.5,dRandReal()-0.5); dMultiply0 (R3,R1,R2,3,3,3); dBodySetRotation (body[0],R3); // randomly adjust position of body[0] const dReal *pos = dBodyGetPosition (body[0]); dBodySetPosition (body[0], pos[0]+0.2*(dRandReal()-0.5), pos[1]+0.2*(dRandReal()-0.5), pos[2]+0.2*(dRandReal()-0.5)); } count++; } } if (cmd_graphics) { dReal sides1[3] = {SIDE,SIDE,SIDE}; dReal sides2[3] = {SIDE*0.99f,SIDE*0.99f,SIDE*0.99f}; dsSetTexture (DS_WOOD); dsSetColor (1,1,0); dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1); if (body[1]) { dsSetColor (0,1,1); dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2); } } } //**************************************************************************** // conduct a specific test, and report the results void doTest (int argc, char **argv, int n, int fatal_if_bad_n) { test_num = n; iteration = 0; max_iterations = 300; max_error = 0; if (! setupTest (n)) { if (fatal_if_bad_n) dError (0,"bad test number"); return; } // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = 0; fn.stop = 0; if (cmd_path_to_textures) fn.path_to_textures = cmd_path_to_textures; else fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // run simulation if (cmd_graphics) { dsSimulationLoop (argc,argv,352,288,&fn); } else { for (int i=0; i < max_iterations; i++) simLoop (0); } dWorldDestroy (world); body[0] = 0; body[1] = 0; joint = 0; // print results printf ("test %d: ",n); if (max_error == dInfinity) printf ("error not computed\n"); else { printf ("max scaled error = %.4e",max_error); if (max_error < 1) printf (" - passed\n"); else printf (" - FAILED\n"); } } //**************************************************************************** // main int main (int argc, char **argv) { int i; dInitODE2(0); // process the command line args. anything that starts with `-' is assumed // to be a drawstuff argument. for (i=1; i #include #include #include #include #include #include "texturepath.h" #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawCylinder dsDrawCylinderD #endif using namespace std; dWorld *world; dSpace *space; dPlane *ground; dBody *kbody; dBox *kbox; dJointGroup joints; dCylinder *kpole; dBody *matraca; dBox *matraca_geom; dHingeJoint *hinge; struct Box { dBody body; dBox geom; Box() : body(*world), geom(*space, 0.2, 0.2, 0.2) { dMass mass; mass.setBox(10, 0.2, 0.2, 0.2); body.setMass(mass); geom.setData(this); geom.setBody(body); } void draw() const { dVector3 lengths; geom.getLengths(lengths); dsSetTexture(DS_WOOD); dsSetColor(0,1,0); dsDrawBox(geom.getPosition(), geom.getRotation(), lengths); } }; set boxes; set to_remove; void dropBox() { Box *box = new Box(); dReal px = (rand() / float(RAND_MAX)) * 2 - 1; dReal py = (rand() / float(RAND_MAX)) * 2 - 1; dReal pz = 2.5; box->body.setPosition(px, py, pz); boxes.insert(box); } void queueRemoval(dGeomID g) { Box *b = (Box*)dGeomGetData(g); to_remove.insert(b); } void removeQueued() { while (!to_remove.empty()) { Box *b = *to_remove.begin(); to_remove.erase(b); boxes.erase(b); delete b; } } void nearCallback(void *, dGeomID g1, dGeomID g2) { if (g1 == ground->id()) { queueRemoval(g2); return; } if (g2 == ground->id()) { queueRemoval(g1); return; } dBodyID b1 = dGeomGetBody(g1); dBodyID b2 = dGeomGetBody(g2); if (b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) return; const int MAX_CONTACTS = 10; dContact contact[MAX_CONTACTS]; int n = dCollide(g1, g2, MAX_CONTACTS, &contact[0].geom, sizeof(dContact)); for (int i=0; i 2*M_PI) t = 0; dVector3 next_pos = { dCos(t), dSin(t), REAL(0.5)}; dVector3 vel; // vel = (next_pos - cur_pos) / timestep dSubtractVectors3(vel, next_pos, kbody->getPosition()); dScaleVector3(vel, 1/timestep); kbody->setLinearVel(vel); // end of hard-coded animation space->collide(0, nearCallback); removeQueued(); world->quickStep(timestep); joints.clear(); } dVector3 lengths; // the moving platform kbox->getLengths(lengths); dsSetTexture(DS_WOOD); dsSetColor(.3, .3, 1); dsDrawBox(kbox->getPosition(), kbox->getRotation(), lengths); dReal length, radius; kpole->getParams(&radius, &length); dsSetTexture(DS_CHECKERED); dsSetColor(1, 1, 0); dsDrawCylinder(kpole->getPosition(), kpole->getRotation(), length, radius); // the matraca matraca_geom->getLengths(lengths); dsSetColor(1,0,0); dsSetTexture(DS_WOOD); dsDrawBox(matraca_geom->getPosition(), matraca_geom->getRotation(), lengths); // and the boxes for_each(boxes.begin(), boxes.end(), mem_fun(&Box::draw)); } void command(int c) { switch (c) { case ' ': dropBox(); break; } } int main(int argc, char **argv) { dInitODE(); // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = 0; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; cout << endl << "*** Press SPACE to drop boxes **" << endl; space = new dSimpleSpace(); ground = new dPlane(*space, 0, 0, 1, 0); world = new dWorld; world->setGravity(0, 0, -.5); kbody = new dBody(*world); kbody->setKinematic(); const dReal kx = 1, ky = 0, kz = .5; kbody->setPosition(kx, ky, kz); kbox = new dBox(*space, 3, 3, .5); kbox->setBody(*kbody); kpole = new dCylinder(*space, .125, 1.5); kpole->setBody(*kbody); dGeomSetOffsetPosition(kpole->id(), 0, 0, 0.8); matraca = new dBody(*world); matraca->setPosition(kx+0, ky+1, kz+1); matraca_geom = new dBox(*space, 0.5, 2, 0.75); matraca_geom->setBody(*matraca); dMass mass; mass.setBox(1, 0.5, 2, 0.75); matraca->setMass(mass); hinge = new dHingeJoint(*world); hinge->attach(*kbody, *matraca); hinge->setAnchor(kx, ky, kz+1); hinge->setAxis(0, 0, 1); dsSimulationLoop (argc, argv, 640, 480, &fn); dCloseODE(); } ode-0.14/ode/demo/demo_motion.cpp0000644000000000000000000003665612635011627015436 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* This demo shows how to use dContactMotionN in a lifting platform. */ //#include // for usleep() #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawConvex dsDrawConvexD #endif // some constants #define NUM 100 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 8 // maximum number of contact points per body #define USE_GEOM_OFFSET 1 // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? static int write_world = 0; static int show_body = 0; static dGeomID platform, ground; dVector3 platpos = {0, 0, 0}; int mov_type = 2; dReal mov_time = 0; const dReal mov1_speed = 0.2; dVector3 mov2_vel = { 0.2, 0.1, 0.25}; /**************************************************************** * Movement 1: move platform up, reset every 80 units of time. * * This is the simplest case * ****************************************************************/ static void moveplat_1(dReal stepsize) { mov_time += stepsize; if (mov_time > 80) mov_time = 0; platpos[0] = platpos[1] = 0; // the platform moves up (Z) at constant speed: mov1_speed platpos[2] = mov1_speed * mov_time; } // Generate contact info for movement 1 static void contactplat_1(dContact &contact) { contact.surface.mode |= dContactMotionN; contact.surface.motionN = mov1_speed; } /**************************************************************** * Movement 2: move platform along direction mov2_vel, reset * * every 80 units of time. * * This is the most general case: the geom moves along * * an arbitrary direction. * ****************************************************************/ static void moveplat_2(dReal stepsize) { mov_time += stepsize; if (mov_time > 80) mov_time = 0; // the platform moves at constant speed: mov2_speed platpos[0] = mov2_vel[0] * mov_time; platpos[1] = mov2_vel[1] * mov_time; platpos[2] = mov2_vel[2] * mov_time; } // Generate contact info for movement 1 static void contactplat_2(dContact &contact) { /* For arbitrary contact directions we need to project the moving geom's velocity against the contact normal and fdir1, fdir2 (obtained with dPlaneSpace()). Assuming moving geom=g2 (so the contact joint is in the moving geom's reference frame): motion1 = dCalcVectorDot3(fdir1, vel); motion2 = dCalcVectorDot3(fdir2, vel); motionN = dCalcVectorDot3(normal, vel); For geom=g1 just negate motionN and motion2. fdir1 is an arbitrary vector, so there's no need to negate motion1. */ contact.surface.mode |= dContactMotionN | // velocity along normal dContactMotion1 | dContactMotion2 | // and along the contact plane dContactFDir1; // don't forget to set the direction 1 // This is a convenience function: given a vector, it finds other 2 perpendicular vectors dVector3 motiondir1, motiondir2; dPlaneSpace(contact.geom.normal, motiondir1, motiondir2); for (int i=0; i<3; ++i) contact.fdir1[i] = motiondir1[i]; dReal inv = 1; if (contact.geom.g1 == platform) inv = -1; contact.surface.motion1 = dCalcVectorDot3(mov2_vel, motiondir1); contact.surface.motion2 = inv * dCalcVectorDot3(mov2_vel, motiondir2); contact.surface.motionN = inv * dCalcVectorDot3(mov2_vel, contact.geom.normal); } static void nearCallback (void *, dGeomID o1, dGeomID o2) { dMatrix3 RI; static const dReal ss[3] = {0.02,0.02,0.02}; dContact contact[MAX_CONTACTS]; int numc = dCollide (o1, o2, MAX_CONTACTS, &contact[0].geom, sizeof(dContact)); if (numc) dRSetIdentity(RI); bool isplatform = (o1 == platform) || (o2 == platform); for (int i=0; i< numc; i++) { contact[i].surface.mode = dContactBounce; contact[i].surface.mu = 1; contact[i].surface.bounce = 0.25; contact[i].surface.bounce_vel = 0.01; if (isplatform) { switch (mov_type) { case 1: contactplat_1(contact[i]); break; case 2: contactplat_2(contact[i]); break; } } dJointID c = dJointCreateContact (world,contactgroup,contact+i); dJointAttach (c, dGeomGetBody(o1), dGeomGetBody(o2)); if (show_contacts) dsDrawBox (contact[i].geom.pos, RI, ss); } } // start simulation - set viewpoint static float xyz[3] = {2.1106f,-1.3007,2.f}; static float hpr[3] = {150.f,-13.5000f,0.0000f}; static void start() { //dAllocateODEDataForThread(dAllocateMaskAll); dsSetViewpoint (xyz,hpr); printf ("To drop another object, press:\n"); printf (" b for box.\n"); printf (" s for sphere.\n"); printf (" c for capsule.\n"); printf (" y for cylinder.\n"); printf ("Press m to change the movement type\n"); printf ("Press space to reset the platform\n"); printf ("To toggle showing the geom AABBs, press a.\n"); printf ("To toggle showing the contact points, press t.\n"); printf ("To toggle dropping from random position/orientation, press r.\n"); printf ("To save the current state to 'state.dif', press 1.\n"); } char locase (char c) { if (c >= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command (int cmd) { size_t i; int k; dReal sides[3]; dMass m; int setBody; cmd = locase (cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'y') { setBody = 0; if (num < NUM) { i = num; num++; } else { i = nextobj; nextobj++; if (nextobj >= num) nextobj = 0; // destroy the body and geoms for slot i if (obj[i].body) { dBodyDestroy (obj[i].body); } for (k=0; k < GPB; k++) { if (obj[i].geom[k]) { dGeomDestroy (obj[i].geom[k]); } } memset (&obj[i],0,sizeof(obj[i])); } obj[i].body = dBodyCreate (world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition (obj[i].body, dRandReal()*2-1 + platpos[0], dRandReal()*2-1 + platpos[1], dRandReal()+2 + platpos[2]); dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { dBodySetPosition (obj[i].body, platpos[0], platpos[1], platpos[2]+2); dRSetIdentity (R); } dBodySetRotation (obj[i].body,R); dBodySetData (obj[i].body,(void*) i); if (cmd == 'b') { dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]); } else if (cmd == 'y') { dMassSetCylinder (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere (space,sides[0]); } if (!setBody) for (k=0; k < GPB; k++) { if (obj[i].geom[k]) { dGeomSetBody (obj[i].geom[k],obj[i].body); } } dBodySetMass (obj[i].body,&m); } else if (cmd == 'a') { show_aabb ^= 1; } else if (cmd == 't') { show_contacts ^= 1; } else if (cmd == 'r') { random_pos ^= 1; } else if (cmd == '1') { write_world = 1; } else if (cmd == ' ') { mov_time = 0; } else if (cmd == 'm') { mov_type = mov_type==1 ? 2 : 1; mov_time = 0; } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { int i; if (!g) return; if (!pos) pos = dGeomGetPosition (g); if (!R) R = dGeomGetRotation (g); int type = dGeomGetClass (g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths (g,sides); dsDrawBox (pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere (pos,R,dGeomSphereGetRadius (g)); } else if (type == dCapsuleClass) { dReal radius,length; dGeomCapsuleGetParams (g,&radius,&length); dsDrawCapsule (pos,R,length,radius); } else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams (g,&radius,&length); dsDrawCylinder (pos,R,length,radius); } if (show_body) { dBodyID body = dGeomGetBody(g); if (body) { const dReal *bodypos = dBodyGetPosition (body); const dReal *bodyr = dBodyGetRotation (body); dReal bodySides[3] = { 0.1, 0.1, 0.1 }; dsSetColorAlpha(0,1,0,1); dsDrawBox(bodypos,bodyr,bodySides); } } if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB (g,aabb); dVector3 bbpos; for (i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (i=0; i<3; i++) bbsides[i] = aabb[i*2+1] - aabb[i*2]; dMatrix3 RI; dRSetIdentity (RI); dsSetColorAlpha (1,0,0,0.5); dsDrawBox (bbpos,RI,bbsides); } } // simulation loop static void updatecam() { xyz[0] = platpos[0] + 3.3; xyz[1] = platpos[1] - 1.8; xyz[2] = platpos[2] + 2; dsSetViewpoint (xyz, hpr); } static void simLoop (int pause) { const dReal stepsize = 0.02; dsSetColor (0,0,2); dSpaceCollide (space,0,&nearCallback); if (!pause) { if (mov_type == 1) moveplat_1(stepsize); else moveplat_2(stepsize); dGeomSetPosition(platform, platpos[0], platpos[1], platpos[2]); updatecam(); dWorldQuickStep (world,stepsize); //dWorldStep (world,stepsize); } if (write_world) { FILE *f = fopen ("state.dif","wt"); if (f) { dWorldExportDIF (world,f,"X"); fclose (f); } write_world = 0; } // remove all contact joints dJointGroupEmpty (contactgroup); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (int i=0; i #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #endif // some constants #define SIDE (0.5f) // side length of a box #define MASS (1.0) // mass of a box // dynamics and collision objects static dWorldID world; static dBodyID body[2]; static dGeomID geom[2]; static dJointID lmotor[2]; static dJointID amotor[2]; static dSpaceID space; static dJointGroupID contactgroup; // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {1.0382f,-1.0811f,1.4700f}; static float hpr[3] = {135.0000f,-19.5000f,0.0000f}; dsSetViewpoint (xyz,hpr); printf ("Press 'q,a,z' to control one axis of lmotor connectiong two bodies. (q is +,a is 0, z is -)\n"); printf ("Press 'w,e,r' to control one axis of lmotor connectiong first body with world. (w is +,e is 0, r is -)\n"); } // called when a key pressed static void command (int cmd) { if (cmd == 'q' || cmd == 'Q') { dJointSetLMotorParam(lmotor[0],dParamVel,0); dJointSetLMotorParam(lmotor[0],dParamVel2,0); dJointSetLMotorParam(lmotor[0],dParamVel3,0.1); } else if (cmd == 'a' || cmd == 'A') { dJointSetLMotorParam(lmotor[0],dParamVel,0); dJointSetLMotorParam(lmotor[0],dParamVel2,0); dJointSetLMotorParam(lmotor[0],dParamVel3,0); } else if (cmd == 'z' || cmd == 'Z') { dJointSetLMotorParam(lmotor[0],dParamVel,0); dJointSetLMotorParam(lmotor[0],dParamVel2,0); dJointSetLMotorParam(lmotor[0],dParamVel3,-0.1); } else if (cmd == 'w' || cmd == 'W') { dJointSetLMotorParam(lmotor[1],dParamVel,0.1); dJointSetLMotorParam(lmotor[1],dParamVel2,0); dJointSetLMotorParam(lmotor[1],dParamVel3,0); } else if (cmd == 'e' || cmd == 'E') { dJointSetLMotorParam(lmotor[1],dParamVel,0); dJointSetLMotorParam(lmotor[1],dParamVel2,0); dJointSetLMotorParam(lmotor[1],dParamVel3,0); } else if (cmd == 'r' || cmd == 'R') { dJointSetLMotorParam(lmotor[1],dParamVel,-0.1); dJointSetLMotorParam(lmotor[1],dParamVel2,0); dJointSetLMotorParam(lmotor[1],dParamVel3,0); } } static void nearCallback (void *, dGeomID o1, dGeomID o2) { // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); dContact contact; contact.surface.mode = 0; contact.surface.mu = dInfinity; if (dCollide (o1,o2,1,&contact.geom,sizeof(dContactGeom))) { dJointID c = dJointCreateContact (world,contactgroup,&contact); dJointAttach (c,b1,b2); } } // simulation loop static void simLoop (int pause) { if (!pause) { dSpaceCollide(space,0,&nearCallback); dWorldQuickStep (world,0.05); dJointGroupEmpty(contactgroup); } dReal sides1[3]; dGeomBoxGetLengths(geom[0], sides1); dReal sides2[3]; dGeomBoxGetLengths(geom[1], sides2); dsSetTexture (DS_WOOD); dsSetColor (1,1,0); dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1); dsSetColor (0,1,1); dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2); } int main (int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE2(0); contactgroup = dJointGroupCreate(0); world = dWorldCreate(); space = dSimpleSpaceCreate(0); dMass m; dMassSetBox (&m,1,SIDE,SIDE,SIDE); dMassAdjust (&m,MASS); body[0] = dBodyCreate (world); dBodySetMass (body[0],&m); dBodySetPosition (body[0],0,0,1); geom[0] = dCreateBox(space,SIDE,SIDE,SIDE); body[1] = dBodyCreate (world); dBodySetMass (body[1],&m); dBodySetPosition (body[1],0,0,2); geom[1] = dCreateBox(space,SIDE,SIDE,SIDE); dGeomSetBody(geom[0],body[0]); dGeomSetBody(geom[1],body[1]); lmotor[0] = dJointCreateLMotor (world,0); dJointAttach (lmotor[0],body[0],body[1]); lmotor[1] = dJointCreateLMotor (world,0); dJointAttach (lmotor[1],body[0],0); amotor[0] = dJointCreateAMotor(world,0); dJointAttach(amotor[0], body[0],body[1]); amotor[1] = dJointCreateAMotor(world,0); dJointAttach(amotor[1], body[0], 0); for (int i=0; i<2; i++) { dJointSetAMotorNumAxes(amotor[i], 3); dJointSetAMotorAxis(amotor[i],0,1,1,0,0); dJointSetAMotorAxis(amotor[i],1,1,0,1,0); dJointSetAMotorAxis(amotor[i],2,1,0,0,1); dJointSetAMotorParam(amotor[i],dParamFMax,0.00001); dJointSetAMotorParam(amotor[i],dParamFMax2,0.00001); dJointSetAMotorParam(amotor[i],dParamFMax3,0.00001); dJointSetAMotorParam(amotor[i],dParamVel,0); dJointSetAMotorParam(amotor[i],dParamVel2,0); dJointSetAMotorParam(amotor[i],dParamVel3,0); dJointSetLMotorNumAxes(lmotor[i],3); dJointSetLMotorAxis(lmotor[i],0,1,1,0,0); dJointSetLMotorAxis(lmotor[i],1,1,0,1,0); dJointSetLMotorAxis(lmotor[i],2,1,0,0,1); dJointSetLMotorParam(lmotor[i],dParamFMax,0.0001); dJointSetLMotorParam(lmotor[i],dParamFMax2,0.0001); dJointSetLMotorParam(lmotor[i],dParamFMax3,0.0001); } // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dJointGroupDestroy(contactgroup); dSpaceDestroy (space); dWorldDestroy (world); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_moving_convex.cpp0000644000000000000000000002624212635011627017000 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include "texturepath.h" #include "bunny_geom.h" #include "convex_bunny_geom.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawLine dsDrawLineD #define dsDrawTriangle dsDrawTriangleD #define dsDrawConvex dsDrawConvexD #endif // some constants #define NUM 200 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 64 // maximum number of contact points per body // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? typedef dReal dVector3R[3]; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback( void *, dGeomID o1, dGeomID o2 ) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody( o1 ); dBodyID b2 = dGeomGetBody( o2 ); if ( b1 && b2 && dAreConnectedExcluding( b1,b2,dJointTypeContact ) ) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for ( i=0; i= 'A' && c <= 'Z' ) return c - ( 'a'-'A' ); else return c; } // called when a key pressed static void command( int cmd ) { int i,k; dReal sides[3]; dMass m; cmd = locase( cmd ); if ( cmd == 'v' || cmd == 'b' || cmd == 'c' || cmd == 's' || cmd == 'y') { if ( num < NUM ) { i = num; num++; } else { i = nextobj; nextobj++; if ( nextobj >= num ) nextobj = 0; // destroy the body and geoms for slot i dBodyDestroy( obj[i].body ); for ( k=0; k < GPB; k++ ) { if ( obj[i].geom[k] ) dGeomDestroy( obj[i].geom[k] ); } memset( &obj[i],0,sizeof( obj[i] ) ); } obj[i].body = dBodyCreate( world ); for ( k=0; k<3; k++ ) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if ( random_pos ) { dBodySetPosition( obj[i].body, dRandReal()*2-1,dRandReal()*2-1,dRandReal()+3 ); dRFromAxisAndAngle( R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0 ); } else { dReal maxheight = 0; for ( k=0; k maxheight ) maxheight = pos[2]; } dBodySetPosition( obj[i].body, 0,0,maxheight+1 ); dRFromAxisAndAngle( R,0,0,1,dRandReal()*10.0-5.0 ); } dBodySetRotation( obj[i].body,R ); dBodySetData( obj[i].body,( void* )( size_t )i ); if ( cmd == 'b' ) { dMassSetBox( &m,DENSITY,sides[0],sides[1],sides[2] ); obj[i].geom[0] = dCreateBox( space,sides[0],sides[1],sides[2] ); } else if ( cmd == 'c' ) { sides[0] *= 0.5; dMassSetCapsule( &m,DENSITY,3,sides[0],sides[1] ); obj[i].geom[0] = dCreateCapsule( space,sides[0],sides[1] ); } else if (cmd == 'y') { dMassSetCylinder (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]); } else if ( cmd == 's' ) { sides[0] *= 0.5; dMassSetSphere( &m,DENSITY,sides[0] ); obj[i].geom[0] = dCreateSphere( space,sides[0] ); } else if ( cmd == 'v' ) { obj[i].geom[0] = dCreateConvex( space, convexBunnyPlanes, convexBunnyPlaneCount, convexBunnyPoints, convexBunnyPointCount, convexBunnyPolygons ); /// Use equivalent TriMesh to set mass dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate(); dGeomTriMeshDataBuildSingle( new_tmdata, &Vertices[0], 3 * sizeof( float ), VertexCount, ( dTriIndex* )&Indices[0], IndexCount, 3 * sizeof( dTriIndex ) ); dGeomID triMesh = dCreateTriMesh( 0, new_tmdata, 0, 0, 0 ); dMassSetTrimesh( &m, DENSITY, triMesh ); dGeomDestroy( triMesh ); dGeomTriMeshDataDestroy( new_tmdata ); printf( "mass at %f %f %f\n", m.c[0], m.c[1], m.c[2] ); dGeomSetPosition( obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2] ); dMassTranslate( &m, -m.c[0], -m.c[1], -m.c[2] ); } for ( k=0; k < GPB; k++ ) { if ( obj[i].geom[k] ) dGeomSetBody( obj[i].geom[k],obj[i].body ); } dBodySetMass( obj[i].body,&m ); } if ( cmd == ' ' ) { selected++; if ( selected >= num ) selected = 0; if ( selected < 0 ) selected = 0; } else if ( cmd == 'd' && selected >= 0 && selected < num ) { dBodyDisable( obj[selected].body ); } else if ( cmd == 'e' && selected >= 0 && selected < num ) { dBodyEnable( obj[selected].body ); } else if ( cmd == 'a' ) { show_aabb ^= 1; } else if ( cmd == 't' ) { show_contacts ^= 1; } else if ( cmd == 'r' ) { random_pos ^= 1; } } // draw a geom void drawGeom( dGeomID g, const dReal *pos, const dReal *R, int show_aabb ) { if ( !g ) return; if ( !pos ) pos = dGeomGetPosition( g ); if ( !R ) R = dGeomGetRotation( g ); int type = dGeomGetClass( g ); if ( type == dBoxClass ) { dVector3 sides; dGeomBoxGetLengths( g,sides ); dsDrawBox( pos,R,sides ); } else if ( type == dSphereClass ) { dsDrawSphere( pos,R,dGeomSphereGetRadius( g ) ); } else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams (g,&radius,&length); dsDrawCylinder (pos,R,length,radius); } else if ( type == dCapsuleClass ) { dReal radius,length; dGeomCapsuleGetParams( g,&radius,&length ); dsDrawCapsule( pos,R,length,radius ); } else if ( type == dConvexClass ) { dsDrawConvex( pos,R, convexBunnyPlanes, convexBunnyPlaneCount, convexBunnyPoints, convexBunnyPointCount, convexBunnyPolygons ); } if ( show_aabb ) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB( g,aabb ); dVector3 bbpos; for ( int i=0; i<3; i++ ) bbpos[i] = 0.5*( aabb[i*2] + aabb[i*2+1] ); dVector3 bbsides; for ( int j=0; j<3; j++ ) bbsides[j] = aabb[j*2+1] - aabb[j*2]; dMatrix3 RI; dRSetIdentity( RI ); dsSetColorAlpha( 1,0,0,0.5 ); dsDrawBox( bbpos,RI,bbsides ); } } // simulation loop static void simLoop( int pause ) { dsSetColor( 0,0,2 ); dSpaceCollide( space,0,&nearCallback ); if ( !pause ) dWorldQuickStep( world,0.05 ); for ( int j = 0; j < dSpaceGetNumGeoms( space ); j++ ) { dSpaceGetGeom( space, j ); } // remove all contact joints dJointGroupEmpty( contactgroup ); dsSetColor( 1,1,0 ); dsSetTexture( DS_WOOD ); for ( int i=0; i #include #include "texturepath.h" #include "bunny_geom.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif //<---- Convex Object static const dReal planes[] = // planes for a cube { 1.0f ,0.0f ,0.0f ,0.25f, 0.0f ,1.0f ,0.0f ,0.25f, 0.0f ,0.0f ,1.0f ,0.25f, 0.0f ,0.0f ,-1.0f,0.25f, 0.0f ,-1.0f,0.0f ,0.25f, -1.0f,0.0f ,0.0f ,0.25f /* 1.0f ,0.0f ,0.0f ,2.0f, 0.0f ,1.0f ,0.0f ,1.0f, 0.0f ,0.0f ,1.0f ,1.0f, 0.0f ,0.0f ,-1.0f,1.0f, 0.0f ,-1.0f,0.0f ,1.0f, -1.0f,0.0f ,0.0f ,0.0f */ }; static const unsigned int planecount=6; static const dReal points[] = // points for a cube { 0.25f,0.25f,0.25f, -0.25f,0.25f,0.25f, 0.25f,-0.25f,0.25f, -0.25f,-0.25f,0.25f, 0.25f,0.25f,-0.25f, -0.25f,0.25f,-0.25f, 0.25f,-0.25f,-0.25f, -0.25f,-0.25f,-0.25f, }; static const unsigned int pointcount=8; static const unsigned int polygons[] = //Polygons for a cube (6 squares) { 4,0,2,6,4, // positive X 4,1,0,4,5, // positive Y 4,0,1,3,2, // positive Z 4,3,1,5,7, // negative X 4,2,3,7,6, // negative Y 4,5,4,6,7, // negative Z }; //----> Convex Object int tmTriangles[] = { 0,2,6, 0,6,4, 1,0,4, 1,4,5, 0,1,3, 0,3,2, 3,1,5, 3,5,7, 2,3,7, 2,7,6, 5,4,6, 5,6,7 }; float tmVertices[] = { 0.25f,0.25f,0.25f, // point 0 -0.25f,0.25f,0.25f, // point 1 0.25f,-0.25f,0.25f, // point 2 -0.25f,-0.25f,0.25f,// point 3 0.25f,0.25f,-0.25f, // point 4 -0.25f,0.25f,-0.25f,// point 5 0.25f,-0.25f,-0.25f,// point 6 -0.25f,-0.25f,-0.25f,// point 7 }; // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawLine dsDrawLineD #define dsDrawTriangle dsDrawTriangleD #define dsDrawConvex dsDrawConvexD #endif // some constants #define NUM 200 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 64 // maximum number of contact points per body // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body // Trimesh only - double buffered matrices for 'last transform' setup dReal matrix_dblbuff[ 16 * 2 ]; int last_matrix_index; }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? typedef dReal dVector3R[3]; dGeomID TriMesh1; dGeomID TriMesh2; static dTriMeshDataID TriData1, TriData2; // reusable static trimesh data // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command (int cmd) { int i,j,k; dReal sides[3]; dMass m; bool setBody = false; cmd = locase (cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'm' || cmd == 'y' || cmd == 'v') { if (num < NUM) { i = num; num++; } else { i = nextobj; nextobj++; if (nextobj >= num) nextobj = 0; // destroy the body and geoms for slot i dBodyDestroy (obj[i].body); for (k=0; k < GPB; k++) { if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]); } memset (&obj[i],0,sizeof(obj[i])); } obj[i].body = dBodyCreate (world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition (obj[i].body, dRandReal()*2-1,dRandReal()*2-1,dRandReal()+3); dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { dReal maxheight = 0; for (k=0; k maxheight) maxheight = pos[2]; } dBodySetPosition (obj[i].body, 0,0,maxheight+1); dRFromAxisAndAngle (R,0,0,1,dRandReal()*10.0-5.0); } dBodySetRotation (obj[i].body,R); dBodySetData (obj[i].body,(void*)(size_t)i); if (cmd == 'b') { dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]); } else if (cmd == 'v') { dMassSetBox (&m,DENSITY,0.25,0.25,0.25); obj[i].geom[0] = dCreateConvex(space, planes, planecount, points, pointcount, polygons); } else if (cmd == 'y') { sides[1] *= 0.5; dMassSetCylinder (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere (space,sides[0]); } else if (cmd == 'm') { dTriMeshDataID new_tmdata = dGeomTriMeshDataCreate(); dGeomTriMeshDataBuildSingle(new_tmdata, &Vertices[0], 3 * sizeof(float), VertexCount, (dTriIndex*)&Indices[0], IndexCount, 3 * sizeof(dTriIndex)); obj[i].geom[0] = dCreateTriMesh(space, new_tmdata, 0, 0, 0); // remember the mesh's dTriMeshDataID on its userdata for convenience. dGeomSetData(obj[i].geom[0], new_tmdata); dMassSetTrimesh( &m, DENSITY, obj[i].geom[0] ); printf("mass at %f %f %f\n", m.c[0], m.c[1], m.c[2]); dGeomSetPosition(obj[i].geom[0], -m.c[0], -m.c[1], -m.c[2]); dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]); } else if (cmd == 'x') { setBody = true; // start accumulating masses for the composite geometries dMass m2; dMassSetZero (&m); dReal dpos[GPB][3]; // delta-positions for composite geometries dMatrix3 drot[GPB]; // set random delta positions for (j=0; j= num) selected = 0; if (selected < 0) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable (obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable (obj[selected].body); } else if (cmd == 'a') { show_aabb ^= 1; } else if (cmd == 't') { show_contacts ^= 1; } else if (cmd == 'r') { random_pos ^= 1; } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { if (!g) return; if (!pos) pos = dGeomGetPosition (g); if (!R) R = dGeomGetRotation (g); int type = dGeomGetClass (g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths (g,sides); dsDrawBox (pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere (pos,R,dGeomSphereGetRadius (g)); } else if (type == dCapsuleClass) { dReal radius,length; dGeomCapsuleGetParams (g,&radius,&length); dsDrawCapsule (pos,R,length,radius); } else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams (g,&radius,&length); dsDrawCylinder (pos,R,length,radius); } else if (type == dConvexClass) { //dVector3 sides={0.50,0.50,0.50}; dsDrawConvex(pos,R,planes, planecount, points, pointcount, polygons); } if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB (g,aabb); dVector3 bbpos; for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (int j=0; j<3; j++) bbsides[j] = aabb[j*2+1] - aabb[j*2]; dMatrix3 RI; dRSetIdentity (RI); dsSetColorAlpha (1,0,0,0.5); dsDrawBox (bbpos,RI,bbsides); } } // set previous transformation matrix for trimesh void setCurrentTransform(dGeomID geom) { const dReal* Pos = dGeomGetPosition(geom); const dReal* Rot = dGeomGetRotation(geom); const dReal Transform[16] = { Rot[0], Rot[4], Rot[8], 0, Rot[1], Rot[5], Rot[9], 0, Rot[2], Rot[6], Rot[10], 0, Pos[0], Pos[1], Pos[2], 1 }; dGeomTriMeshSetLastTransform( geom, *(dMatrix4*)(&Transform) ); } // simulation loop static void simLoop (int pause) { dsSetColor (0,0,2); dSpaceCollide (space,0,&nearCallback); #if 1 // What is this for??? - Bram if (!pause) { for (int i=0; i #include #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif //**************************************************************************** // matrix accessors #define _A(i,j) A[(i)*4+(j)] #define _I(i,j) I[(i)*4+(j)] #define _R(i,j) R[(i)*4+(j)] //**************************************************************************** // tolerances #ifdef dDOUBLE const double tol = 1e-10; #endif #ifdef dSINGLE const double tol = 1e-5; #endif //**************************************************************************** // misc messages and error handling #ifdef __GNUC__ #define HEADER printf ("%s()\n", __FUNCTION__); #else #define HEADER printf ("%s:%d\n",__FILE__,__LINE__); #endif static jmp_buf jump_buffer; void myMessageFunction (int num, const char *msg, va_list ap) { printf ("(Message %d: ",num); vprintf (msg,ap); printf (")"); dSetMessageHandler (0); longjmp (jump_buffer,1); } #define TRAP_MESSAGE(do,ifnomsg,ifmsg) \ dSetMessageHandler (&myMessageFunction); \ if (setjmp (jump_buffer)) { \ dSetMessageHandler (0); \ ifmsg ; \ } \ else { \ dSetMessageHandler (&myMessageFunction); \ do ; \ ifnomsg ; \ } \ dSetMessageHandler (0); //**************************************************************************** // utility stuff // compare two numbers, within a threshhold, return 1 if approx equal int cmp (dReal a, dReal b) { return (fabs(a-b) < tol); } //**************************************************************************** // matrix utility stuff // compare a 3x3 matrix with the identity int cmpIdentityMat3 (dMatrix3 A) { return (cmp(_A(0,0),1.0) && cmp(_A(0,1),0.0) && cmp(_A(0,2),0.0) && cmp(_A(1,0),0.0) && cmp(_A(1,1),1.0) && cmp(_A(1,2),0.0) && cmp(_A(2,0),0.0) && cmp(_A(2,1),0.0) && cmp(_A(2,2),1.0)); } // transpose a 3x3 matrix in-line void transpose3x3 (dMatrix3 A) { dReal tmp; tmp=A[4]; A[4]=A[1]; A[1]=tmp; tmp=A[8]; A[8]=A[2]; A[2]=tmp; tmp=A[9]; A[9]=A[6]; A[6]=tmp; } //**************************************************************************** // test miscellaneous math functions void testRandomNumberGenerator() { HEADER; if (dTestRand()) printf ("\tpassed\n"); else printf ("\tFAILED\n"); } void testInfinity() { HEADER; if (1e10 < dInfinity && -1e10 > -dInfinity && -dInfinity < dInfinity) printf ("\tpassed\n"); else printf ("\tFAILED\n"); } void testPad() { HEADER; char s[100]; s[0]=0; for (int i=0; i<=16; i++) sprintf (s+strlen(s),"%d ",dPAD(i)); printf ("\t%s\n", strcmp(s,"0 1 4 4 4 8 8 8 8 12 12 12 12 16 16 16 16 ") ? "FAILED" : "passed"); } void testCrossProduct() { HEADER; dVector3 a1,a2,b,c; dMatrix3 B; dMakeRandomVector (b,3,1.0); dMakeRandomVector (c,3,1.0); dCalcVectorCross3(a1,b,c); dSetZero (B,12); dSetCrossMatrixPlus(B,b,4); dMultiply0 (a2,B,c,3,3,1); dReal diff = dMaxDifference(a1,a2,3,1); printf ("\t%s\n", diff > tol ? "FAILED" : "passed"); } void testSetZero() { HEADER; dReal a[100]; dMakeRandomVector (a,100,1.0); dSetZero (a,100); for (int i=0; i<100; i++) if (a[i] != 0.0) { printf ("\tFAILED\n"); return; } printf ("\tpassed\n"); } void testNormalize3() { HEADER; int i,j,bad=0; dVector3 n1,n2; for (i=0; i<1000; i++) { dMakeRandomVector (n1,3,1.0); for (j=0; j<3; j++) n2[j]=n1[j]; dNormalize3 (n2); if (dFabs(dCalcVectorDot3(n2,n2) - 1.0) > tol) bad |= 1; if (dFabs(n2[0]/n1[0] - n2[1]/n1[1]) > tol) bad |= 2; if (dFabs(n2[0]/n1[0] - n2[2]/n1[2]) > tol) bad |= 4; if (dFabs(n2[1]/n1[1] - n2[2]/n1[2]) > tol) bad |= 8; if (dFabs(dCalcVectorDot3(n2,n1) - dSqrt(dCalcVectorDot3(n1,n1))) > tol) bad |= 16; if (bad) { printf ("\tFAILED (code=%x)\n",bad); return; } } printf ("\tpassed\n"); } /* void testReorthonormalize() { HEADER; dMatrix3 R,I; dMakeRandomMatrix (R,3,3,1.0); for (int i=0; i<30; i++) dReorthonormalize (R); dMultiply2 (I,R,R,3,3,3); printf ("\t%s\n",cmpIdentityMat3 (I) ? "passed" : "FAILED"); } */ void testPlaneSpace() { HEADER; dVector3 n,p,q; int bad = 0; for (int i=0; i<1000; i++) { dMakeRandomVector (n,3,1.0); dNormalize3 (n); dPlaneSpace (n,p,q); if (fabs(dCalcVectorDot3(n,p)) > tol) bad = 1; if (fabs(dCalcVectorDot3(n,q)) > tol) bad = 1; if (fabs(dCalcVectorDot3(p,q)) > tol) bad = 1; if (fabs(dCalcVectorDot3(p,p)-1) > tol) bad = 1; if (fabs(dCalcVectorDot3(q,q)-1) > tol) bad = 1; } printf ("\t%s\n", bad ? "FAILED" : "passed"); } //**************************************************************************** // test matrix functions #define MSIZE 21 #define MSIZE4 24 // MSIZE rounded up to 4 void testMatrixMultiply() { // A is 2x3, B is 3x4, B2 is B except stored columnwise, C is 2x4 dReal A[8],B[12],A2[12],B2[16],C[8]; int i; HEADER; dSetZero (A,8); for (i=0; i<3; i++) A[i] = i+2; for (i=0; i<3; i++) A[i+4] = i+3+2; for (i=0; i<12; i++) B[i] = i+8; dSetZero (A2,12); for (i=0; i<6; i++) A2[i+2*(i/2)] = A[i+i/3]; dSetZero (B2,16); for (i=0; i<12; i++) B2[i+i/3] = B[i]; dMultiply0 (C,A,B,2,3,4); if (C[0] != 116 || C[1] != 125 || C[2] != 134 || C[3] != 143 || C[4] != 224 || C[5] != 242 || C[6] != 260 || C[7] != 278) printf ("\tFAILED (1)\n"); else printf ("\tpassed (1)\n"); dMultiply1 (C,A2,B,2,3,4); if (C[0] != 160 || C[1] != 172 || C[2] != 184 || C[3] != 196 || C[4] != 196 || C[5] != 211 || C[6] != 226 || C[7] != 241) printf ("\tFAILED (2)\n"); else printf ("\tpassed (2)\n"); dMultiply2 (C,A,B2,2,3,4); if (C[0] != 83 || C[1] != 110 || C[2] != 137 || C[3] != 164 || C[4] != 164 || C[5] != 218 || C[6] != 272 || C[7] != 326) printf ("\tFAILED (3)\n"); else printf ("\tpassed (3)\n"); } void testSmallMatrixMultiply() { dMatrix3 A,B,C,A2; dVector3 a,a2,x; HEADER; dMakeRandomMatrix (A,3,3,1.0); dMakeRandomMatrix (B,3,3,1.0); dMakeRandomMatrix (C,3,3,1.0); dMakeRandomMatrix (x,3,1,1.0); // dMultiply0_331() dMultiply0_331 (a,B,x); dMultiply0 (a2,B,x,3,3,1); printf ("\t%s (1)\n",(dMaxDifference (a,a2,3,1) > tol) ? "FAILED" : "passed"); // dMultiply1_331() dMultiply1_331 (a,B,x); dMultiply1 (a2,B,x,3,3,1); printf ("\t%s (2)\n",(dMaxDifference (a,a2,3,1) > tol) ? "FAILED" : "passed"); // dMultiply0_133 dMultiply0_133 (a,x,B); dMultiply0 (a2,x,B,1,3,3); printf ("\t%s (3)\n",(dMaxDifference (a,a2,1,3) > tol) ? "FAILED" : "passed"); // dMultiply0_333() dMultiply0_333 (A,B,C); dMultiply0 (A2,B,C,3,3,3); printf ("\t%s (4)\n",(dMaxDifference (A,A2,3,3) > tol) ? "FAILED" : "passed"); // dMultiply1_333() dMultiply1_333 (A,B,C); dMultiply1 (A2,B,C,3,3,3); printf ("\t%s (5)\n",(dMaxDifference (A,A2,3,3) > tol) ? "FAILED" : "passed"); // dMultiply2_333() dMultiply2_333 (A,B,C); dMultiply2 (A2,B,C,3,3,3); printf ("\t%s (6)\n",(dMaxDifference (A,A2,3,3) > tol) ? "FAILED" : "passed"); } void testCholeskyFactorization() { dReal A[MSIZE4*MSIZE], B[MSIZE4*MSIZE], C[MSIZE4*MSIZE], diff; HEADER; dMakeRandomMatrix (A,MSIZE,MSIZE,1.0); dMultiply2 (B,A,A,MSIZE,MSIZE,MSIZE); memcpy (A,B,MSIZE4*MSIZE*sizeof(dReal)); if (dFactorCholesky (B,MSIZE)) printf ("\tpassed (1)\n"); else printf ("\tFAILED (1)\n"); dClearUpperTriangle (B,MSIZE); dMultiply2 (C,B,B,MSIZE,MSIZE,MSIZE); diff = dMaxDifference(A,C,MSIZE,MSIZE); printf ("\tmaximum difference = %.6e - %s (2)\n",diff, diff > tol ? "FAILED" : "passed"); } void testCholeskySolve() { dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], b[MSIZE],x[MSIZE],btest[MSIZE],diff; HEADER; // get A,L = PD matrix dMakeRandomMatrix (A,MSIZE,MSIZE,1.0); dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE); memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal)); // get b,x = right hand side dMakeRandomMatrix (b,MSIZE,1,1.0); memcpy (x,b,MSIZE*sizeof(dReal)); // factor L if (dFactorCholesky (L,MSIZE)) printf ("\tpassed (1)\n"); else printf ("\tFAILED (1)\n"); dClearUpperTriangle (L,MSIZE); // solve A*x = b dSolveCholesky (L,x,MSIZE); // compute A*x and compare it with b dMultiply2 (btest,A,x,MSIZE,MSIZE,1); diff = dMaxDifference(b,btest,MSIZE,1); printf ("\tmaximum difference = %.6e - %s (2)\n",diff, diff > tol ? "FAILED" : "passed"); } void testInvertPDMatrix() { int i,j,ok; dReal A[MSIZE4*MSIZE], Ainv[MSIZE4*MSIZE], I[MSIZE4*MSIZE]; HEADER; dMakeRandomMatrix (A,MSIZE,MSIZE,1.0); dMultiply2 (Ainv,A,A,MSIZE,MSIZE,MSIZE); memcpy (A,Ainv,MSIZE4*MSIZE*sizeof(dReal)); dSetZero (Ainv,MSIZE4*MSIZE); if (dInvertPDMatrix (A,Ainv,MSIZE)) printf ("\tpassed (1)\n"); else printf ("\tFAILED (1)\n"); dMultiply0 (I,A,Ainv,MSIZE,MSIZE,MSIZE); // compare with identity ok = 1; for (i=0; i tol ? "FAILED" : "passed"); } void testSolveLDLT() { dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], d[MSIZE], x[MSIZE], b[MSIZE], btest[MSIZE], diff; HEADER; dMakeRandomMatrix (A,MSIZE,MSIZE,1.0); dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE); memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal)); dMakeRandomMatrix (b,MSIZE,1,1.0); memcpy (x,b,MSIZE*sizeof(dReal)); dFactorLDLT (L,d,MSIZE,MSIZE4); dSolveLDLT (L,d,x,MSIZE,MSIZE4); dMultiply2 (btest,A,x,MSIZE,MSIZE,1); diff = dMaxDifference(b,btest,MSIZE,1); printf ("\tmaximum difference = %.6e - %s\n",diff, diff > tol ? "FAILED" : "passed"); } void testLDLTAddTL() { int i,j; dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], d[MSIZE], a[MSIZE], DL[MSIZE4*MSIZE], ATEST[MSIZE4*MSIZE], diff; HEADER; dMakeRandomMatrix (A,MSIZE,MSIZE,1.0); dMultiply2 (L,A,A,MSIZE,MSIZE,MSIZE); memcpy (A,L,MSIZE4*MSIZE*sizeof(dReal)); dFactorLDLT (L,d,MSIZE,MSIZE4); // delete first row and column of factorization for (i=0; i tol ? "FAILED" : "passed"); } void testLDLTRemove() { int i,j,r,p[MSIZE]; dReal A[MSIZE4*MSIZE], L[MSIZE4*MSIZE], d[MSIZE], L2[MSIZE4*MSIZE], d2[MSIZE], DL2[MSIZE4*MSIZE], Atest1[MSIZE4*MSIZE], Atest2[MSIZE4*MSIZE], diff, maxdiff; HEADER; // make array of A row pointers dReal *Arows[MSIZE]; for (i=0; i= r) ii--; if (jj >= r) jj--; if (A[i*MSIZE4+j] != Atest1[ii*MSIZE4+jj]) bad = 1; } } } if (bad) printf ("\trow/col removal FAILED for row %d\n",r); // zero out last row/column of Atest1 for (i=0; i tol ? "FAILED" : "passed"); } //**************************************************************************** // test mass stuff #define NUMP 10 // number of particles void printMassParams (dMass *m) { printf ("mass = %.4f\n",m->mass); printf ("com = (%.4f,%.4f,%.4f)\n",m->c[0],m->c[1],m->c[2]); printf ("I = [ %10.4f %10.4f %10.4f ]\n" " [ %10.4f %10.4f %10.4f ]\n" " [ %10.4f %10.4f %10.4f ]\n", m->_I(0,0),m->_I(0,1),m->_I(0,2), m->_I(1,0),m->_I(1,1),m->_I(1,2), m->_I(2,0),m->_I(2,1),m->_I(2,2)); } void compareMassParams (dMass *m1, dMass *m2, const char *msg) { int i,j,ok = 1; if (!(cmp(m1->mass,m2->mass) && cmp(m1->c[0],m2->c[0]) && cmp(m1->c[1],m2->c[1]) && cmp(m1->c[2],m2->c[2]))) ok = 0; for (i=0; i<3; i++) for (j=0; j<3; j++) if (cmp (m1->_I(i,j),m2->_I(i,j))==0) ok = 0; if (ok) printf ("\tpassed (%s)\n",msg); else printf ("\tFAILED (%s)\n",msg); } // compute the mass parameters of a particle set void computeMassParams (dMass *m, dReal q[NUMP][3], dReal pm[NUMP]) { int i,j; dMassSetZero (m); for (i=0; imass += pm[i]; for (j=0; j<3; j++) m->c[j] += pm[i]*q[i][j]; m->_I(0,0) += pm[i]*(q[i][1]*q[i][1] + q[i][2]*q[i][2]); m->_I(1,1) += pm[i]*(q[i][0]*q[i][0] + q[i][2]*q[i][2]); m->_I(2,2) += pm[i]*(q[i][0]*q[i][0] + q[i][1]*q[i][1]); m->_I(0,1) -= pm[i]*(q[i][0]*q[i][1]); m->_I(0,2) -= pm[i]*(q[i][0]*q[i][2]); m->_I(1,2) -= pm[i]*(q[i][1]*q[i][2]); } for (j=0; j<3; j++) m->c[j] /= m->mass; m->_I(1,0) = m->_I(0,1); m->_I(2,0) = m->_I(0,2); m->_I(2,1) = m->_I(1,2); } void testMassFunctions() { dMass m; int i,j; dReal q[NUMP][3]; // particle positions dReal pm[NUMP]; // particle masses dMass m1,m2; dMatrix3 R; HEADER; printf ("\t"); dMassSetZero (&m); TRAP_MESSAGE (dMassSetParameters (&m,10, 0,0,0, 1,2,3, 4,5,6), printf (" FAILED (1)\n"), printf (" passed (1)\n")); printf ("\t"); dMassSetZero (&m); TRAP_MESSAGE (dMassSetParameters (&m,10, 0.1,0.2,0.15, 3,5,14, 3.1,3.2,4), printf ("passed (2)\n") , printf (" FAILED (2)\n")); if (m.mass==10 && m.c[0]==REAL(0.1) && m.c[1]==REAL(0.2) && m.c[2]==REAL(0.15) && m._I(0,0)==3 && m._I(1,1)==5 && m._I(2,2)==14 && m._I(0,1)==REAL(3.1) && m._I(0,2)==REAL(3.2) && m._I(1,2)==4 && m._I(1,0)==REAL(3.1) && m._I(2,0)==REAL(3.2) && m._I(2,1)==4) printf ("\tpassed (3)\n"); else printf ("\tFAILED (3)\n"); dMassSetZero (&m); dMassSetSphere (&m,1.4, 0.86); if (cmp(m.mass,3.73002719949386) && m.c[0]==0 && m.c[1]==0 && m.c[2]==0 && cmp(m._I(0,0),1.10349124669826) && cmp(m._I(1,1),1.10349124669826) && cmp(m._I(2,2),1.10349124669826) && m._I(0,1)==0 && m._I(0,2)==0 && m._I(1,2)==0 && m._I(1,0)==0 && m._I(2,0)==0 && m._I(2,1)==0) printf ("\tpassed (4)\n"); else printf ("\tFAILED (4)\n"); dMassSetZero (&m); dMassSetCapsule (&m,1.3,1,0.76,1.53); if (cmp(m.mass,5.99961928996029) && m.c[0]==0 && m.c[1]==0 && m.c[2]==0 && cmp(m._I(0,0),1.59461986077384) && cmp(m._I(1,1),4.21878433864904) && cmp(m._I(2,2),4.21878433864904) && m._I(0,1)==0 && m._I(0,2)==0 && m._I(1,2)==0 && m._I(1,0)==0 && m._I(2,0)==0 && m._I(2,1)==0) printf ("\tpassed (5)\n"); else printf ("\tFAILED (5)\n"); dMassSetZero (&m); dMassSetBox (&m,0.27,3,4,5); if (cmp(m.mass,16.2) && m.c[0]==0 && m.c[1]==0 && m.c[2]==0 && cmp(m._I(0,0),55.35) && cmp(m._I(1,1),45.9) && cmp(m._I(2,2),33.75) && m._I(0,1)==0 && m._I(0,2)==0 && m._I(1,2)==0 && m._I(1,0)==0 && m._I(2,0)==0 && m._I(2,1)==0) printf ("\tpassed (6)\n"); else printf ("\tFAILED (6)\n"); // test dMassAdjust? // make random particles and compute the mass, COM and inertia, then // translate and repeat. for (i=0; i Q -> R works dReal maxdiff=0; for (i=0; i<100; i++) { makeRandomRotation (R); dRtoQ (R,q); dQtoR (q,R2); dReal diff = dMaxDifference (R,R2,3,3); if (diff > maxdiff) maxdiff = diff; } printf ("\tmaximum difference = %e - %s (3)\n",maxdiff, (maxdiff > tol) ? "FAILED" : "passed"); } void testQuaternionMultiply() { HEADER; dMatrix3 RA,RB,RC,Rtest; dQuaternion qa,qb,qc; dReal diff,maxdiff=0; for (int i=0; i<100; i++) { makeRandomRotation (RB); makeRandomRotation (RC); dRtoQ (RB,qb); dRtoQ (RC,qc); dMultiply0 (RA,RB,RC,3,3,3); dQMultiply0 (qa,qb,qc); dQtoR (qa,Rtest); diff = dMaxDifference (Rtest,RA,3,3); if (diff > maxdiff) maxdiff = diff; dMultiply1 (RA,RB,RC,3,3,3); dQMultiply1 (qa,qb,qc); dQtoR (qa,Rtest); diff = dMaxDifference (Rtest,RA,3,3); if (diff > maxdiff) maxdiff = diff; dMultiply2 (RA,RB,RC,3,3,3); dQMultiply2 (qa,qb,qc); dQtoR (qa,Rtest); diff = dMaxDifference (Rtest,RA,3,3); if (diff > maxdiff) maxdiff = diff; dMultiply0 (RA,RC,RB,3,3,3); transpose3x3 (RA); dQMultiply3 (qa,qb,qc); dQtoR (qa,Rtest); diff = dMaxDifference (Rtest,RA,3,3); if (diff > maxdiff) maxdiff = diff; } printf ("\tmaximum difference = %e - %s\n",maxdiff, (maxdiff > tol) ? "FAILED" : "passed"); } void testRotationFunctions() { dMatrix3 R1; HEADER; printf ("\tdRSetIdentity - "); dMakeRandomMatrix (R1,3,3,1.0); dRSetIdentity (R1); if (cmpIdentityMat3(R1)) printf ("passed\n"); else printf ("FAILED\n"); printf ("\tdRFromAxisAndAngle - "); printf ("\n"); printf ("\tdRFromEulerAngles - "); printf ("\n"); printf ("\tdRFrom2Axes - "); printf ("\n"); } //**************************************************************************** #include template class simplevector { private: int n; int max; T* data; public: simplevector() { initialize(); } ~simplevector() { finalize(); } T& operator[](int i) { assert(i>=0 && i=0 && i mat; int afterfirst,index; public: dMatrixComparison(); ~dMatrixComparison(); dReal nextMatrix (dReal *A, int n, int m, int lower_tri, const char *name, ...); // add a new n*m matrix A to the sequence. the name of the matrix is given // by the printf-style arguments (name,...). if this is the first sequence // then this object will simply record the matrices and return 0. // if this the second or subsequent sequence then this object will compare // the matrices with the first sequence, and report any differences. // the matrix error will be returned. if `lower_tri' is 1 then only the // lower triangle of the matrix (including the diagonal) will be compared // (the matrix must be square). void end(); // end a sequence. void reset(); // restarts the object, so the next sequence will be the first sequence. void dump(); // print out info about all the matrices in the sequence }; struct dMatrixComparison::dMatInfo { int n,m; // size of matrix char name[128]; // name of the matrix dReal *data; // matrix data int size; // size of `data' }; dMatrixComparison::dMatrixComparison() { afterfirst = 0; index = 0; } dMatrixComparison::~dMatrixComparison() { reset(); } dReal dMatrixComparison::nextMatrix (dReal *A, int n, int m, int lower_tri, const char *name, ...) { if (A==0 || n < 1 || m < 1 || name==0) dDebug (0,"bad args to nextMatrix"); int num = n*dPAD(m); if (afterfirst==0) { dMatInfo *mi = (dMatInfo*) dAlloc (sizeof(dMatInfo)); mi->n = n; mi->m = m; mi->size = num * sizeof(dReal); mi->data = (dReal*) dAlloc (mi->size); memcpy (mi->data,A,mi->size); va_list ap; va_start (ap,name); vsprintf (mi->name,name,ap); va_end (ap); if (strlen(mi->name) >= sizeof (mi->name)) dDebug (0,"name too long"); mat.push_back(mi); return 0; } else { if (lower_tri && n != m) dDebug (0,"dMatrixComparison, lower triangular matrix must be square"); if (index >= mat.size()) dDebug (0,"dMatrixComparison, too many matrices"); dMatInfo *mp = mat[index]; index++; dMatInfo mi; va_list ap; va_start (ap,name); vsprintf (mi.name,name,ap); va_end (ap); if (strlen(mi.name) >= sizeof (mi.name)) dDebug (0,"name too long"); if (strcmp(mp->name,mi.name) != 0) dDebug (0,"dMatrixComparison, name mismatch (\"%s\" and \"%s\")", mp->name,mi.name); if (mp->n != n || mp->m != m) dDebug (0,"dMatrixComparison, size mismatch (%dx%d and %dx%d)", mp->n,mp->m,n,m); dReal maxdiff; if (lower_tri) { maxdiff = dMaxDifferenceLowerTriangle (A,mp->data,n); } else { maxdiff = dMaxDifference (A,mp->data,n,m); } if (maxdiff > tol) dDebug (0,"dMatrixComparison, matrix error (size=%dx%d, name=\"%s\", " "error=%.4e)",n,m,mi.name,maxdiff); return maxdiff; } } void dMatrixComparison::end() { if (mat.size() <= 0) dDebug (0,"no matrices in sequence"); afterfirst = 1; index = 0; } void dMatrixComparison::reset() { for (int i=0; idata,mat[i]->size); dFree (mat[i],sizeof(dMatInfo)); } mat.clear(); afterfirst = 0; index = 0; } void dMatrixComparison::dump() { for (int i=0; iname,mat[i]->n,mat[i]->m); } //**************************************************************************** // unit test #include // static jmp_buf jump_buffer; static void myDebug (int /*num*/, const char */*msg*/, va_list /*ap*/) { // printf ("(Error %d: ",num); // vprintf (msg,ap); // printf (")\n"); longjmp (jump_buffer,1); } extern "C" void dTestMatrixComparison() { volatile int i; printf ("dTestMatrixComparison()\n"); dMessageFunction *orig_debug = dGetDebugHandler(); dMatrixComparison mc; dReal A[50*50]; // make first sequence unsigned long seed = dRandGetSeed(); for (i=1; i<49; i++) { dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"A%d",i); } mc.end(); //mc.dump(); // test identical sequence dSetDebugHandler (&myDebug); dRandSetSeed (seed); if (setjmp (jump_buffer)) { printf ("\tFAILED (1)\n"); } else { for (i=1; i<49; i++) { dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"A%d",i); } mc.end(); printf ("\tpassed (1)\n"); } dSetDebugHandler (orig_debug); // test broken sequences (with matrix error) dRandSetSeed (seed); volatile int passcount = 0; for (i=1; i<49; i++) { if (setjmp (jump_buffer)) { passcount++; } else { dSetDebugHandler (&myDebug); dMakeRandomMatrix (A,i,i+1,1.0); A[(i-1)*dPAD(i+1)+i] += REAL(0.01); mc.nextMatrix (A,i,i+1,0,"A%d",i); dSetDebugHandler (orig_debug); } } mc.end(); printf ("\t%s (2)\n",(passcount == 48) ? "passed" : "FAILED"); // test broken sequences (with name error) dRandSetSeed (seed); passcount = 0; for (i=1; i<49; i++) { if (setjmp (jump_buffer)) { passcount++; } else { dSetDebugHandler (&myDebug); dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"B%d",i); dSetDebugHandler (orig_debug); } } mc.end(); printf ("\t%s (3)\n",(passcount == 48) ? "passed" : "FAILED"); // test identical sequence again dSetDebugHandler (&myDebug); dRandSetSeed (seed); if (setjmp (jump_buffer)) { printf ("\tFAILED (4)\n"); } else { for (i=1; i<49; i++) { dMakeRandomMatrix (A,i,i+1,1.0); mc.nextMatrix (A,i,i+1,0,"A%d",i); } mc.end(); printf ("\tpassed (4)\n"); } dSetDebugHandler (orig_debug); } //**************************************************************************** // internal unit tests extern "C" void dTestDataStructures(); extern "C" void dTestMatrixComparison(); extern "C" int dTestSolveLCP(); int main() { dInitODE(); testRandomNumberGenerator(); testInfinity(); testPad(); testCrossProduct(); testSetZero(); testNormalize3(); //testReorthonormalize(); ... not any more testPlaneSpace(); testMatrixMultiply(); testSmallMatrixMultiply(); testCholeskyFactorization(); testCholeskySolve(); testInvertPDMatrix(); testIsPositiveDefinite(); testFastLDLTFactorization(); testSolveLDLT(); testLDLTAddTL(); testLDLTRemove(); testMassFunctions(); testRtoQandQtoR(); testQuaternionMultiply(); testRotationFunctions(); dTestMatrixComparison(); dTestSolveLCP(); // dTestDataStructures(); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_piston.cpp0000644000000000000000000005545212635011627015440 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * * Created by: Remi Ricard * * (remi.ricard@simlog.com or papaDoc@videotron.ca) * * Creation date: 2007/05/04 * *************************************************************************/ /* This program demonstrates how the Piston joint works. A Piston joint enables the sliding of a body with respect to another body and the 2 bodies are free to rotate about the sliding axis. - The yellow body is fixed to the world. - The yellow body and the blue body are attached by a Piston joint with the axis along the x direction. - The purple object is a geometry obstacle. - The red line is the representation of the prismatic axis - The orange line is the representation of the rotoide axis - The light blue ball is the anchor position N.B. Many command options are available type -h to print them. */ #include #include #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawSphere dsDrawSphereD #endif const dReal VEL_INC = 0.01; // Velocity increment // physics parameters const dReal PI = 3.14159265358979323846264338327950288419716939937510; const dReal BODY1_LENGTH = 1.5; // Size along the X axis const dReal RADIUS = 0.2; const dReal AXIS_RADIUS = 0.01; #define X 0 #define Y 1 #define Z 2 enum INDEX { BODY1 = 0, BODY2, RECT, BOX, OBS, GROUND, NUM_PARTS, ALL = NUM_PARTS }; const int catBits[NUM_PARTS+1] = { 0x0001, ///< Ext Cylinder category 0x0002, ///< Int Cylinder category 0x0004, ///< Int_Rect Cylinder category 0x0008, ///< Box category 0x0010, ///< Obstacle category 0x0020, ///< Ground category ~0L ///< All categories }; #define Mass1 10 #define Mass2 8 //camera view static float xyz[3] = {2.0f,-3.5f,2.0000f}; static float hpr[3] = {90.000f,-25.5000f,0.0000f}; //world,space,body & geom static dWorldID world; static dSpaceID space; static dJointGroupID contactgroup; static dBodyID body[NUM_PARTS]; static dGeomID geom[NUM_PARTS]; // Default Positions and anchor of the 2 bodies dVector3 pos1; dVector3 pos2; dVector3 anchor; static dJoint *joint; const dReal BODY2_SIDES[3] = {0.4, 0.4, 0.4}; const dReal OBS_SIDES[3] = {1,1,1}; const dReal RECT_SIDES[3] = {0.3, 0.1, 0.2}; int type = dJointTypePiston; //#pragma message("tc to be changed to 0") int tc = 0; // The test case choice; //collision detection static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i,n; dBodyID b1 = dGeomGetBody (o1); dBodyID b2 = dGeomGetBody (o2); if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact) ) return; const int N = 10; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof (dContact) ); if (n > 0) { for (i=0; iattach (body[BODY1], body[BODY2]); if (joint->getType() == dJointTypePiston) dJointSetPistonAnchor(joint->id(), anchor[X], anchor[Y], anchor[Z]); } } // function to update camera position at each step. void update() { // static FILE *file = fopen("x:/sim/src/libode/tstsrcSF/export.dat", "w"); // static int cnt = 0; // char str[24]; // sprintf(str, "%06d",cnt++); // dWorldExportDIF(world, file, str); } // called when a key pressed static void command (int cmd) { switch (cmd) { case 'h' : case 'H' : case '?' : printKeyBoardShortCut(); break; // Force case 'q' : case 'Q' : dBodyAddForce (body[BODY1],4,0,0); break; case 'w' : case 'W' : dBodyAddForce (body[BODY1],-4,0,0); break; case 'a' : case 'A' : dBodyAddForce (body[BODY1],0,40,0); break; case 's' : case 'S' : dBodyAddForce (body[BODY1],0,-40,0); break; case 'z' : case 'Z' : dBodyAddForce (body[BODY1],0,0,4); break; case 'x' : case 'X' : dBodyAddForce (body[BODY1],0,0,-4); break; // Torque case 'e': case 'E': dBodyAddTorque (body[BODY1],0.1,0,0); break; case 'r': case 'R': dBodyAddTorque (body[BODY1],-0.1,0,0); break; case 'd': case 'D': dBodyAddTorque (body[BODY1],0, 0.1,0); break; case 'f': case 'F': dBodyAddTorque (body[BODY1],0,-0.1,0); break; case 'c': case 'C': dBodyAddTorque (body[BODY1],0.1,0,0); break; case 'v': case 'V': dBodyAddTorque (body[BODY1],-0.1,0,0); break; case 't': case 'T': if (joint->getType() == dJointTypePiston) dJointAddPistonForce (joint->id(),1); else dJointAddSliderForce (joint->id(),1); break; case 'y': case 'Y': if (joint->getType() == dJointTypePiston) dJointAddPistonForce (joint->id(),-1); else dJointAddSliderForce (joint->id(),-1); break; case '8' : dJointAttach(joint->id(), body[0], 0); break; case '9' : dJointAttach(joint->id(), 0, body[0]); break; case 'i': case 'I' : joint->setParam (dParamLoStop, 0); joint->setParam (dParamHiStop, 0); break; case 'o': case 'O' : joint->setParam (dParamLoStop2, 0); joint->setParam (dParamHiStop2, 0); break; case 'k': case 'K': joint->setParam (dParamLoStop2, -45.0*3.14159267/180.0); joint->setParam (dParamHiStop2, 45.0*3.14159267/180.0); break; case 'l': case 'L': joint->setParam (dParamLoStop2, -dInfinity); joint->setParam (dParamHiStop2, dInfinity); break; // Velocity of joint case ',': case '<' : { dReal vel = joint->getParam (dParamVel) - VEL_INC; joint->setParam (dParamVel, vel); std::cout<<"Velocity = "<' : { dReal vel = joint->getParam (dParamVel) + VEL_INC; joint->setParam (dParamVel, vel); std::cout<<"Velocity = "<getType() ) { case dJointTypeSlider : { dSliderJoint *sj = reinterpret_cast (joint); std::cout<<"Position ="<getPosition() <<"\n"; } break; case dJointTypePiston : { dPistonJoint *rj = reinterpret_cast (joint); std::cout<<"Position ="<getPosition() <<"\n"; } break; default: {} // keep the compiler happy } } break; case '+' : (++tc) %= 4; setPositionBodies (tc); break; case '-' : (--tc) %= 4; setPositionBodies (tc); break; } } static void drawBox (dGeomID id, int R, int G, int B) { if (!id) return; const dReal *pos = dGeomGetPosition (id); const dReal *rot = dGeomGetRotation (id); dsSetColor (R,G,B); dVector3 l; dGeomBoxGetLengths (id, l); dsDrawBox (pos, rot, l); } // simulation loop static void simLoop (int pause) { const dReal *rot; dVector3 ax; dReal l=0; switch (joint->getType() ) { case dJointTypeSlider : ( (dSliderJoint *) joint)->getAxis (ax); l = ( (dSliderJoint *) joint)->getPosition(); break; case dJointTypePiston : ( (dPistonJoint *) joint)->getAxis (ax); l = ( (dPistonJoint *) joint)->getPosition(); break; default: {} // keep the compiler happy } if (!pause) { double simstep = 0.01; // 1ms simulation steps double dt = dsElapsedTime(); int nrofsteps = (int) ceilf (dt/simstep); if (!nrofsteps) nrofsteps = 1; for (int i=0; igetType() == dJointTypePiston ) { dVector3 anchor; dJointGetPistonAnchor(joint->id(), anchor); // Draw the rotoide axis rot = dGeomGetRotation (geom[BODY2]); dsSetColor (1,0.5,0); dsDrawCylinder (anchor, rot, 4, AXIS_RADIUS); dsSetColor (0,1,1); rot = dGeomGetRotation (geom[BODY1]); dsDrawSphere (anchor, rot, 1.5*RADIUS); } } } void Help (char **argv) { printf ("%s ", argv[0]); printf (" -h | --help : print this help\n"); printf (" -s | --slider : Set the joint as a slider\n"); printf (" -p | --piston : Set the joint as a Piston. (Default joint)\n"); printf (" -1 | --offset1 : Create an offset between the 2 bodies\n"); printf (" Offset one of the body by z=-0.5 and keep the anchor\n"); printf (" point in the middle of the fixed body\n"); printf (" -2 | --offset2 : Create an offset between the 2 bodies\n"); printf (" Offset one of the body by z=-0.5 and set the anchor\n"); printf (" point in the middle of the movable body\n"); printf (" -3 | --offset3 : Create an offset between the 2 bodies\n"); printf (" Offset one of the body by z=-0.5 and set the anchor\n"); printf (" point in the middle of the 2 bodies\n"); printf (" -t | --texture-path path : Path to the texture.\n"); printf (" Default = %s\n", DRAWSTUFF_TEXTURE_PATH); printf (" -n | --notFixed : In free space with no gravity mode"); printf ("-notex : Don't use texture\n"); printf ("-noshadow : No shadow\n"); printf ("-noshadows : No shadows\n"); printf ("-pause : Initial pause\n"); printf ("--------------------------------------------------\n"); printf ("Hit any key to continue:"); getchar(); exit (0); } int main (int argc, char **argv) { dInitODE2(0); bool fixed = true; // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; dVector3 offset; dSetZero (offset, 4); // Default test case if (argc >= 2 ) { for (int i=1; i < argc; ++i) { //static int tata = 0; if (1) { if ( 0 == strcmp ("-h", argv[i]) || 0 == strcmp ("--help", argv[i]) ) Help (argv); if ( 0 == strcmp ("-s", argv[i]) || 0 == strcmp ("--slider", argv[i]) ) type = dJointTypeSlider; if ( 0 == strcmp ("-t", argv[i]) || 0 == strcmp ("--texture-path", argv[i]) ) { int j = i+1; if ( j+1 > argc || // Check if we have enough arguments argv[j] == '\0' || // We should have a path here argv[j][0] == '-' ) // We should have a path not a command line Help (argv); else fn.path_to_textures = argv[++i]; // Increase i since we use this argument } } if ( 0 == strcmp ("-1", argv[i]) || 0 == strcmp ("--offset1", argv[i]) ) tc = 1; if ( 0 == strcmp ("-2", argv[i]) || 0 == strcmp ("--offset2", argv[i]) ) tc = 2; if ( 0 == strcmp ("-3", argv[i]) || 0 == strcmp ("--offset3", argv[i]) ) tc = 3; if (0 == strcmp ("-n", argv[i]) || 0 == strcmp ("--notFixed", argv[i]) ) fixed = false; } } world = dWorldCreate(); dWorldSetERP (world, 0.8); space = dSimpleSpaceCreate (0); contactgroup = dJointGroupCreate (0); geom[GROUND] = dCreatePlane (space, 0,0,1,0); dGeomSetCategoryBits (geom[GROUND], catBits[GROUND]); dGeomSetCollideBits (geom[GROUND], catBits[ALL]); dMass m; dMatrix3 R; // Create the Obstacle geom[OBS] = dCreateBox (space, OBS_SIDES[0], OBS_SIDES[1], OBS_SIDES[2]); dGeomSetCategoryBits (geom[OBS], catBits[OBS]); dGeomSetCollideBits (geom[OBS], catBits[ALL]); //Rotation of 45deg around y dRFromAxisAndAngle (R, 1,1,0, -0.25*PI); dGeomSetRotation (geom[OBS], R); dGeomSetPosition (geom[OBS], 1.95, -0.2, 0.5); //Rotation of 90deg around y // Will orient the Z axis along X dRFromAxisAndAngle (R, 0,1,0, -0.5*PI); // Create Body2 (Wiil be attached to the world) body[BODY2] = dBodyCreate (world); // Main axis of cylinder is along X=1 dMassSetBox (&m, 1, BODY2_SIDES[0], BODY2_SIDES[1], BODY2_SIDES[2]); dMassAdjust (&m, Mass1); geom[BODY2] = dCreateBox (space, BODY2_SIDES[0], BODY2_SIDES[1], BODY2_SIDES[2]); dGeomSetBody (geom[BODY2], body[BODY2]); dGeomSetOffsetRotation (geom[BODY2], R); dGeomSetCategoryBits (geom[BODY2], catBits[BODY2]); dGeomSetCollideBits (geom[BODY2], catBits[ALL] & (~catBits[BODY1]) ); dBodySetMass (body[BODY2], &m); // Create Body 1 (Slider on the prismatic axis) body[BODY1] = dBodyCreate (world); // Main axis of capsule is along X=1 dMassSetCapsule (&m, 1, 1, RADIUS, BODY1_LENGTH); dMassAdjust (&m, Mass1); geom[BODY1] = dCreateCapsule (space, RADIUS, BODY1_LENGTH); dGeomSetBody (geom[BODY1], body[BODY1]); dGeomSetOffsetRotation (geom[BODY1], R); dGeomSetCategoryBits (geom[BODY1], catBits[BODY1]); dGeomSetCollideBits (geom[BODY1], catBits[ALL] & ~catBits[BODY2] & ~catBits[RECT]); dMass mRect; dMassSetBox (&mRect, 1, RECT_SIDES[0], RECT_SIDES[1], RECT_SIDES[2]); dMassAdd (&m, &mRect); // TODO: translate m? geom[RECT] = dCreateBox (space, RECT_SIDES[0], RECT_SIDES[1], RECT_SIDES[2]); dGeomSetBody (geom[RECT], body[BODY1]); dGeomSetOffsetPosition (geom[RECT], (BODY1_LENGTH-RECT_SIDES[0]) /2.0, 0.0, -RADIUS -RECT_SIDES[2]/2.0); dGeomSetCategoryBits (geom[RECT], catBits[RECT]); dGeomSetCollideBits (geom[RECT], catBits[ALL] & (~catBits[BODY1]) ); dBodySetMass (body[BODY1], &m); setPositionBodies (tc); if ( fixed ) { // Attache external cylinder to the world dJointID fixed = dJointCreateFixed (world,0); dJointAttach (fixed , NULL, body[BODY2]); dJointSetFixed (fixed ); dWorldSetGravity (world,0,0,-0.8); } else { dWorldSetGravity (world,0,0,0); } // The static is here only to help debugging switch (type) { case dJointTypeSlider : { dSliderJoint *sj = new dSliderJoint (world, 0); sj->attach (body[BODY1], body[BODY2]); sj->setAxis (1, 0, 0); joint = sj; } break; case dJointTypePiston : // fall through default default: { dPistonJoint *pj = new dPistonJoint (world, 0); pj->attach (body[BODY1], body[BODY2]); pj->setAxis (1, 0, 0); dJointSetPistonAnchor(pj->id(), anchor[X], anchor[Y], anchor[Z]); joint = pj; } break; }; // run simulation dsSimulationLoop (argc,argv,400,300,&fn); delete joint; dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_plane2d.cpp0000644000000000000000000002437512635011627015451 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ // Test my Plane2D constraint. // Uses ode-0.35 collision API. # include # include # include # include # include #include "texturepath.h" # define drand48() ((double) (((double) rand()) / ((double) RAND_MAX))) # define N_BODIES 40 # define STAGE_SIZE 8.0 // in m # define TIME_STEP 0.01 # define K_SPRING 10.0 # define K_DAMP 10.0 //using namespace ode; struct GlobalVars { dWorld dyn_world; dBody dyn_bodies[N_BODIES]; dReal bodies_sides[N_BODIES][3]; dSpaceID coll_space_id; dJointID plane2d_joint_ids[N_BODIES]; dJointGroup coll_contacts; }; static GlobalVars *g_globals_ptr = NULL; static void cb_start () /*************************/ { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = { 0.5f*STAGE_SIZE, 0.5f*STAGE_SIZE, 0.65f*STAGE_SIZE}; static float hpr[3] = { 90.0f, -90.0f, 0 }; dsSetViewpoint (xyz, hpr); } static void cb_near_collision (void *, dGeomID o1, dGeomID o2) /********************************************************************/ { dBodyID b1 = dGeomGetBody (o1); dBodyID b2 = dGeomGetBody (o2); dContact contact; // exit without doing anything if the two bodies are static if (b1 == 0 && b2 == 0) return; // exit without doing anything if the two bodies are connected by a joint if (b1 && b2 && dAreConnected (b1, b2)) { /* MTRAP; */ return; } contact.surface.mode = 0; contact.surface.mu = 0; // frictionless if (dCollide (o1, o2, 1, &contact.geom, sizeof (dContactGeom))) { dJointID c = dJointCreateContact (g_globals_ptr->dyn_world.id(), g_globals_ptr->coll_contacts.id (), &contact); dJointAttach (c, b1, b2); } } static void track_to_pos (dBody &body, dJointID joint_id, dReal target_x, dReal target_y) /************************************************************************/ { dReal curr_x = body.getPosition()[0]; dReal curr_y = body.getPosition()[1]; dJointSetPlane2DXParam (joint_id, dParamVel, 1 * (target_x - curr_x)); dJointSetPlane2DYParam (joint_id, dParamVel, 1 * (target_y - curr_y)); } static void cb_sim_step (int pause) /*************************************/ { if (! pause) { static dReal angle = 0; angle += REAL( 0.01 ); track_to_pos (g_globals_ptr->dyn_bodies[0], g_globals_ptr->plane2d_joint_ids[0], dReal( STAGE_SIZE/2 + STAGE_SIZE/2.0 * cos (angle) ), dReal( STAGE_SIZE/2 + STAGE_SIZE/2.0 * sin (angle) )); /* double f0 = 0.001; */ /* for (int b = 0; b < N_BODIES; b ++) */ /* { */ /* double p = 1 + b / (double) N_BODIES; */ /* double q = 2 - b / (double) N_BODIES; */ /* g_globals_ptr->dyn_bodies[b].addForce (f0 * cos (p*angle), f0 * sin (q*angle), 0); */ /* } */ /* g_globals_ptr->dyn_bodies[0].addTorque (0, 0, 0.1); */ const int n = 10; for (int i = 0; i < n; i ++) { dSpaceCollide (g_globals_ptr->coll_space_id, 0, &cb_near_collision); g_globals_ptr->dyn_world.step (dReal(TIME_STEP/n)); g_globals_ptr->coll_contacts.empty (); } } # if 1 /* [ */ { // @@@ hack Plane2D constraint error reduction here: for (int b = 0; b < N_BODIES; b ++) { const dReal *rot = dBodyGetAngularVel (g_globals_ptr->dyn_bodies[b].id()); const dReal *quat_ptr; dReal quat[4], quat_len; quat_ptr = dBodyGetQuaternion (g_globals_ptr->dyn_bodies[b].id()); quat[0] = quat_ptr[0]; quat[1] = 0; quat[2] = 0; quat[3] = quat_ptr[3]; quat_len = sqrt (quat[0] * quat[0] + quat[3] * quat[3]); quat[0] /= quat_len; quat[3] /= quat_len; dBodySetQuaternion (g_globals_ptr->dyn_bodies[b].id(), quat); dBodySetAngularVel (g_globals_ptr->dyn_bodies[b].id(), 0, 0, rot[2]); } } # endif /* ] */ # if 0 /* [ */ { // @@@ friction for (int b = 0; b < N_BODIES; b ++) { const dReal *vel = dBodyGetLinearVel (g_globals_ptr->dyn_bodies[b].id()), *rot = dBodyGetAngularVel (g_globals_ptr->dyn_bodies[b].id()); dReal s = 1.00; dReal t = 0.99; dBodySetLinearVel (g_globals_ptr->dyn_bodies[b].id(), s*vel[0],s*vel[1],s*vel[2]); dBodySetAngularVel (g_globals_ptr->dyn_bodies[b].id(),t*rot[0],t*rot[1],t*rot[2]); } } # endif /* ] */ { // ode drawstuff dsSetTexture (DS_WOOD); for (int b = 0; b < N_BODIES; b ++) { if (b == 0) dsSetColor (1.0, 0.5, 1.0); else dsSetColor (0, 0.5, 1.0); #ifdef dDOUBLE dsDrawBoxD (g_globals_ptr->dyn_bodies[b].getPosition(), g_globals_ptr->dyn_bodies[b].getRotation(), g_globals_ptr->bodies_sides[b]); #else dsDrawBox (g_globals_ptr->dyn_bodies[b].getPosition(), g_globals_ptr->dyn_bodies[b].getRotation(), g_globals_ptr->bodies_sides[b]); #endif } } } extern int main /******************/ ( int argc, char **argv ) { int b; dsFunctions drawstuff_functions; dInitODE2(0); g_globals_ptr = new GlobalVars(); // dynamic world dReal cf_mixing;// = 1 / TIME_STEP * K_SPRING + K_DAMP; dReal err_reduct;// = TIME_STEP * K_SPRING * cf_mixing; err_reduct = REAL( 0.5 ); cf_mixing = REAL( 0.001 ); dWorldSetERP (g_globals_ptr->dyn_world.id (), err_reduct); dWorldSetCFM (g_globals_ptr->dyn_world.id (), cf_mixing); g_globals_ptr->dyn_world.setGravity (0, 0.0, -1.0); g_globals_ptr->coll_space_id = dSimpleSpaceCreate (0); // dynamic bodies for (b = 0; b < N_BODIES; b ++) { int l = (int) (1 + sqrt ((double) N_BODIES)); dReal x = dReal( (0.5 + (b / l)) / l * STAGE_SIZE ); dReal y = dReal( (0.5 + (b % l)) / l * STAGE_SIZE ); dReal z = REAL( 1.0 ) + REAL( 0.1 ) * (dReal)drand48(); g_globals_ptr->bodies_sides[b][0] = dReal( 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES) ); g_globals_ptr->bodies_sides[b][1] = dReal( 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES) ); g_globals_ptr->bodies_sides[b][2] = z; g_globals_ptr->dyn_bodies[b].create (g_globals_ptr->dyn_world); g_globals_ptr->dyn_bodies[b].setPosition (x, y, z/2); g_globals_ptr->dyn_bodies[b].setData ((void*) (size_t)b); dBodySetLinearVel (g_globals_ptr->dyn_bodies[b].id (), dReal( 3 * (drand48 () - 0.5) ), dReal( 3 * (drand48 () - 0.5) ), 0); dMass m; m.setBox (1, g_globals_ptr->bodies_sides[b][0],g_globals_ptr->bodies_sides[b][1],g_globals_ptr->bodies_sides[b][2]); m.adjust (REAL(0.1) * g_globals_ptr->bodies_sides[b][0] * g_globals_ptr->bodies_sides[b][1]); g_globals_ptr->dyn_bodies[b].setMass (&m); g_globals_ptr->plane2d_joint_ids[b] = dJointCreatePlane2D (g_globals_ptr->dyn_world.id (), 0); dJointAttach (g_globals_ptr->plane2d_joint_ids[b], g_globals_ptr->dyn_bodies[b].id (), 0); } dJointSetPlane2DXParam (g_globals_ptr->plane2d_joint_ids[0], dParamFMax, 10); dJointSetPlane2DYParam (g_globals_ptr->plane2d_joint_ids[0], dParamFMax, 10); // collision geoms and joints dCreatePlane (g_globals_ptr->coll_space_id, 1, 0, 0, 0); dCreatePlane (g_globals_ptr->coll_space_id, -1, 0, 0, -STAGE_SIZE); dCreatePlane (g_globals_ptr->coll_space_id, 0, 1, 0, 0); dCreatePlane (g_globals_ptr->coll_space_id, 0, -1, 0, -STAGE_SIZE); for (b = 0; b < N_BODIES; b ++) { dGeomID coll_box_id; coll_box_id = dCreateBox (g_globals_ptr->coll_space_id, g_globals_ptr->bodies_sides[b][0], g_globals_ptr->bodies_sides[b][1], g_globals_ptr->bodies_sides[b][2]); dGeomSetBody (coll_box_id, g_globals_ptr->dyn_bodies[b].id ()); } g_globals_ptr->coll_contacts.create (); { // simulation loop (by drawstuff lib) drawstuff_functions.version = DS_VERSION; drawstuff_functions.start = &cb_start; drawstuff_functions.step = &cb_sim_step; drawstuff_functions.command = 0; drawstuff_functions.stop = 0; drawstuff_functions.path_to_textures = DRAWSTUFF_TEXTURE_PATH; dsSimulationLoop (argc, argv, 352,288,&drawstuff_functions); } delete g_globals_ptr; g_globals_ptr = NULL; dCloseODE(); return 0; } ode-0.14/ode/demo/demo_rfriction.cpp0000644000000000000000000001666112635011627016122 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* Angular friction demo: A bunch of ramps of different pitch. A bunch of spheres with rolling friction. */ #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define GRAVITY 10 // the global gravity to use #define RAMP_COUNT 8 static const dReal rampX = 6.0f; static const dReal rampY = 0.5f; static const dReal rampZ = 0.25f; static const dReal sphereRadius = 0.25f; static const dReal maxRamp = M_PI/4.0f; // Needs to be less than pi/2 static const dReal rampInc = maxRamp/RAMP_COUNT; // dynamics and collision objects static dWorldID world = 0; static dSpaceID space = 0; static dJointGroupID contactgroup = 0; static dGeomID ground; static dReal mu = REAL(0.37); // the global mu to use static dReal rho = REAL(0.1); // the global rho to use static dReal omega = REAL(25.0); static dGeomID rampGeom[RAMP_COUNT]; static dBodyID sphereBody[RAMP_COUNT]; static dGeomID sphereGeom[RAMP_COUNT]; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1==0 && b2==0) return; dContact contact[3]; for (int ii=0; ii<3; ii++) { contact[ii].surface.mode = dContactApprox1 | dContactRolling; contact[ii].surface.mu = mu; contact[ii].surface.rho = rho; } if (int numc = dCollide (o1,o2,3,&contact[0].geom,sizeof(dContact))) { for (i=0; i1) rho=1; break; case 'n': case 'N': mu-=0.02; if (mu<0) mu=0; break; case 'm': case 'M': mu+=0.02; if (mu>1) mu=1; break; case 'r': case 'R': reset(); break; case ']': omega+=1; break; case '[': omega-=1; break; } } // simulation loop static void simLoop (int pause) { if (!pause) { dSpaceCollide (space,0,&nearCallback); dWorldStep (world,0.017); // 60 fps // remove all contact joints dJointGroupEmpty (contactgroup); } // Render ramps and spheres dsSetTexture (DS_WOOD); for (int ii=0;ii #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #endif // some constants #define SIDE (0.5f) // side length of a box #define MASS (1.0) // mass of a box // dynamics and collision objects static dWorldID world; static dBodyID body[2]; static dJointID slider; // state set by keyboard commands static int occasional_error = 0; // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {1.0382f,-1.0811f,1.4700f}; static float hpr[3] = {135.0000f,-19.5000f,0.0000f}; dsSetViewpoint (xyz,hpr); printf ("Press 'e' to start/stop occasional error.\n"); } // called when a key pressed static void command (int cmd) { if (cmd == 'e' || cmd == 'E') { occasional_error ^= 1; } } // simulation loop static void simLoop (int pause) { const dReal kd = -0.3; // angular damping constant const dReal ks = 0.5; // spring constant if (!pause) { // add an oscillating torque to body 0, and also damp its rotational motion static dReal a=0; const dReal *w = dBodyGetAngularVel (body[0]); dBodyAddTorque (body[0],kd*w[0],kd*w[1]+0.1*cos(a),kd*w[2]+0.1*sin(a)); a += 0.01; // add a spring force to keep the bodies together, otherwise they will // fly apart along the slider axis. const dReal *p1 = dBodyGetPosition (body[0]); const dReal *p2 = dBodyGetPosition (body[1]); dBodyAddForce (body[0],ks*(p2[0]-p1[0]),ks*(p2[1]-p1[1]), ks*(p2[2]-p1[2])); dBodyAddForce (body[1],ks*(p1[0]-p2[0]),ks*(p1[1]-p2[1]), ks*(p1[2]-p2[2])); // occasionally re-orient one of the bodies to create a deliberate error. if (occasional_error) { static int count = 0; if ((count % 20)==0) { // randomly adjust orientation of body[0] const dReal *R1; dMatrix3 R2,R3; R1 = dBodyGetRotation (body[0]); dRFromAxisAndAngle (R2,dRandReal()-0.5,dRandReal()-0.5, dRandReal()-0.5,dRandReal()-0.5); dMultiply0 (R3,R1,R2,3,3,3); dBodySetRotation (body[0],R3); // randomly adjust position of body[0] const dReal *pos = dBodyGetPosition (body[0]); dBodySetPosition (body[0], pos[0]+0.2*(dRandReal()-0.5), pos[1]+0.2*(dRandReal()-0.5), pos[2]+0.2*(dRandReal()-0.5)); } count++; } dWorldStep (world,0.05); } dReal sides1[3] = {SIDE,SIDE,SIDE}; dReal sides2[3] = {SIDE*0.8f,SIDE*0.8f,SIDE*2.0f}; dsSetTexture (DS_WOOD); dsSetColor (1,1,0); dsDrawBox (dBodyGetPosition(body[0]),dBodyGetRotation(body[0]),sides1); dsSetColor (0,1,1); dsDrawBox (dBodyGetPosition(body[1]),dBodyGetRotation(body[1]),sides2); } int main (int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE2(0); world = dWorldCreate(); dMass m; dMassSetBox (&m,1,SIDE,SIDE,SIDE); dMassAdjust (&m,MASS); body[0] = dBodyCreate (world); dBodySetMass (body[0],&m); dBodySetPosition (body[0],0,0,1); body[1] = dBodyCreate (world); dBodySetMass (body[1],&m); dQuaternion q; dQFromAxisAndAngle (q,-1,1,0,0.25*M_PI); dBodySetPosition (body[1],0.2,0.2,1.2); dBodySetQuaternion (body[1],q); slider = dJointCreateSlider (world,0); dJointAttach (slider,body[0],body[1]); dJointSetSliderAxis (slider,1,1,1); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dWorldDestroy (world); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_space.cpp0000644000000000000000000001461412635011627015212 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ /* testing procedure: * create a bunch of random boxes * test for intersections directly, put results in n^2 array * get space to report collisions: - all correct collisions reported - no pair reported more than once - no incorrect collisions reported */ #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define NUM 20 // number of boxes to test // collision objects and globals static dSpaceID space; static dGeomID geom[NUM]; static dReal bounds[NUM][6]; static size_t good_matrix[NUM][NUM]; // correct collision matrix static size_t test_matrix[NUM][NUM]; // testing collision matrix static size_t hits[NUM]; // number of collisions a box has static unsigned long seed=37; static void init_test() { int i,j; const dReal scale = 0.5; // set random boxes dRandSetSeed (seed); for (i=0; i < NUM; i++) { bounds[i][0] = dRandReal()*2-1; bounds[i][1] = bounds[i][0] + dRandReal()*scale; bounds[i][2] = dRandReal()*2-1; bounds[i][3] = bounds[i][2] + dRandReal()*scale; bounds[i][4] = dRandReal()*2; bounds[i][5] = bounds[i][4] + dRandReal()*scale; if (geom[i]) dGeomDestroy (geom[i]); geom[i] = dCreateBox (space, bounds[i][1] - bounds[i][0], bounds[i][3] - bounds[i][2], bounds[i][5] - bounds[i][4]); dGeomSetPosition (geom[i], (bounds[i][0] + bounds[i][1])*0.5, (bounds[i][2] + bounds[i][3])*0.5, (bounds[i][4] + bounds[i][5])*0.5); dGeomSetData (geom[i],(void*)(size_t)(i)); } // compute all intersections and put the results in "good_matrix" for (i=0; i < NUM; i++) { for (j=0; j < NUM; j++) good_matrix[i][j] = 0; } for (i=0; i < NUM; i++) hits[i] = 0; for (i=0; i < NUM; i++) { for (j=i+1; j < NUM; j++) { dReal *bounds1 = &bounds[i][0]; dReal *bounds2 = &bounds[j][0]; if (bounds1[0] > bounds2[1] || bounds1[1] < bounds2[0] || bounds1[2] > bounds2[3] || bounds1[3] < bounds2[2] || bounds1[4] > bounds2[5] || bounds1[5] < bounds2[4]) continue; good_matrix[i][j] = 1; good_matrix[j][i] = 1; hits[i]++; hits[j]++; } } } // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { size_t i,j; i = (size_t) dGeomGetData (o1); j = (size_t) dGeomGetData (o2); if (i==j) printf ("collision (%d,%d) is between the same object\n",(int)i,(int)j); if (!good_matrix[i][j] || !good_matrix[j][i]) printf ("collision (%d,%d) is incorrect\n",(int)i,(int)j); if (test_matrix[i][j] || test_matrix[j][i]) printf ("collision (%d,%d) reported more than once\n",(int)i,(int)j); test_matrix[i][j] = 1; test_matrix[j][i] = 1; } // start simulation - set viewpoint static void start() { dAllocateODEDataForThread(dAllocateMaskAll); static float xyz[3] = {2.1640f,-1.3079f,1.7600f}; static float hpr[3] = {125.5000f,-17.0000f,0.0000f}; dsSetViewpoint (xyz,hpr); } static void command (int cmd) { if (cmd == ' ') { seed++; init_test(); } } // simulation loop static void simLoop (int) { int i,j; for (i=0; i < NUM; i++) { for (j=0; j < NUM; j++) test_matrix[i][j] = 0; } dSpaceCollide (space,0,&nearCallback); for (i=0; i < NUM; i++) { for (j=i+1; j < NUM; j++) { if (good_matrix[i][j] && !test_matrix[i][j]) { printf ("failed to report collision (%d,%d) (seed=%ld)\n",i,j,seed); } } } seed++; init_test(); for (i=0; i 0) dsSetColor (1,0,0); else dsSetColor (1,1,0); dsDrawBox (pos,R,side); } } int main (int argc, char **argv) { int i; // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; dInitODE2(0); // test the simple space: // space = dSimpleSpaceCreate(); // test the hash space: // space = dHashSpaceCreate (0); // dHashSpaceSetLevels (space,-10,10); // test the quadtree space dVector3 Center = {0, 0, 0, 0}; dVector3 Extents = {10, 0, 10, 0}; space = dQuadTreeSpaceCreate(0, Center, Extents, 7); for (i=0; i < NUM; i++) geom[i] = 0; init_test(); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dSpaceDestroy (space); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_space_stress.cpp0000644000000000000000000003341412635011627016614 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #include #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define NUM 10000 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 4 // maximum number of contact points per body #define WORLD_SIZE 20 #define WORLD_HEIGHT 20 // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space = NULL; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? static int draw_geom = 1; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command (int cmd) { int i,j,k; dReal sides[3]; dMass m; bool setBody = false; cmd = locase(cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'y') { if (num < NUM) { // new object to be created i = num; num++; } else { // recycle existing object i = nextobj++; nextobj %= num; // wrap-around if needed // destroy the body and geoms for slot i dBodyDestroy (obj[i].body); obj[i].body = 0; for (k=0; k < GPB; k++) if (obj[i].geom[k]) { dGeomDestroy(obj[i].geom[k]); obj[i].geom[k] = 0; } } obj[i].body = dBodyCreate(world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition(obj[i].body, dRandReal()*2-1,dRandReal()*2-1,dRandReal()+2); dRFromAxisAndAngle(R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { // higher than highest body position dReal maxheight = 0; for (k=0; k maxheight) maxheight = pos[2]; } dBodySetPosition(obj[i].body, 0,0,maxheight+1); dRSetIdentity(R); //dRFromAxisAndAngle (R,0,0,1,/*dRandReal()*10.0-5.0*/0); } dBodySetRotation(obj[i].body,R); if (cmd == 'b') { dMassSetBox(&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox(space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCapsule(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]); } else if (cmd == 'y') { dMassSetCylinder(&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder(space,sides[0],sides[1]); } else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere (space,sides[0]); } else if (cmd == 'x') { setBody = true; // start accumulating masses for the composite geometries dMass m2; dMassSetZero (&m); dReal dpos[GPB][3]; // delta-positions for composite geometries dMatrix3 drot[GPB]; // set random delta positions for (j=0; j= num) selected = 0; if (selected < 0) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable (obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable (obj[selected].body); } else if (cmd == 'a') { show_aabb ^= 1; } else if (cmd == 't') { show_contacts ^= 1; } else if (cmd == 'r') { random_pos ^= 1; } else if (cmd == 'o') { draw_geom ^= 1; } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { if (!draw_geom){ return; } if (!g) return; if (!pos) pos = dGeomGetPosition(g); if (!R) R = dGeomGetRotation(g); int type = dGeomGetClass (g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths(g,sides); dsDrawBox(pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere(pos,R,dGeomSphereGetRadius (g)); } else if (type == dCapsuleClass) { dReal radius,length; dGeomCapsuleGetParams(g,&radius,&length); dsDrawCapsule (pos,R,length,radius); } else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams(g,&radius,&length); dsDrawCylinder(pos,R,length,radius); } if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB(g,aabb); dVector3 bbpos; for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (int j=0; j<3; j++) bbsides[j] = aabb[j*2+1] - aabb[j*2]; dMatrix3 RI; dRSetIdentity(RI); dsSetColorAlpha(1,0,0,0.5); dsDrawBox(bbpos,RI,bbsides); } } // simulation loop static void simLoop (int pause) { dsSetColor (0,0,2); dSpaceCollide (space,0,&nearCallback); //if (!pause) dWorldStep (world,0.05); if (!pause) dWorldQuickStep (world,0.05); //if (!pause) dWorldStepFast (world,0.05, 1); // remove all contact joints dJointGroupEmpty (contactgroup); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (int i=0; i #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #endif // some constants #define NUM 10 // number of bodies #define NUMJ 9 // number of joints #define SIDE (0.2) // side length of a box #define MASS (1.0) // mass of a box #define RADIUS (0.1732f) // sphere radius // dynamics and collision objects static dWorldID world=0; static dBodyID body[NUM]; static dJointID joint[NUMJ]; // create the test system void createTest() { int i,j; if (world) dWorldDestroy (world); world = dWorldCreate(); // create random bodies for (i=0; i #include #include #include "texturepath.h" #ifdef dDOUBLE #define dsDrawSphere dsDrawSphereD #define dsDrawBox dsDrawBoxD #define dsDrawTriangle dsDrawTriangleD #define dsDrawLine dsDrawLineD #endif const dReal ball_radius = 0.4; const dReal balls_sep = 2; // separation between the balls /* Choose one test case */ #define TEST_CASE 0 #if TEST_CASE == 0 const dReal track_len = 10; const dReal track_height = 1; const dReal track_width = 0.1; const dReal track_gauge = 1; const dReal track_elevation = 2; const dReal track_angle = 80 * M_PI/180.; const dReal track_incl = 10 * M_PI/180.; #elif TEST_CASE == 1 const dReal track_len = 10; const dReal track_height = 1; const dReal track_width = 0.1; const dReal track_gauge = 1.9*ball_radius; const dReal track_elevation = 2; const dReal track_angle = 0 * M_PI/180.; const dReal track_incl = 10 * M_PI/180.; #elif TEST_CASE == 2 const dReal track_len = 10; const dReal track_height = 1; const dReal track_width = 0.1; const dReal track_gauge = 1.9*ball_radius; const dReal track_elevation = 2; const dReal track_angle = 15 * M_PI/180.; const dReal track_incl = 10 * M_PI/180.; #elif TEST_CASE == 3 const dReal track_len = 10; const dReal track_height = .7; const dReal track_width = 0.1; const dReal track_gauge = track_height*1.1; const dReal track_elevation = 2; const dReal track_angle = 90 * M_PI/180.; const dReal track_incl = 10 * M_PI/180.; #else #error "TEST_CAST to a valid value!" #endif dWorldID world; dSpaceID space; dJointGroupID contact_group; dGeomID ground; dGeomID ball1_geom, ball2_geom; dTriMeshDataID mesh_data; dGeomID mesh_geom; dBodyID ball1_body, ball2_body; const unsigned n_box_verts = 8; dVector3 box_verts[n_box_verts] = { {-track_len/2, -track_width/2, track_height/2}, // 0 { track_len/2, -track_width/2, track_height/2}, // 1 { track_len/2, track_width/2, track_height/2}, // 2 {-track_len/2, track_width/2, track_height/2}, // 3 { track_len/2, -track_width/2, -track_height/2}, // 4 {-track_len/2, -track_width/2, -track_height/2}, // 5 {-track_len/2, track_width/2, -track_height/2}, // 6 { track_len/2, track_width/2, -track_height/2} // 7 }; const unsigned n_box_faces = 12; dTriIndex box_faces[n_box_faces * 3] = { 0, 1, 2, 0, 2, 3, 1, 4, 7, 1, 7, 2, 4, 5, 6, 4, 6, 7, 5, 0, 3, 5, 3, 6, 3, 2, 7, 3, 7, 6, 0, 5, 4, 0, 4, 1 }; const unsigned n_track_verts = n_box_verts * 2; const unsigned n_track_faces = n_box_faces * 2; dVector3 track_verts[n_track_verts]; dTriIndex track_faces[n_track_faces * 3]; void resetBall(dBodyID b, unsigned idx) { dBodySetPosition(b, 0.5*track_len*cos(track_incl) // Z - 0.5*track_height*sin(track_incl) - ball_radius, // X balls_sep*idx, // Y track_elevation + ball_radius// Z + 0.5*track_len*sin(track_incl) + 0.5*track_height*cos(track_incl)); dMatrix3 r = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0}; dBodySetRotation(b, r); dBodySetLinearVel(b, 0, 0, 0); dBodySetAngularVel(b, 0, 0, 0); } void resetSim() { resetBall(ball1_body, 0); resetBall(ball2_body, 1); } void start() { dAllocateODEDataForThread(dAllocateMaskAll); world = dWorldCreate(); dWorldSetGravity (world,0,0,-9.8); contact_group = dJointGroupCreate(0); space = dSimpleSpaceCreate (0); // first, the ground plane // it has to coincide with the plane we have in drawstuff ground = dCreatePlane(space, 0, 0, 1, 0); // now a ball dMass m; dMassSetSphere(&m, 0.1, ball_radius); ball1_geom = dCreateSphere(space, ball_radius); ball1_body = dBodyCreate(world); dGeomSetBody(ball1_geom, ball1_body); dBodySetMass(ball1_body, &m); ball2_geom = dCreateSphere(space, ball_radius); ball2_body = dBodyCreate(world); dGeomSetBody(ball2_geom, ball2_body); dBodySetMass(ball2_body, &m); // tracks made out of boxes dGeomID trk; dMatrix3 r1, r2, r3; dVector3 ro = {0, -(0.5*track_gauge + 0.5*track_width), track_elevation}; dMatrix3 s1, s2, s3; dVector3 so = {0, 0.5*track_gauge + 0.5*track_width, track_elevation}; dRFromAxisAndAngle(r1, 1, 0, 0, track_angle); dRFromAxisAndAngle(r2, 0, 1, 0, -track_incl); dMultiply0_333(r3, r2, r1); dRFromAxisAndAngle(s1, 1, 0, 0, -track_angle); dRFromAxisAndAngle(s2, 0, 1, 0, -track_incl); dMultiply0_333(s3, s2, s1); trk = dCreateBox(space, track_len, track_width, track_height); dGeomSetPosition(trk, ro[0], ro[1] + balls_sep, ro[2]); dGeomSetRotation(trk, r3); trk = dCreateBox(space, track_len, track_width, track_height); dGeomSetPosition(trk, so[0], so[1] + balls_sep, so[2]); dGeomSetRotation(trk, s3); // tracks made out of trimesh for (unsigned i=0; i 0.99 // about 8 degrees of difference && dCalcPointsDistance3(contacts[i].geom.pos, contacts[j].geom.pos) < epsilon) { // they are too close closest_point = j; //clog << "found close points: " << j << " and " << i << endl; break; } } if (closest_point != i) { // we discard one of the points if (contacts[i].geom.depth > contacts[closest_point].geom.depth) // the new point is deeper, copy it over closest_point contacts[closest_point] = contacts[i]; } else contacts[new_n++] = contacts[i]; // the point is preserved } //clog << "reduced from " << n << " to " << new_n << endl; n = new_n; for (int i=0; i #include #include "texturepath.h" #ifdef dDOUBLE #define dsDrawCylinder dsDrawCylinderD #define dsDrawLine dsDrawLineD #define dsDrawSphere dsDrawSphereD #endif dReal theta = M_PI / 4; dReal ratio = 1, speed = 5, rho_1 = 1, rho_2 = 1, backlash = 0.1; int mode = 0; dWorldID world; dSpaceID space; dBodyID body1, body2; dGeomID geom1, geom2; dJointID hinge1, hinge2, transmission; dJointFeedback feedback; void setup() { dMatrix3 R; switch (mode) { case 0: // Parallel axes. dBodySetPosition(body1, 1, 0, 1); dBodySetPosition(body2, -1, 0, 1); dRSetIdentity (R); dBodySetRotation (body1, R); dBodySetRotation (body2, R); dJointSetHingeAnchor(hinge2, -1, 0, 1); dJointSetHingeAxis(hinge2, 0, 0, 1); dJointSetHingeAnchor(hinge1, 1, 0, 1); dJointSetHingeAxis(hinge1, 0, 0, 1); dJointSetTransmissionMode(transmission, dTransmissionParallelAxes); dJointSetTransmissionRatio(transmission, ratio); dJointSetTransmissionAnchor1(transmission, 1, 0, 1); dJointSetTransmissionAnchor2(transmission, -1, 0, 1); dJointSetTransmissionAxis(transmission, 0, 0, 1); break; case 1: // Intersecting axes. dBodySetPosition(body1, 1, 0, 1); dBodySetPosition(body2, -1, 0, 2); dRSetIdentity (R); dBodySetRotation (body1, R); dRFromZAxis (R, cos(theta), 0, sin(theta)); dBodySetRotation (body2, R); dJointSetHingeAnchor(hinge2, -1, 0, 2); dJointSetHingeAxis(hinge2, cos(theta), 0, sin(theta)); dJointSetHingeAnchor(hinge1, 1, 0, 1); dJointSetHingeAxis(hinge1, 0, 0, 1); dJointSetTransmissionMode(transmission, dTransmissionIntersectingAxes); dJointSetTransmissionAnchor1(transmission, 1, 0, 1); dJointSetTransmissionAnchor2(transmission, -1, 0, 2); dJointSetTransmissionAxis1(transmission, 0, 0, -1); dJointSetTransmissionAxis2(transmission, cos(theta), 0, sin(theta)); break; case 2: // Chain. dBodySetPosition(body1, 2, 0, 1); dBodySetPosition(body2, -2, 0, 1); dRSetIdentity (R); dBodySetRotation (body1, R); dBodySetRotation (body2, R); dJointSetHingeAnchor(hinge2, -2, 0, 1); dJointSetHingeAxis(hinge2, 0, 0, 1); dJointSetHingeAnchor(hinge1, 2, 0, 1); dJointSetHingeAxis(hinge1, 0, 0, 1); dJointSetTransmissionMode(transmission, dTransmissionChainDrive); dJointSetTransmissionAnchor1(transmission, 2, 0, 1); dJointSetTransmissionAnchor2(transmission, -2, 0, 1); dJointSetTransmissionRadius1(transmission, rho_1); dJointSetTransmissionRadius2(transmission, rho_2); dJointSetTransmissionAxis(transmission, 0, 0, 1); break; } dJointSetTransmissionBacklash(transmission, backlash); dJointSetHingeParam(hinge2, dParamVel, speed); dJointSetHingeParam(hinge2, dParamFMax, 50); dJointSetHingeParam(hinge1, dParamVel, 0); dJointSetHingeParam(hinge1, dParamFMax, 2); dBodySetLinearVel(body1, 0, 0, 0); dBodySetLinearVel(body2, 0, 0, 0); dBodySetAngularVel(body1, 0, 0, 0); dBodySetAngularVel(body2, 0, 0, 0); } void start() { dMass mass; world = dWorldCreate(); dWorldSetGravity (world,0,0,-9.8); dWorldSetERP(world, 0.2); space = dSimpleSpaceCreate (0); body1 = dBodyCreate(world); body2 = dBodyCreate(world); dBodySetFiniteRotationMode(body1, 1); dBodySetFiniteRotationMode(body2, 1); geom1 = dCreateCylinder(space, 0.2, 0.5); dGeomSetBody(geom1, body1); dMassSetCylinder(&mass, 100, 3, 0.2, 0.5); dBodySetMass(body1, &mass); geom2 = dCreateCylinder(space, 0.2, 0.5); dGeomSetBody(geom2, body2); dMassSetCylinder(&mass, 100, 3, 0.2, 0.5); dBodySetMass(body2, &mass); hinge1 = dJointCreateHinge(world, 0); dJointAttach(hinge1, body1, 0); hinge2 = dJointCreateHinge(world, 0); dJointAttach(hinge2, body2, 0); transmission = dJointCreateTransmission(world, 0); dJointAttach(transmission, body1, body2); dJointSetFeedback(transmission, &feedback); setup(); // initial camera position static float xyz[3] = {1.15,-2.78,4.1}; static float hpr[3] = {105,-45.5,0}; dsSetViewpoint (xyz,hpr); fprintf (stderr, "The green wheel is driving the red one. To control it use the following:\n" " '[' : decrease wheel ratio\n" " ']' : increase wheel ratio\n" " ',' : decrease driving wheel speed\n" " '.' : increase driving wheel speed\n" " '-' : decrease backlash\n" " '=' : increase backlash\n" " '1' : switch to parallel axes gears mode\n" " '2' : switch to intersecting axes gears mode\n" " '3' : switch to chain (or belt) mode\n" ); } void stop() { dSpaceDestroy(space); dWorldDestroy(world); } void drawGeom(dGeomID g) { int gclass = dGeomGetClass(g); const dReal *pos = dGeomGetPosition(g); const dReal *rot = dGeomGetRotation(g); switch (gclass) { case dCylinderClass: { dReal length, radius; if (g == geom1) { dsSetColorAlpha(1, 0, 0, 1); } else { dsSetColorAlpha(0, 1, 0, 1); } dsSetTexture (DS_WOOD); dGeomCylinderGetParams(g, &radius, &length); dsDrawCylinder(pos, rot, length, radius); break; } default: { abort(); } } } void simLoop(int pause) { if (!pause) { const dReal step = 0.003; const unsigned nsteps = 4; for (unsigned i=0; i 0.125) { ratio *= 0.5; fprintf (stderr, "Gear ratio set to %.3f.\n", ratio); } break; case dTransmissionIntersectingAxes: if (theta > 0.1) { theta -= 0.1; fprintf (stderr, "Gear angle set to %.3f deg.\n", theta / M_PI * 180); } break; case dTransmissionChainDrive: if (rho_2 > 0.125) { rho_2 /= 2; fprintf (stderr, "Sprocket ratio set to %.3f.\n", rho_2 / rho_1); } break; } setup(); } else if (cmd == ']') { switch(mode) { case dTransmissionParallelAxes: if (ratio < 8) { ratio *= 2; fprintf (stderr, "Gear ratio set to %.3f.\n", ratio); } break; case dTransmissionIntersectingAxes: if (theta < 0.9) { theta += 0.1; fprintf (stderr, "Gear angle set to %.3f deg.\n", theta / M_PI * 180); } break; case dTransmissionChainDrive: if (rho_2 < 2) { rho_2 *= 2; fprintf (stderr, "Sprocket ratio set to %.3f.\n", rho_2 / rho_1); } break; } setup(); } else if (cmd == '.') { speed += 5; fprintf (stderr, "Driving wheel speed set to %g rad/s.\n", speed); dJointSetHingeParam(hinge2, dParamVel, speed); } else if (cmd == ',') { speed -= 5; fprintf (stderr, "Driving wheel speed set to %g rad/s.\n", speed); dJointSetHingeParam(hinge2, dParamVel, speed); } else if (cmd == '/') { if (dJointGetHingeParam(hinge2, dParamFMax) > 0) { dJointSetHingeParam(hinge2, dParamFMax, 0); } else { dJointSetHingeParam(hinge2, dParamFMax, 50); } } else if (cmd == '-') { backlash -= 0.1; fprintf (stderr, "Backlash set to %g m.\n", backlash); dJointSetTransmissionBacklash(transmission, backlash); } else if (cmd == '=') { backlash += 0.1; fprintf (stderr, "Backlash set to %g m.\n", backlash); dJointSetTransmissionBacklash(transmission, backlash); } else if (cmd == '1') { mode = dTransmissionParallelAxes; setup(); } else if (cmd == '2') { mode = dTransmissionIntersectingAxes; setup(); } else if (cmd == '3') { mode = dTransmissionChainDrive; setup(); } } int main(int argc, char **argv) { // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = stop; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE(); // run demo dsSimulationLoop (argc, argv, 800, 600, &fn); dCloseODE(); return 0; } ode-0.14/ode/demo/demo_trimesh.cpp0000644000000000000000000004304312635011627015570 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ // TriMesh test by Erwin de Vries #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif //<---- Convex Object static const dReal planes[] = // planes for a cube { 1.0f ,0.0f ,0.0f ,0.25f, 0.0f ,1.0f ,0.0f ,0.25f, 0.0f ,0.0f ,1.0f ,0.25f, 0.0f ,0.0f ,-1.0f,0.25f, 0.0f ,-1.0f,0.0f ,0.25f, -1.0f,0.0f ,0.0f ,0.25f /* 1.0f ,0.0f ,0.0f ,2.0f, 0.0f ,1.0f ,0.0f ,1.0f, 0.0f ,0.0f ,1.0f ,1.0f, 0.0f ,0.0f ,-1.0f,1.0f, 0.0f ,-1.0f,0.0f ,1.0f, -1.0f,0.0f ,0.0f ,0.0f */ }; static const unsigned int planecount=6; static const dReal points[] = // points for a cube { 0.25f,0.25f,0.25f, -0.25f,0.25f,0.25f, 0.25f,-0.25f,0.25f, -0.25f,-0.25f,0.25f, 0.25f,0.25f,-0.25f, -0.25f,0.25f,-0.25f, 0.25f,-0.25f,-0.25f, -0.25f,-0.25f,-0.25f, }; static const unsigned int pointcount=8; static const unsigned int polygons[] = //Polygons for a cube (6 squares) { 4,0,2,6,4, // positive X 4,1,0,4,5, // positive Y 4,0,1,3,2, // positive Z 4,3,1,5,7, // negative X 4,2,3,7,6, // negative Y 4,5,4,6,7, // negative Z }; //----> Convex Object // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawSphere dsDrawSphereD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawLine dsDrawLineD #define dsDrawTriangle dsDrawTriangleD #define dsDrawConvex dsDrawConvexD #endif // some constants #define NUM 200 // max number of objects #define DENSITY (5.0) // density of all objects #define GPB 3 // maximum number of geometries per body #define MAX_CONTACTS 40 // maximum number of contact points per body // dynamics and collision objects struct MyObject { dBodyID body; // the body dGeomID geom[GPB]; // geometries representing this body }; static int num=0; // number of objects in simulation static int nextobj=0; // next object to recycle if num==NUM static dWorldID world; static dSpaceID space; static MyObject obj[NUM]; static dJointGroupID contactgroup; static int selected = -1; // selected object static int show_aabb = 0; // show geom AABBs? static int show_contacts = 0; // show contact points? static int random_pos = 1; // drop objects from random position? #define VertexCount 5 #define IndexCount 12 static dVector3 Size; static float Vertices[VertexCount][3]; static dTriIndex Indices[IndexCount]; static dGeomID TriMesh; static dGeomID Ray; // this is called by dSpaceCollide when two objects in space are // potentially colliding. static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i; // if (o1->body && o2->body) return; // exit without doing anything if the two bodies are connected by a joint dBodyID b1 = dGeomGetBody(o1); dBodyID b2 = dGeomGetBody(o2); if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact)) return; dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per box-box for (i=0; i= 'A' && c <= 'Z') return c - ('a'-'A'); else return c; } // called when a key pressed static void command (int cmd) { int i,j,k; dReal sides[3]; dMass m; bool setBody = false; cmd = locase (cmd); if (cmd == 'b' || cmd == 's' || cmd == 'c' || cmd == 'x' || cmd == 'v' /* || cmd == 'l' */) { if (num < NUM) { i = num; num++; } else { i = nextobj; nextobj++; if (nextobj >= num) nextobj = 0; // destroy the body and geoms for slot i dBodyDestroy (obj[i].body); for (k=0; k < GPB; k++) { if (obj[i].geom[k]) dGeomDestroy (obj[i].geom[k]); } memset (&obj[i],0,sizeof(obj[i])); } obj[i].body = dBodyCreate (world); for (k=0; k<3; k++) sides[k] = dRandReal()*0.5+0.1; dMatrix3 R; if (random_pos) { dBodySetPosition (obj[i].body, dRandReal()*2-1,dRandReal()*2-1,dRandReal()+1); dRFromAxisAndAngle (R,dRandReal()*2.0-1.0,dRandReal()*2.0-1.0, dRandReal()*2.0-1.0,dRandReal()*10.0-5.0); } else { dReal maxheight = 0; for (k=0; k maxheight) maxheight = pos[2]; } dBodySetPosition (obj[i].body, 0,0,maxheight+1); dRFromAxisAndAngle (R,0,0,1,dRandReal()*10.0-5.0); } dBodySetRotation (obj[i].body,R); dBodySetData (obj[i].body,(void*)(size_t)i); if (cmd == 'b') { dMassSetBox (&m,DENSITY,sides[0],sides[1],sides[2]); obj[i].geom[0] = dCreateBox (space,sides[0],sides[1],sides[2]); } else if (cmd == 'c') { sides[0] *= 0.5; dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCapsule (space,sides[0],sides[1]); } /* // cylinder option not yet implemented else if (cmd == 'l') { sides[1] *= 0.5; dMassSetCapsule (&m,DENSITY,3,sides[0],sides[1]); obj[i].geom[0] = dCreateCylinder (space,sides[0],sides[1]); } */ else if (cmd == 's') { sides[0] *= 0.5; dMassSetSphere (&m,DENSITY,sides[0]); obj[i].geom[0] = dCreateSphere (space,sides[0]); } else if (cmd == 'x') { setBody = true; // start accumulating masses for the composite geometries dMass m2; dMassSetZero (&m); dReal dpos[GPB][3]; // delta-positions for composite geometries dMatrix3 drot[GPB]; // set random delta positions for (j=0; j= num) selected = 0; if (selected < 0) selected = 0; } else if (cmd == 'd' && selected >= 0 && selected < num) { dBodyDisable (obj[selected].body); } else if (cmd == 'e' && selected >= 0 && selected < num) { dBodyEnable (obj[selected].body); } else if (cmd == 'a') { show_aabb ^= 1; } else if (cmd == 't') { show_contacts ^= 1; } else if (cmd == 'r') { random_pos ^= 1; } } // draw a geom void drawGeom (dGeomID g, const dReal *pos, const dReal *R, int show_aabb) { if (!g) return; if (!pos) pos = dGeomGetPosition (g); if (!R) R = dGeomGetRotation (g); int type = dGeomGetClass (g); if (type == dBoxClass) { dVector3 sides; dGeomBoxGetLengths (g,sides); dsDrawBox (pos,R,sides); } else if (type == dSphereClass) { dsDrawSphere (pos,R,dGeomSphereGetRadius (g)); } else if (type == dCapsuleClass) { dReal radius,length; dGeomCapsuleGetParams (g,&radius,&length); dsDrawCapsule (pos,R,length,radius); } else if (type == dConvexClass) { //dVector3 sides={0.50,0.50,0.50}; dsDrawConvex(pos,R,planes, planecount, points, pointcount, polygons); } /* // cylinder option not yet implemented else if (type == dCylinderClass) { dReal radius,length; dGeomCylinderGetParams (g,&radius,&length); dsDrawCylinder (pos,R,length,radius); } */ if (show_aabb) { // draw the bounding box for this geom dReal aabb[6]; dGeomGetAABB (g,aabb); dVector3 bbpos; for (int i=0; i<3; i++) bbpos[i] = 0.5*(aabb[i*2] + aabb[i*2+1]); dVector3 bbsides; for (int j=0; j<3; j++) bbsides[j] = aabb[j*2+1] - aabb[j*2]; dMatrix3 RI; dRSetIdentity (RI); dsSetColorAlpha (1,0,0,0.5); dsDrawBox (bbpos,RI,bbsides); } } // simulation loop static void simLoop (int pause) { dsSetColor (0,0,2); dSpaceCollide (space,0,&nearCallback); if (!pause) dWorldStep (world,0.05); //if (!pause) dWorldStepFast (world,0.05, 1); // remove all contact joints dJointGroupEmpty (contactgroup); dsSetColor (1,1,0); dsSetTexture (DS_WOOD); for (int i=0; i /* This is a description of a convex icosahedron, to test the convex collision detection. */ unsigned int Sphere_pointcount = 42; unsigned int Sphere_planecount = 80; dReal Sphere_points[126]={ 0.000000,0.000000,-0.300000, 0.217080,-0.157716,-0.134164, -0.082915,-0.255192,-0.134164, -0.268327,0.000000,-0.134164, -0.082915,0.255192,-0.134164, 0.217080,0.157716,-0.134164, 0.082915,-0.255192,0.134164, -0.217080,-0.157716,0.134164, -0.217080,0.157716,0.134164, 0.082915,0.255192,0.134164, 0.268327,0.000000,0.134164, 0.000000,0.000000,0.300000, 0.127597,-0.092703,-0.255196, -0.048737,-0.149999,-0.255196, 0.078861,-0.242703,-0.157721, 0.127597,0.092703,-0.255196, 0.255194,0.000000,-0.157721, -0.157719,0.000000,-0.255195, -0.206457,-0.149999,-0.157721, -0.048737,0.149999,-0.255196, -0.206457,0.149999,-0.157721, 0.078861,0.242703,-0.157721, 0.285317,0.092704,0.000000, 0.285317,-0.092704,0.000000, 0.176336,-0.242705,0.000000, 0.000000,-0.300000,0.000000, -0.176336,-0.242705,0.000000, -0.285317,-0.092704,0.000000, -0.285317,0.092704,0.000000, -0.176336,0.242705,0.000000, 0.000000,0.300000,0.000000, 0.176336,0.242705,0.000000, 0.206457,-0.149999,0.157721, -0.078861,-0.242703,0.157721, -0.255194,0.000000,0.157721, -0.078861,0.242703,0.157721, 0.206457,0.149999,0.157721, 0.157719,0.000000,0.255195, 0.048737,-0.149999,0.255196, -0.127597,-0.092703,0.255196, -0.127597,0.092703,0.255196, 0.048737,0.149999,0.255196 }; unsigned int Sphere_polygons[]={ 3,14,12,1, 3,12,14,13, 3,2,13,14, 3,13,0,12, 3,16,1,12, 3,12,15,16, 3,5,16,15, 3,12,0,15, 3,18,13,2, 3,13,18,17, 3,3,17,18, 3,17,0,13, 3,20,17,3, 3,17,20,19, 3,4,19,20, 3,19,0,17, 3,21,19,4, 3,19,21,15, 3,5,15,21, 3,15,0,19, 3,23,1,16, 3,16,22,23, 3,10,23,22, 3,22,16,5, 3,25,2,14, 3,14,24,25, 3,6,25,24, 3,24,14,1, 3,27,3,18, 3,18,26,27, 3,7,27,26, 3,26,18,2, 3,29,4,20, 3,20,28,29, 3,8,29,28, 3,28,20,3, 3,31,5,21, 3,21,30,31, 3,9,31,30, 3,30,21,4, 3,32,23,10, 3,23,32,24, 3,6,24,32, 3,24,1,23, 3,33,25,6, 3,25,33,26, 3,7,26,33, 3,26,2,25, 3,34,27,7, 3,27,34,28, 3,8,28,34, 3,28,3,27, 3,35,29,8, 3,29,35,30, 3,9,30,35, 3,30,4,29, 3,36,31,9, 3,31,36,22, 3,10,22,36, 3,22,5,31, 3,38,6,32, 3,32,37,38, 3,11,38,37, 3,37,32,10, 3,39,7,33, 3,33,38,39, 3,11,39,38, 3,38,33,6, 3,40,8,34, 3,34,39,40, 3,11,40,39, 3,39,34,7, 3,41,9,35, 3,35,40,41, 3,11,41,40, 3,40,35,8, 3,37,10,36, 3,36,41,37, 3,11,37,41, 3,41,36,9, }; dReal Sphere_planes[]={ 0.471317,-0.583121,-0.661687,0.283056, 0.187594,-0.577345,-0.794658,0.280252, -0.038547,-0.748789,-0.661687,0.283056, 0.102381,-0.315090,-0.943523,0.283057, 0.700228,-0.268049,-0.661688,0.283056, 0.607060,0.000000,-0.794656,0.280252, 0.700228,0.268049,-0.661688,0.283056, 0.331305,0.000000,-0.943524,0.283057, -0.408939,-0.628443,-0.661686,0.283056, -0.491119,-0.356821,-0.794657,0.280252, -0.724044,-0.194735,-0.661694,0.283057, -0.268034,-0.194737,-0.943523,0.283057, -0.724044,0.194735,-0.661694,0.283057, -0.491119,0.356821,-0.794657,0.280252, -0.408939,0.628443,-0.661686,0.283056, -0.268034,0.194737,-0.943523,0.283057, -0.038547,0.748789,-0.661687,0.283056, 0.187594,0.577345,-0.794658,0.280252, 0.471317,0.583121,-0.661687,0.283056, 0.102381,0.315090,-0.943523,0.283057, 0.904981,-0.268049,-0.330393,0.283056, 0.982246,0.000000,-0.187599,0.280252, 0.992077,0.000000,0.125631,0.283057, 0.904981,0.268049,-0.330393,0.283056, 0.024726,-0.943519,-0.330396,0.283056, 0.303531,-0.934171,-0.187598,0.280251, 0.306568,-0.943519,0.125651,0.283056, 0.534590,-0.777851,-0.330395,0.283056, -0.889698,-0.315092,-0.330386,0.283056, -0.794656,-0.577348,-0.187595,0.280251, -0.802607,-0.583125,0.125648,0.283055, -0.574584,-0.748793,-0.330397,0.283055, -0.574584,0.748793,-0.330397,0.283055, -0.794656,0.577348,-0.187595,0.280251, -0.802607,0.583125,0.125648,0.283055, -0.889698,0.315092,-0.330386,0.283056, 0.534590,0.777851,-0.330395,0.283056, 0.303531,0.934171,-0.187598,0.280251, 0.306568,0.943519,0.125651,0.283056, 0.024726,0.943519,-0.330396,0.283056, 0.889698,-0.315092,0.330386,0.283056, 0.794656,-0.577348,0.187595,0.280251, 0.574584,-0.748793,0.330397,0.283055, 0.802607,-0.583125,-0.125648,0.283055, -0.024726,-0.943519,0.330396,0.283055, -0.303531,-0.934171,0.187598,0.280251, -0.534590,-0.777851,0.330395,0.283056, -0.306568,-0.943519,-0.125651,0.283056, -0.904981,-0.268049,0.330393,0.283056, -0.982246,0.000000,0.187599,0.280252, -0.904981,0.268049,0.330393,0.283056, -0.992077,0.000000,-0.125631,0.283057, -0.534590,0.777851,0.330395,0.283056, -0.303531,0.934171,0.187598,0.280251, -0.024726,0.943519,0.330396,0.283055, -0.306568,0.943519,-0.125651,0.283056, 0.574584,0.748793,0.330397,0.283055, 0.794656,0.577348,0.187595,0.280251, 0.889698,0.315092,0.330386,0.283056, 0.802607,0.583125,-0.125648,0.283055, 0.408939,-0.628443,0.661686,0.283056, 0.491119,-0.356821,0.794657,0.280252, 0.268034,-0.194737,0.943523,0.283057, 0.724044,-0.194735,0.661694,0.283057, -0.471317,-0.583121,0.661687,0.283056, -0.187594,-0.577345,0.794658,0.280252, -0.102381,-0.315090,0.943523,0.283057, 0.038547,-0.748789,0.661687,0.283056, -0.700228,0.268049,0.661688,0.283056, -0.607060,0.000000,0.794656,0.280252, -0.331305,0.000000,0.943524,0.283057, -0.700228,-0.268049,0.661688,0.283056, 0.038547,0.748789,0.661687,0.283056, -0.187594,0.577345,0.794658,0.280252, -0.102381,0.315090,0.943523,0.283057, -0.471317,0.583121,0.661687,0.283056, 0.724044,0.194735,0.661694,0.283057, 0.491119,0.356821,0.794657,0.280252, 0.268034,0.194737,0.943523,0.283057, 0.408939,0.628443,0.661686,0.283056, }; ode-0.14/ode/demo/texturepath.h0000644000000000000000000000321212635011627015125 0ustar rootroot/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * *************************************************************************/ #ifndef DRAWSTUFF_TEXTURE_PATH #define DRAWSTUFF_TEXTURE_PATH "../../drawstuff/textures" #endif ode-0.14/ode/demo/world_geom3.h0000644000000000000000000003555612635011627015011 0ustar rootroot// mesh for a world model, to be used with test_cyl.cpp static float world_vertices[] = {10.000000f,-10.000000f,1.000000f,-10.000000f,-10.000000f,1.000000f,-10.000000f,-10.000000f,-1.000000f,-10.000000f,-10.000000f,-1.000000f,10.000000f,-10.000000f,-1.000000f,10.000000f,-10.000000f,1.000000f,10.000000f,10.000000f,1.000000f,10.000000f,-10.000000f,1.000000f,10.000000f,-10.000000f,-1.000000f,10.000000f,-10.000000f,-1.000000f,10.000000f,10.000000f,-1.000000f,10.000000f,10.000000f,1.000000f,10.000000f,10.000000f,-1.000000f,10.000000f,-10.000000f,-1.000000f,-10.000000f,-10.000000f,-1.000000f,-10.000000f,-10.000000f,-1.000000f,-10.000000f,10.000000f,-1.000000f,10.000000f,10.000000f,-1.000000f,0.000000f,9.000000f,-0.000000f,0.000000f,-9.000000f,0.000000f,9.000000f,-9.000000f,0.000000f,0.000000f,9.000000f,-0.000000f,9.000000f,-9.000000f,0.000000f,9.000000f,9.000000f,-0.000000f,10.000000f,10.000000f,-1.000000f,-10.000000f,10.000000f,-1.000000f,-10.000000f,10.000000f,1.000000f,10.000000f,10.000000f,-1.000000f,-10.000000f,10.000000f,1.000000f,10.000000f,10.000000f,1.000000f,-10.000000f,-10.000000f,-1.000000f,-10.000000f,-10.000000f,1.000000f,-10.000000f,10.000000f,1.000000f,-10.000000f,10.000000f,1.000000f,-10.000000f,10.000000f,-1.000000f,-10.000000f,-10.000000f,-1.000000f,9.000000f,-9.000000f,1.000000f,-9.000000f,-9.000000f,1.000000f,10.000000f,-10.000000f,1.000000f,-9.000000f,-9.000000f,1.000000f,-10.000000f,-10.000000f,1.000000f,10.000000f,-10.000000f,1.000000f,9.000000f,9.000000f,1.000000f,9.000000f,-9.000000f,1.000000f,10.000000f,-10.000000f,1.000000f,10.000000f,-10.000000f,1.000000f,10.000000f,10.000000f,1.000000f,9.000000f,9.000000f,1.000000f,-9.000000f,9.000000f,1.000000f,9.000000f,9.000000f,1.000000f,10.000000f,10.000000f,1.000000f,10.000000f,10.000000f,1.000000f,-10.000000f,10.000000f,1.000000f,-9.000000f,9.000000f,1.000000f,-9.000000f,9.000000f,1.000000f,-10.000000f,10.000000f,1.000000f,-9.000000f,-9.000000f,1.000000f,-10.000000f,10.000000f,1.000000f,-10.000000f,-10.000000f,1.000000f,-9.000000f,-9.000000f,1.000000f,0.000000f,-9.000000f,0.000000f,-9.000000f,-9.000000f,0.000000f,-9.000000f,-9.000000f,1.000000f,0.000000f,-9.000000f,0.000000f,-9.000000f,-9.000000f,1.000000f,9.000000f,-9.000000f,1.000000f,0.000000f,-9.000000f,0.000000f,9.000000f,-9.000000f,1.000000f,9.000000f,-9.000000f,0.000000f,9.000000f,-9.000000f,0.000000f,9.000000f,-9.000000f,1.000000f,9.000000f,9.000000f,1.000000f,9.000000f,9.000000f,1.000000f,9.000000f,9.000000f,-0.000000f,9.000000f,-9.000000f,0.000000f,0.000000f,9.000000f,-0.000000f,9.000000f,9.000000f,-0.000000f,9.000000f,9.000000f,1.000000f,0.000000f,9.000000f,-0.000000f,9.000000f,9.000000f,1.000000f,-9.000000f,9.000000f,1.000000f,0.000000f,9.000000f,-0.000000f,-9.000000f,9.000000f,1.000000f,-9.000000f,9.000000f,-0.000000f,-9.000000f,9.000000f,1.000000f,-9.000000f,-9.000000f,1.000000f,-9.000000f,-9.000000f,0.000000f,-9.000000f,-9.000000f,0.000000f,-9.000000f,9.000000f,-0.000000f,-9.000000f,9.000000f,1.000000f,-2.997000f,-1.748874f,0.000000f,-2.997000f,-2.001000f,0.000000f,0.000000f,-9.000000f,0.000000f,-2.997000f,-1.748874f,0.000000f,0.000000f,-9.000000f,0.000000f,-2.997000f,1.748874f,-0.000000f,-2.997000f,-2.001000f,0.000000f,-2.997000f,-6.003000f,0.002697f,0.000000f,-9.000000f,0.000000f,0.000000f,9.000000f,-0.000000f,-2.997000f,2.001000f,-0.000000f,-2.997000f,1.748874f,-0.000000f,0.000000f,9.000000f,-0.000000f,-2.997000f,1.748874f,-0.000000f,0.000000f,-9.000000f,0.000000f,-2.997000f,2.001000f,-0.000000f,0.000000f,9.000000f,-0.000000f,-2.997000f,6.003000f,0.002697f,-6.003000f,6.003000f,0.002697f,-2.997000f,6.003000f,0.002697f,0.000000f,9.000000f,-0.000000f,0.000000f,9.000000f,-0.000000f,-9.000000f,9.000000f,-0.000000f,-6.003000f,6.003000f,0.002697f,-6.003000f,1.748874f,-0.000000f,-9.000000f,-9.000000f,0.000000f,-6.003000f,-1.748874f,0.000000f,-6.003000f,2.001000f,-0.000000f,-6.003000f,6.003000f,0.002697f,-9.000000f,9.000000f,-0.000000f,-9.000000f,9.000000f,-0.000000f,-6.003000f,1.748874f,-0.000000f,-6.003000f,2.001000f,-0.000000f,-9.000000f,9.000000f,-0.000000f,-9.000000f,-9.000000f,0.000000f,-6.003000f,1.748874f,-0.000000f,-9.000000f,-9.000000f,0.000000f,-6.003000f,-6.003000f,0.002697f,-6.003000f,-2.001000f,0.000000f,-9.000000f,-9.000000f,0.000000f,-6.003000f,-2.001000f,0.000000f,-6.003000f,-1.748874f,0.000000f,-6.003000f,-6.003000f,0.002697f,-9.000000f,-9.000000f,0.000000f,0.000000f,-9.000000f,0.000000f,-6.003000f,-6.003000f,0.002697f,0.000000f,-9.000000f,0.000000f,-2.997000f,-6.003000f,0.002697f,-2.997000f,1.748874f,1.237951f,-2.997000f,1.748874f,-0.000000f,-2.997000f,2.001000f,-0.000000f,-2.997000f,1.748874f,1.237951f,-2.997000f,2.001000f,-0.000000f,-2.997000f,2.001000f,1.515748f,-6.003000f,-2.001000f,1.515748f,-6.003000f,-6.003000f,0.002697f,-2.997000f,-6.003000f,0.002697f,-6.003000f,-2.001000f,1.515748f,-2.997000f,-6.003000f,0.002697f,-2.997000f,-2.001000f,1.515748f,-2.997000f,2.001000f,1.515748f,-2.997000f,6.003000f,0.002697f,-6.003000f,6.003000f,0.002697f,-6.003000f,6.003000f,0.002697f,-6.003000f,2.001000f,1.515748f,-2.997000f,2.001000f,1.515748f,-6.003000f,-2.001000f,0.000000f,-6.003000f,-6.003000f,0.002697f,-6.003000f,-2.001000f,1.515748f,-6.003000f,2.001000f,1.515748f,-6.003000f,6.003000f,0.002697f,-6.003000f,2.001000f,-0.000000f,-2.997000f,-2.001000f,1.515748f,-2.997000f,-6.003000f,0.002697f,-2.997000f,-2.001000f,0.000000f,-2.997000f,2.001000f,-0.000000f,-2.997000f,6.003000f,0.002697f,-2.997000f,2.001000f,1.515748f,-2.997000f,-2.001000f,1.515748f,-2.997000f,2.001000f,1.515748f,-6.003000f,2.001000f,1.515748f,-6.003000f,2.001000f,1.515748f,-6.003000f,-2.001000f,1.515748f,-2.997000f,-2.001000f,1.515748f,-2.997000f,-1.748874f,1.237951f,-2.997000f,1.748874f,1.237951f,-2.997000f,2.001000f,1.515748f,-2.997000f,-1.748874f,1.237951f,-2.997000f,2.001000f,1.515748f,-2.997000f,-2.001000f,1.515748f,-6.003000f,-1.748874f,1.237951f,-6.003000f,-1.748874f,0.000000f,-6.003000f,-2.001000f,0.000000f,-6.003000f,-1.748874f,1.237951f,-6.003000f,-2.001000f,0.000000f,-6.003000f,-2.001000f,1.515748f,-2.997000f,-2.001000f,1.515748f,-2.997000f,-2.001000f,0.000000f,-2.997000f,-1.748874f,1.237951f,-2.997000f,-2.001000f,0.000000f,-2.997000f,-1.748874f,0.000000f,-2.997000f,-1.748874f,1.237951f,-6.003000f,1.748874f,1.237951f,-6.003000f,2.001000f,1.515748f,-6.003000f,2.001000f,-0.000000f,-6.003000f,1.748874f,1.237951f,-6.003000f,2.001000f,-0.000000f,-6.003000f,1.748874f,-0.000000f,-6.003000f,1.748874f,1.237951f,-6.003000f,-1.748874f,1.237951f,-6.003000f,-2.001000f,1.515748f,-6.003000f,1.748874f,1.237951f,-6.003000f,-2.001000f,1.515748f,-6.003000f,2.001000f,1.515748f,-6.003000f,1.748874f,1.237951f,-6.003000f,1.748874f,-0.000000f,-2.997000f,1.748874f,1.237951f,-6.003000f,1.748874f,-0.000000f,-2.997000f,1.748874f,-0.000000f,-2.997000f,1.748874f,1.237951f,-6.003000f,1.748874f,-0.000000f,-6.003000f,-1.748874f,0.000000f,-2.997000f,-1.748874f,0.000000f,-6.003000f,1.748874f,-0.000000f,-2.997000f,-1.748874f,0.000000f,-2.997000f,1.748874f,-0.000000f,-6.003000f,-1.748874f,0.000000f,-6.003000f,-1.748874f,1.237951f,-2.997000f,-1.748874f,1.237951f,-2.997000f,-1.748874f,1.237951f,-2.997000f,-1.748874f,0.000000f,-6.003000f,-1.748874f,0.000000f,-6.003000f,-1.748874f,1.237951f,-6.003000f,1.748874f,1.237951f,-2.997000f,-1.748874f,1.237951f,-6.003000f,1.748874f,1.237951f,-2.997000f,1.748874f,1.237951f,-2.997000f,-1.748874f,1.237951f}; static float world_normals[] = {0.000000f,-1.000000f,0.000000f,-0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,-0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000225f,0.000161f,1.000000f,0.000225f,-0.000161f,1.000000f,0.000000f,0.000000f,1.000000f,0.000225f,0.000161f,1.000000f,0.000000f,0.000000f,1.000000f,-0.000000f,0.000000f,1.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,-0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,-0.000000f,-1.000000f,0.000000f,0.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,-0.000000f,-1.000000f,0.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,-0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,-0.000000f,0.000000f,1.000000f,0.000787f,0.000337f,1.000000f,0.000225f,-0.000161f,1.000000f,-0.000000f,0.000000f,1.000000f,0.000225f,-0.000161f,1.000000f,0.000000f,0.000000f,1.000000f,0.000787f,0.000337f,1.000000f,0.000400f,-0.179805f,0.983702f,0.000225f,-0.000161f,1.000000f,0.000225f,0.000161f,1.000000f,0.000787f,-0.000337f,1.000000f,0.000000f,0.000000f,1.000000f,0.000225f,0.000161f,1.000000f,0.000000f,0.000000f,1.000000f,0.000225f,-0.000161f,1.000000f,0.000787f,-0.000337f,1.000000f,0.000225f,0.000161f,1.000000f,0.000532f,0.119686f,0.992812f,-0.000320f,0.143927f,0.989588f,0.000532f,0.119686f,0.992812f,0.000225f,0.000161f,1.000000f,0.000225f,0.000161f,1.000000f,-0.000393f,0.000056f,1.000000f,-0.000320f,0.143927f,0.989588f,-0.000000f,0.000000f,1.000000f,-0.000315f,-0.000045f,1.000000f,0.000000f,0.000000f,1.000000f,-0.000787f,-0.000337f,1.000000f,-0.000320f,0.143927f,0.989588f,-0.000393f,0.000056f,1.000000f,-0.000393f,0.000056f,1.000000f,-0.000000f,0.000000f,1.000000f,-0.000787f,-0.000337f,1.000000f,-0.000393f,0.000056f,1.000000f,-0.000315f,-0.000045f,1.000000f,-0.000000f,0.000000f,1.000000f,-0.000315f,-0.000045f,1.000000f,-0.000398f,-0.089784f,0.995961f,-0.000787f,0.000337f,1.000000f,-0.000315f,-0.000045f,1.000000f,-0.000787f,0.000337f,1.000000f,0.000000f,0.000000f,1.000000f,-0.000398f,-0.089784f,0.995961f,-0.000315f,-0.000045f,1.000000f,0.000225f,-0.000161f,1.000000f,-0.000398f,-0.089784f,0.995961f,0.000225f,-0.000161f,1.000000f,0.000400f,-0.179805f,0.983702f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,0.000000f,-0.239222f,0.970965f,-0.000398f,-0.089784f,0.995961f,0.000400f,-0.179805f,0.983702f,0.000000f,-0.239222f,0.970965f,0.000400f,-0.179805f,0.983702f,0.000000f,-0.119611f,0.992821f,0.000000f,0.239222f,0.970965f,0.000532f,0.119686f,0.992812f,-0.000320f,0.143927f,0.989588f,-0.000320f,0.143927f,0.989588f,0.000000f,0.119611f,0.992821f,0.000000f,0.239222f,0.970965f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,0.000000f,-0.119611f,0.992821f,0.000000f,0.239222f,0.970965f,0.000000f,0.119611f,0.992821f,0.000000f,0.119611f,0.992821f,0.000000f,-0.239222f,0.970965f,0.000000f,-0.119611f,0.992821f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,-0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,-0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,-0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,-0.000000f,0.000000f,1.000000f,-0.000000f,0.000000f,1.000000f,-0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,1.000000f,0.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f,0.000000f,0.000000f,-1.000000f}; static dTriIndex world_indices[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227}; ode-0.14/ode/doc/0000775000000000000000000000000012635012023012213 5ustar rootrootode-0.14/ode/doc/Doxyfile.in0000644000000000000000000030540012635011627014337 0ustar rootroot# Doxyfile 1.8.5 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = ODE # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @ODE_VERSION@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. PROJECT_LOGO = @top_srcdir@/web/ODElogo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese- # Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi, # Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en, # Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, # Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a # new page for each member. If set to NO, the documentation of a member will be # part of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. # # Note For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined # locally in source files will be included in the documentation. If set to NO # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO these classes will be included in the various overviews. This option has # no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO the members will appear in declaration order. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the # todo list. This list is created by putting \todo commands in the # documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the # test list. This list is created by putting \test commands in the # documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES the list # will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See # also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO doxygen will only warn about wrong or incomplete parameter # documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. # Note: If this tag is empty the current directory is searched. INPUT = @top_srcdir@/include/ode @top_builddir@/include/ode # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank the # following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, # *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, # *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.idl \ *.ddl \ *.odl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.cs \ *.d \ *.php \ *.php4 \ *.php5 \ *.phtml \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.for \ *.tcl \ *.vhd \ *.vhdl \ *.ucf \ *.qsf \ *.as \ *.js # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = ODE_API # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES, then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = d #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefor more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 243 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 187 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 92 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = NativeMML # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /